Merge "Make sure IME state is updated on BubbleExpandedView" into main
diff --git a/.gitignore b/.gitignore
index b093c81..b4af567 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,8 @@
.vscode/
*.code-workspace
.gradle/
+# .classpath and .settings/ are configurations
+# used by the IDE and java development tools
+# to configure filepaths + project settings
+.classpath
+.settings/
diff --git a/apct-tests/perftests/core/src/android/os/TracePerfTest.java b/apct-tests/perftests/core/src/android/os/TracePerfTest.java
index 00e1c1f..3df708d 100644
--- a/apct-tests/perftests/core/src/android/os/TracePerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/TracePerfTest.java
@@ -46,6 +46,7 @@
private static final String FOO = "foo";
private static final Category FOO_CATEGORY = new Category(FOO);
+ private static final Category UNREGISTERED_CATEGORY = new Category("unregistered");
private static PerfettoTrace.Session sPerfettoSession;
@BeforeClass
@@ -163,6 +164,30 @@
}
}
+ @Test
+ public void testInstantPerfettoWithProtoUnregistered() {
+ PerfettoTrace.begin(UNREGISTERED_CATEGORY, "message_queue_receive")
+ .beginProto()
+ .beginNested(2004 /* message_queue */)
+ .addField(1 /* sending_thread_name */, "foo")
+ .endNested()
+ .endProto()
+ .setTerminatingFlow(5)
+ .emit();
+
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ PerfettoTrace.begin(UNREGISTERED_CATEGORY, "message_queue_receive")
+ .beginProto()
+ .beginNested(2004 /* message_queue */)
+ .addField(1 /* sending_thread_name */, "foo")
+ .endNested()
+ .endProto()
+ .setTerminatingFlow(5)
+ .emit();
+ }
+ }
+
private static TraceConfig getTraceConfig(String cat) {
BufferConfig bufferConfig = BufferConfig.newBuilder().setSizeKb(1024).build();
TrackEventConfig trackEventConfig = TrackEventConfig
diff --git a/api/coverage/tools/ExtractFlaggedApis.kt b/api/coverage/tools/ExtractFlaggedApis.kt
index 0a3ae4f..e50f7f8 100644
--- a/api/coverage/tools/ExtractFlaggedApis.kt
+++ b/api/coverage/tools/ExtractFlaggedApis.kt
@@ -88,6 +88,6 @@
return item.modifiers
.findAnnotation("android.annotation.FlaggedApi")
?.findAttribute("value")
- ?.value
+ ?.legacyValue
?.value() as? String
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 95b9b49..42c60b0 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -18628,6 +18628,7 @@
method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionService(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.Set<java.lang.Integer> getAttachRestrictionReasonsForCarrier(int);
method @FlaggedApi("com.android.internal.telephony.flags.satellite_25q4_apis") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.List<java.lang.String> getSatelliteDataOptimizedApps();
+ method @FlaggedApi("com.android.internal.telephony.flags.satellite_25q4_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int getSatelliteDataSupportMode(int);
method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int[] getSatelliteDisallowedReasons();
method @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.List<java.lang.String> getSatellitePlmnsForCarrier(int);
method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void pollPendingDatagrams(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
@@ -18710,6 +18711,10 @@
field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS = 2; // 0x2
field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN = -1; // 0xffffffff
field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT = 8; // 0x8
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_25q4_apis") public static final int SATELLITE_DATA_SUPPORT_CONSTRAINED = 1; // 0x1
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_25q4_apis") public static final int SATELLITE_DATA_SUPPORT_RESTRICTED = 0; // 0x0
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_25q4_apis") public static final int SATELLITE_DATA_SUPPORT_UNCONSTRAINED = 2; // 0x2
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_25q4_apis") public static final int SATELLITE_DATA_SUPPORT_UNKNOWN = -1; // 0xffffffff
field public static final int SATELLITE_MODEM_STATE_CONNECTED = 7; // 0x7
field public static final int SATELLITE_MODEM_STATE_DATAGRAM_RETRYING = 3; // 0x3
field public static final int SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING = 2; // 0x2
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 980d973..7123ee7 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -17,19 +17,19 @@
filegroup {
name: "framework-core-sources",
srcs: [
- "**/*.java",
"**/*.aidl",
- ":systemfeatures-gen-srcs",
+ "**/*.java",
":framework-nfc-non-updatable-sources",
":messagequeue-gen",
":ranging_stack_mock_initializer",
+ ":systemfeatures-gen-srcs",
],
// Exactly one MessageQueue.java will be added to srcs by messagequeue-gen
exclude_srcs: [
+ "**/*_ravenwood.java",
+ ":dynamic_instrumentation_manager_aidl_sources",
"android/os/*MessageQueue/**/*.java",
"android/ranging/**/*.java",
- ":dynamic_instrumentation_manager_aidl_sources",
- "**/*_ravenwood.java",
],
visibility: ["//frameworks/base"],
}
@@ -52,9 +52,9 @@
"release_ranging_stack",
],
properties: [
- "srcs",
"cmd",
"out",
+ "srcs",
],
}
@@ -153,9 +153,9 @@
filegroup {
name: "framework-core-sources-for-test-mock",
srcs: [
+ "android/accounts/AccountManager.java",
"android/accounts/AccountManagerCallback.java",
"android/accounts/AccountManagerFuture.java",
- "android/accounts/AccountManager.java",
"android/accounts/AccountsException.java",
"android/accounts/AuthenticatorException.java",
"android/accounts/OperationCanceledException.java",
@@ -163,8 +163,8 @@
"android/app/IApplicationThread.aidl",
"android/app/IServiceConnection.aidl",
"android/app/PackageDeleteObserver.java",
- "android/content/ComponentCallbacks2.java",
"android/content/ComponentCallbacks.java",
+ "android/content/ComponentCallbacks2.java",
"android/content/ContentInterface.java",
"android/content/ContentProvider.java",
"android/content/ContentProviderNative.java",
@@ -178,8 +178,8 @@
"android/content/OperationApplicationException.java",
"android/content/pm/ActivityInfo.java",
"android/content/pm/ApplicationInfo.java",
- "android/content/pm/InstantAppInfo.java",
"android/content/pm/IPackageDataObserver.aidl",
+ "android/content/pm/InstantAppInfo.java",
"android/content/pm/KeySet.java",
"android/content/pm/PackageManager.java",
"android/content/pm/VerifierDeviceIdentity.java",
@@ -192,8 +192,8 @@
"android/os/Bundle.java",
"android/os/IBinder.java",
"android/os/IInterface.java",
- "android/os/Parcelable.java",
"android/os/ParcelFileDescriptor.java",
+ "android/os/Parcelable.java",
"android/os/RemoteException.java",
"android/os/storage/VolumeInfo.java",
"android/util/AndroidException.java",
@@ -215,24 +215,24 @@
filegroup {
name: "libvibrator_aidl",
srcs: [
+ "android/os/ExternalVibrationScale.aidl",
"android/os/IExternalVibrationController.aidl",
"android/os/IExternalVibratorService.aidl",
- "android/os/ExternalVibrationScale.aidl",
],
}
filegroup {
name: "libpowermanager_aidl",
srcs: [
- "android/os/Temperature.aidl",
"android/os/CoolingDevice.aidl",
+ "android/os/IPowerManager.aidl",
+ "android/os/IScreenTimeoutPolicyListener.aidl",
"android/os/IThermalEventListener.aidl",
"android/os/IThermalHeadroomListener.aidl",
- "android/os/IThermalStatusListener.aidl",
"android/os/IThermalService.aidl",
- "android/os/IPowerManager.aidl",
+ "android/os/IThermalStatusListener.aidl",
"android/os/IWakeLockCallback.aidl",
- "android/os/IScreenTimeoutPolicyListener.aidl",
+ "android/os/Temperature.aidl",
],
}
@@ -282,8 +282,8 @@
java_library {
name: "uieventloggerlib",
srcs: [
- "com/android/internal/logging/UiEventLoggerImpl.java",
":statslog-framework-java-gen",
+ "com/android/internal/logging/UiEventLoggerImpl.java",
],
libs: [
"androidx.annotation_annotation",
@@ -353,11 +353,11 @@
name: "framework-permission-s-shared-srcs",
srcs: [
":modules-utils-preconditions-srcs",
- "com/android/internal/infra/AndroidFuture.java",
- "com/android/internal/infra/ServiceConnector.java",
- "com/android/internal/infra/AndroidFuture.aidl",
- "com/android/internal/infra/IAndroidFuture.aidl",
"android/os/HandlerExecutor.java",
+ "com/android/internal/infra/AndroidFuture.aidl",
+ "com/android/internal/infra/AndroidFuture.java",
+ "com/android/internal/infra/IAndroidFuture.aidl",
+ "com/android/internal/infra/ServiceConnector.java",
],
}
@@ -393,10 +393,10 @@
"android/content/pm/FileSystemControlParcel.aidl",
"android/content/pm/IDataLoader.aidl",
"android/content/pm/IDataLoaderManager.aidl",
- "android/content/pm/InstallationFileParcel.aidl",
- "android/content/pm/InstallationFileLocation.aidl",
"android/content/pm/IDataLoaderStatusListener.aidl",
"android/content/pm/IPackageInstallerSessionFileSystemConnector.aidl",
+ "android/content/pm/InstallationFileLocation.aidl",
+ "android/content/pm/InstallationFileParcel.aidl",
],
}
@@ -404,9 +404,9 @@
name: "incremental_manager_aidl",
srcs: [
"android/os/incremental/IIncrementalService.aidl",
+ "android/os/incremental/IStorageHealthListener.aidl",
"android/os/incremental/IStorageLoadingProgressListener.aidl",
"android/os/incremental/IncrementalNewFileParams.aidl",
- "android/os/incremental/IStorageHealthListener.aidl",
"android/os/incremental/PerUidReadTimeouts.aidl",
"android/os/incremental/StorageHealthCheckParams.aidl",
],
@@ -422,15 +422,15 @@
filegroup {
name: "hwbinder-stubs-srcs",
srcs: [
- "android/os/HidlSupport.java",
+ "android/os/DeadObjectException.java",
+ "android/os/DeadSystemException.java",
"android/os/HidlMemory.java",
+ "android/os/HidlSupport.java",
"android/os/HwBinder.java",
"android/os/HwBlob.java",
"android/os/HwParcel.java",
"android/os/IHwBinder.java",
"android/os/IHwInterface.java",
- "android/os/DeadObjectException.java",
- "android/os/DeadSystemException.java",
"android/os/NativeHandle.java",
"android/os/RemoteException.java",
"android/util/AndroidException.java",
@@ -444,12 +444,12 @@
cc_defaults {
name: "incremental_default",
cflags: [
+ "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
"-Wall",
+ "-Werror",
"-Wextra",
"-Wextra-semi",
- "-Werror",
"-Wzero-as-null-pointer-constant",
- "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
],
shared_libs: [
"libbinder",
@@ -489,8 +489,8 @@
],
defaults: ["incremental_default"],
shared_libs: [
- "libincremental_aidl-cpp",
"libdataloader_aidl-cpp",
+ "libincremental_aidl-cpp",
],
}
@@ -580,8 +580,8 @@
filegroup {
name: "framework-telephony-common-shared-srcs",
srcs: [
- "android/os/RegistrantList.java",
"android/os/Registrant.java",
+ "android/os/RegistrantList.java",
"android/util/IndentingPrintWriter.java",
"android/util/LocalLog.java",
"android/util/TimeUtils.java",
@@ -599,8 +599,8 @@
name: "framework-ims-common-shared-srcs",
srcs: [
":modules-utils-preconditions-srcs",
- "android/os/RegistrantList.java",
"android/os/Registrant.java",
+ "android/os/RegistrantList.java",
"com/android/internal/os/SomeArgs.java",
],
}
@@ -609,9 +609,9 @@
filegroup {
name: "framework-core-sources-for-fuzzers",
srcs: [
- "android/os/IInterface.java",
"android/os/Binder.java",
"android/os/IBinder.java",
+ "android/os/IInterface.java",
"android/os/Parcelable.java",
],
}
@@ -657,6 +657,17 @@
}
java_library {
+ name: "protolog-common-lib",
+ srcs: [
+ ":protolog-common-src",
+ ],
+ host_supported: true,
+ static_libs: [
+ "framework-annotations-lib",
+ ],
+}
+
+java_library {
name: "protolog-group",
srcs: [
"com/android/internal/protolog/common/IProtoLogGroup.java",
@@ -694,7 +705,9 @@
name: "protolog-groups",
srcs: [
"com/android/internal/protolog/WmProtoLogGroups.java",
- ":protolog-common-src",
+ ],
+ static_libs: [
+ "protolog-common-lib",
],
}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 01b2953..6c6709b 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -369,6 +369,11 @@
in RemoteCallback navigationObserver, in BackAnimationAdapter adaptor);
/**
+ * Registers a callback to be invoked when the system server requests a back gesture.
+ */
+ void registerBackGestureDelegate(in RemoteCallback monitor);
+
+ /**
* registers a callback to be invoked when a background activity launch is aborted.
*
* @param observer callback to be registered.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 7c293cb..f5277fd 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1983,7 +1983,7 @@
* treatment.
* @hide
*/
- public static final String EXTRA_IS_MAGIC = "android.extra.IS_MAGIC";
+ public static final String EXTRA_IS_ANIMATED = "android.extra.IS_ANIMATED";
private final Bundle mExtras;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index 6f0eafe..7eda66e 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -287,7 +287,7 @@
name: "notif_entry_creation_time_use_elapsed_realtime"
namespace: "systemui"
description: "makes the notification entry expect its creation time to be elapsedRealtime, not uptimeMillis"
- bug: "343631648"
+ bug: "389606876"
metadata {
purpose: PURPOSE_BUGFIX
}
@@ -385,3 +385,13 @@
description: "Shows summarized notifications in the UI"
bug: "390217880"
}
+
+flag {
+ name: "nm_collapsed_lines"
+ namespace: "systemui"
+ description: "Shows 2 lines for collapsed notifications by default"
+ bug: "390217880"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensor.java b/core/java/android/companion/virtual/sensor/VirtualSensor.java
index 8d4acfc..7f228ab 100644
--- a/core/java/android/companion/virtual/sensor/VirtualSensor.java
+++ b/core/java/android/companion/virtual/sensor/VirtualSensor.java
@@ -174,7 +174,7 @@
@FlaggedApi(Flags.FLAG_VIRTUAL_SENSOR_ADDITIONAL_INFO)
public void sendAdditionalInfo(@NonNull VirtualSensorAdditionalInfo info) {
if (!Flags.virtualSensorAdditionalInfo()) {
- return;
+ throw new UnsupportedOperationException("Sensor additional info not supported.");
}
if ((mFlags & VirtualSensorConfig.ADDITIONAL_INFO_MASK) == 0) {
throw new UnsupportedOperationException("Sensor additional info not supported.");
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensorAdditionalInfo.java b/core/java/android/companion/virtual/sensor/VirtualSensorAdditionalInfo.java
index a4fca50..0f1a298 100644
--- a/core/java/android/companion/virtual/sensor/VirtualSensorAdditionalInfo.java
+++ b/core/java/android/companion/virtual/sensor/VirtualSensorAdditionalInfo.java
@@ -90,6 +90,7 @@
*
* @see SensorAdditionalInfo#type
*/
+ @VirtualSensorAdditionalInfo.Type
public int getType() {
return mType;
}
@@ -114,6 +115,21 @@
@NonNull
private final ArrayList<float[]> mValues = new ArrayList<>();
+ /** Payload size for {@link SensorAdditionalInfo#TYPE_SAMPLING} */
+ private static final int TYPE_SAMPLING_PLAYLOAD_SIZE = 2;
+
+ /** Payload size for {@link SensorAdditionalInfo#TYPE_UNTRACKED_DELAY} */
+ private static final int TYPE_UNTRACKED_DELAY_PAYLOAD_SIZE = 2;
+
+ /** Payload size for {@link SensorAdditionalInfo#TYPE_INTERNAL_TEMPERATURE} */
+ private static final int TYPE_INTERNAL_TEMPERATURE_PLAYLOAD_SIZE = 1;
+
+ /** Payload size for {@link SensorAdditionalInfo#TYPE_VEC3_CALIBRATION} */
+ private static final int TYPE_VEC3_CALIBRATION_PAYLOAD_SIZE = 12;
+
+ /** Payload size for {@link SensorAdditionalInfo#TYPE_SENSOR_PLACEMENT} */
+ private static final int TYPE_SENSOR_PLACEMENT_PAYLOAD_SIZE = 12;
+
/**
* Creates a new builder.
*
@@ -135,28 +151,31 @@
}
/**
- * Additional info payload data represented in float values. Depending on the type of
- * information, this may be null.
+ * Additional info payload data represented in float values.
*
+ * @param values the float values of this additional info frame.
+ * @throws IllegalArgumentException if the payload size doesn't match the expectation
+ * for the given type, as documented in {@link SensorAdditionalInfo}.
* @see SensorAdditionalInfo#floatValues
*/
@NonNull
public Builder addValues(@NonNull float[] values) {
- if (values.length > 14) {
- throw new IllegalArgumentException("Maximum payload value size is 14.");
- }
if (mValues.isEmpty()) {
switch (mType) {
case SensorAdditionalInfo.TYPE_UNTRACKED_DELAY:
+ assertValuesLength(values, TYPE_UNTRACKED_DELAY_PAYLOAD_SIZE);
+ break;
case SensorAdditionalInfo.TYPE_SAMPLING:
- assertValuesLength(values, 2);
+ assertValuesLength(values, TYPE_SAMPLING_PLAYLOAD_SIZE);
break;
case SensorAdditionalInfo.TYPE_INTERNAL_TEMPERATURE:
- assertValuesLength(values, 1);
+ assertValuesLength(values, TYPE_INTERNAL_TEMPERATURE_PLAYLOAD_SIZE);
break;
case SensorAdditionalInfo.TYPE_VEC3_CALIBRATION:
+ assertValuesLength(values, TYPE_VEC3_CALIBRATION_PAYLOAD_SIZE);
+ break;
case SensorAdditionalInfo.TYPE_SENSOR_PLACEMENT:
- assertValuesLength(values, 11);
+ assertValuesLength(values, TYPE_SENSOR_PLACEMENT_PAYLOAD_SIZE);
break;
}
} else if (values.length != mValues.getFirst().length) {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 210653b..63c819eb 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -5198,12 +5198,6 @@
* </tr>
* <tr>
* <td style="text-align: center;">PRIV</td>
- * <td style="text-align: center;">S1080P</td>
- * <td style="text-align: center;">PRIV</td>
- * <td style="text-align: center;">UHD</td>
- * </tr>
- * <tr>
- * <td style="text-align: center;">PRIV</td>
* <td style="text-align: center;">S720P</td>
* <td style="text-align: center;">JPEG/JPEG_R</td>
* <td style="text-align: center;">MAXIMUM_16_9</td>
@@ -5271,28 +5265,36 @@
* </thead>
* <tbody>
* <tr>
- * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PRIV Preview</td>
* <td style="text-align: center;">S1080P</td>
- * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PRIV Video</td>
* <td style="text-align: center;">S1080P</td>
* <td style="text-align: center;"></td>
* <td style="text-align: center;"></td>
* </tr>
* <tr>
- * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PRIV Preview</td>
* <td style="text-align: center;">S1080P</td>
- * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PRIV Video</td>
* <td style="text-align: center;">S1440P</td>
* <td style="text-align: center;"></td>
* <td style="text-align: center;"></td>
* </tr>
* <tr>
- * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PRIV Preview</td>
* <td style="text-align: center;">S1080P</td>
- * <td style="text-align: center;">YUV</td>
+ * <td style="text-align: center;">PRIV Video</td>
+ * <td style="text-align: center;">UHD</td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;"></td>
+ * </tr>
+ * <tr>
+ * <td style="text-align: center;">PRIV Preview</td>
* <td style="text-align: center;">S1080P</td>
+ * <td style="text-align: center;">YUV Analysis</td>
* <td style="text-align: center;">S1080P</td>
- * <td style="text-align: center;">PRIV</td>
+ * <td style="text-align: center;">PRIV Video</td>
+ * <td style="text-align: center;">1080P</td>
* </tr>
* </tbody>
* </table>
diff --git a/core/java/android/hardware/display/DisplayTopology.java b/core/java/android/hardware/display/DisplayTopology.java
index c3c8c3d..aae09e6 100644
--- a/core/java/android/hardware/display/DisplayTopology.java
+++ b/core/java/android/hardware/display/DisplayTopology.java
@@ -169,7 +169,23 @@
* @hide
*/
public void addDisplay(int displayId, float width, float height) {
- addDisplay(displayId, width, height, /* shouldLog= */ true);
+ if (findDisplay(displayId, mRoot) != null) {
+ return;
+ }
+ if (mRoot == null) {
+ mRoot = new TreeNode(displayId, width, height, POSITION_LEFT, /* offset= */ 0);
+ mPrimaryDisplayId = displayId;
+ } else if (mRoot.mChildren.isEmpty()) {
+ // This is the 2nd display. Align the middles of the top and bottom edges.
+ float offset = mRoot.mWidth / 2 - width / 2;
+ TreeNode display = new TreeNode(displayId, width, height, POSITION_TOP, offset);
+ mRoot.mChildren.add(display);
+ } else {
+ TreeNode rightMostDisplay = findRightMostDisplay(mRoot, mRoot.mWidth).first;
+ TreeNode newDisplay = new TreeNode(displayId, width, height, POSITION_RIGHT,
+ /* offset= */ 0);
+ rightMostDisplay.mChildren.add(newDisplay);
+ }
}
/**
@@ -216,7 +232,7 @@
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
if (node.mDisplayId != displayId) {
- addDisplay(node.mDisplayId, node.mWidth, node.mHeight, /* shouldLog= */ false);
+ addDisplay(node.mDisplayId, node.mWidth, node.mHeight);
}
queue.addAll(node.mChildren);
}
@@ -227,10 +243,6 @@
} else {
mPrimaryDisplayId = Display.INVALID_DISPLAY;
}
- Slog.i(TAG, "Primary display with ID " + displayId
- + " removed, new primary display: " + mPrimaryDisplayId);
- } else {
- Slog.i(TAG, "Display with ID " + displayId + " removed");
}
return true;
}
@@ -598,37 +610,6 @@
return out.toString();
}
- private void addDisplay(int displayId, float width, float height, boolean shouldLog) {
- if (findDisplay(displayId, mRoot) != null) {
- return;
- }
- if (mRoot == null) {
- mRoot = new TreeNode(displayId, width, height, POSITION_LEFT, /* offset= */ 0);
- mPrimaryDisplayId = displayId;
- if (shouldLog) {
- Slog.i(TAG, "First display added: " + mRoot);
- }
- } else if (mRoot.mChildren.isEmpty()) {
- // This is the 2nd display. Align the middles of the top and bottom edges.
- float offset = mRoot.mWidth / 2 - width / 2;
- TreeNode display = new TreeNode(displayId, width, height, POSITION_TOP, offset);
- mRoot.mChildren.add(display);
- if (shouldLog) {
- Slog.i(TAG, "Second display added: " + display + ", parent ID: "
- + mRoot.mDisplayId);
- }
- } else {
- TreeNode rightMostDisplay = findRightMostDisplay(mRoot, mRoot.mWidth).first;
- TreeNode newDisplay = new TreeNode(displayId, width, height, POSITION_RIGHT,
- /* offset= */ 0);
- rightMostDisplay.mChildren.add(newDisplay);
- if (shouldLog) {
- Slog.i(TAG, "Display added: " + newDisplay + ", parent ID: "
- + rightMostDisplay.mDisplayId);
- }
- }
- }
-
/**
* @param display The display from which the search should start.
* @param xPos The x position of the right edge of that display.
diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig
index 6c2ce36..3dfad53 100644
--- a/core/java/android/hardware/input/input_framework.aconfig
+++ b/core/java/android/hardware/input/input_framework.aconfig
@@ -213,3 +213,19 @@
is_fixed_read_only: true
}
+flag {
+ name: "request_key_capture_api"
+ namespace: "input"
+ description: "Adds support for key capture APIs"
+ bug: "375435312"
+}
+
+flag {
+ name: "fix_search_modifier_fallbacks"
+ namespace: "input"
+ description: "Fixes a bug in which fallbacks from Search based key combinations were not activating."
+ bug: "384113980"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 71d79bb..cc1dee7 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1780,7 +1780,7 @@
out.writeInt(statIrqTime);
out.writeInt(statSoftIrqTime);
out.writeInt(statIdlTime);
- out.writeString(statSubsystemPowerState);
+ out.writeString8(statSubsystemPowerState);
}
public void readFromParcel(Parcel in) {
@@ -1801,7 +1801,15 @@
statIrqTime = in.readInt();
statSoftIrqTime = in.readInt();
statIdlTime = in.readInt();
- statSubsystemPowerState = in.readString();
+ statSubsystemPowerState = in.readString8();
+ }
+
+
+ public boolean isEmpty() {
+ return userTime == 0 && systemTime == 0 && appCpuUid1 == Process.INVALID_UID
+ && appCpuUid2 == Process.INVALID_UID && appCpuUid3 == Process.INVALID_UID
+ && statSystemTime == 0 && statIOWaitTime == 0 && statIrqTime == 0
+ && statSoftIrqTime == 0 && statIdlTime == 0 && statSubsystemPowerState == null;
}
}
@@ -2238,6 +2246,7 @@
tagsFirstOccurrence = false;
powerStats = null;
processStateChange = null;
+ stepDetails = null;
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@@ -2289,6 +2298,7 @@
currentTime = o.currentTime;
powerStats = o.powerStats;
processStateChange = o.processStateChange;
+ stepDetails = o.stepDetails;
}
public boolean sameNonEvent(HistoryItem o) {
@@ -7318,7 +7328,8 @@
}
item.append(", SubsystemPowerState ");
- item.append(rec.stepDetails.statSubsystemPowerState);
+ item.append(rec.stepDetails.statSubsystemPowerState != null
+ ? rec.stepDetails.statSubsystemPowerState : "Empty");
item.append("\n");
} else {
item.append(BATTERY_STATS_CHECKIN_VERSION); item.append(',');
diff --git a/core/java/android/os/PerfettoTrace.java b/core/java/android/os/PerfettoTrace.java
index 932836f..8b96b89 100644
--- a/core/java/android/os/PerfettoTrace.java
+++ b/core/java/android/os/PerfettoTrace.java
@@ -232,7 +232,8 @@
* @param eventName The event name to appear in the trace.
*/
public static PerfettoTrackEventExtra.Builder instant(Category category, String eventName) {
- return PerfettoTrackEventExtra.builder().init(PERFETTO_TE_TYPE_INSTANT, category)
+ return PerfettoTrackEventExtra.builder(category.isEnabled())
+ .init(PERFETTO_TE_TYPE_INSTANT, category)
.setEventName(eventName);
}
@@ -243,7 +244,8 @@
* @param eventName The event name to appear in the trace.
*/
public static PerfettoTrackEventExtra.Builder begin(Category category, String eventName) {
- return PerfettoTrackEventExtra.builder().init(PERFETTO_TE_TYPE_SLICE_BEGIN, category)
+ return PerfettoTrackEventExtra.builder(category.isEnabled())
+ .init(PERFETTO_TE_TYPE_SLICE_BEGIN, category)
.setEventName(eventName);
}
@@ -253,7 +255,8 @@
* @param category The perfetto category.
*/
public static PerfettoTrackEventExtra.Builder end(Category category) {
- return PerfettoTrackEventExtra.builder().init(PERFETTO_TE_TYPE_SLICE_END, category);
+ return PerfettoTrackEventExtra.builder(category.isEnabled())
+ .init(PERFETTO_TE_TYPE_SLICE_END, category);
}
/**
@@ -263,7 +266,8 @@
* @param value The value of the counter.
*/
public static PerfettoTrackEventExtra.Builder counter(Category category, long value) {
- return PerfettoTrackEventExtra.builder().init(PERFETTO_TE_TYPE_COUNTER, category)
+ return PerfettoTrackEventExtra.builder(category.isEnabled())
+ .init(PERFETTO_TE_TYPE_COUNTER, category)
.setCounter(value);
}
@@ -286,7 +290,8 @@
* @param value The value of the counter.
*/
public static PerfettoTrackEventExtra.Builder counter(Category category, double value) {
- return PerfettoTrackEventExtra.builder().init(PERFETTO_TE_TYPE_COUNTER, category)
+ return PerfettoTrackEventExtra.builder(category.isEnabled())
+ .init(PERFETTO_TE_TYPE_COUNTER, category)
.setCounter(value);
}
diff --git a/core/java/android/os/PerfettoTrackEventExtra.java b/core/java/android/os/PerfettoTrackEventExtra.java
index 07b44a8..5fc7cf7 100644
--- a/core/java/android/os/PerfettoTrackEventExtra.java
+++ b/core/java/android/os/PerfettoTrackEventExtra.java
@@ -37,6 +37,7 @@
public final class PerfettoTrackEventExtra {
private static final boolean DEBUG = false;
private static final int DEFAULT_EXTRA_CACHE_SIZE = 5;
+ private static final Builder NO_OP_BUILDER = new Builder(/* extra= */ null, /* isCategoryEnabled= */ false);
private static final ThreadLocal<PerfettoTrackEventExtra> sTrackEventExtra =
new ThreadLocal<PerfettoTrackEventExtra>() {
@Override
@@ -153,8 +154,8 @@
private Builder mParent;
private FieldContainer mCurrentContainer;
- private boolean mIsCategoryEnabled;
+ private final boolean mIsCategoryEnabled;
private final CounterInt64 mCounterInt64;
private final CounterDouble mCounterDouble;
private final Proto mProto;
@@ -175,24 +176,29 @@
private final Pool<Builder> mBuilderCache;
private Builder() {
- mExtra = sTrackEventExtra.get();
- mNamedTrackCache = mExtra.mNamedTrackCache;
- mCounterTrackCache = mExtra.mCounterTrackCache;
- mArgInt64Cache = mExtra.mArgInt64Cache;
- mArgDoubleCache = mExtra.mArgDoubleCache;
- mArgBoolCache = mExtra.mArgBoolCache;
- mArgStringCache = mExtra.mArgStringCache;
- mFieldInt64Cache = mExtra.mFieldInt64Cache;
- mFieldDoubleCache = mExtra.mFieldDoubleCache;
- mFieldStringCache = mExtra.mFieldStringCache;
- mFieldNestedCache = mExtra.mFieldNestedCache;
- mBuilderCache = mExtra.mBuilderCache;
+ this(sTrackEventExtra.get(), true);
+ }
- mCounterInt64 = mExtra.getCounterInt64();
- mCounterDouble = mExtra.getCounterDouble();
- mProto = mExtra.getProto();
- mFlow = mExtra.getFlow();
- mTerminatingFlow = mExtra.getTerminatingFlow();
+ public Builder(PerfettoTrackEventExtra extra, boolean isCategoryEnabled) {
+ mIsCategoryEnabled = isCategoryEnabled;
+ mExtra = extra;
+ mNamedTrackCache = mExtra == null ? null : mExtra.mNamedTrackCache;
+ mCounterTrackCache = mExtra == null ? null : mExtra.mCounterTrackCache;
+ mArgInt64Cache = mExtra == null ? null : mExtra.mArgInt64Cache;
+ mArgDoubleCache = mExtra == null ? null : mExtra.mArgDoubleCache;
+ mArgBoolCache = mExtra == null ? null : mExtra.mArgBoolCache;
+ mArgStringCache = mExtra == null ? null : mExtra.mArgStringCache;
+ mFieldInt64Cache = mExtra == null ? null : mExtra.mFieldInt64Cache;
+ mFieldDoubleCache = mExtra == null ? null : mExtra.mFieldDoubleCache;
+ mFieldStringCache = mExtra == null ? null : mExtra.mFieldStringCache;
+ mFieldNestedCache = mExtra == null ? null : mExtra.mFieldNestedCache;
+ mBuilderCache = mExtra == null ? null : mExtra.mBuilderCache;
+
+ mCounterInt64 = mExtra == null ? null : mExtra.getCounterInt64();
+ mCounterDouble = mExtra == null ? null : mExtra.getCounterDouble();
+ mProto = mExtra == null ? null : mExtra.getProto();
+ mFlow = mExtra == null ? null : mExtra.getFlow();
+ mTerminatingFlow = mExtra == null ? null : mExtra.getTerminatingFlow();
}
/**
@@ -214,6 +220,10 @@
* Initialize the builder for a new trace event.
*/
public Builder init(int traceType, PerfettoTrace.Category category) {
+ if (!mIsCategoryEnabled) {
+ return this;
+ }
+
mTraceType = traceType;
mCategory = category;
mEventName = "";
@@ -225,7 +235,7 @@
mExtra.reset();
// Reset after on init in case the thread created builders without calling emit
- return initInternal(this, null, category.isEnabled());
+ return initInternal(this, null);
}
/**
@@ -529,7 +539,7 @@
}
mProto.clearFields();
mExtra.addPerfettoPointer(mProto);
- return mBuilderCache.get(sBuilderSupplier).initInternal(this, mProto, true);
+ return mBuilderCache.get(sBuilderSupplier).initInternal(this, mProto);
}
/**
@@ -560,7 +570,7 @@
FieldNested field = mFieldNestedCache.get(sFieldNestedSupplier);
field.setId(id);
mExtra.addPerfettoPointer(mCurrentContainer, field);
- return mBuilderCache.get(sBuilderSupplier).initInternal(this, field, true);
+ return mBuilderCache.get(sBuilderSupplier).initInternal(this, field);
}
/**
@@ -577,11 +587,9 @@
}
- private Builder initInternal(Builder parent, FieldContainer field,
- boolean isCategoryEnabled) {
+ private Builder initInternal(Builder parent, FieldContainer field) {
mParent = parent;
mCurrentContainer = field;
- mIsCategoryEnabled = isCategoryEnabled;
mIsBuilt = false;
return this;
@@ -613,9 +621,12 @@
/**
* Start a {@link Builder} to build a {@link PerfettoTrackEventExtra}.
*/
- public static Builder builder() {
- return sTrackEventExtra.get().mBuilderCache.get(sBuilderSupplier).initInternal(null, null,
- false);
+ public static Builder builder(boolean isCategoryEnabled) {
+ if (isCategoryEnabled) {
+ return sTrackEventExtra.get().mBuilderCache.get(sBuilderSupplier)
+ .initInternal(null, null);
+ }
+ return NO_OP_BUILDER;
}
private final RingBuffer<NamedTrack> mNamedTrackCache =
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index b52a454..14c154d 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -13,6 +13,16 @@
}
flag {
+ name: "adpf_25q2_metrics"
+ namespace: "game"
+ description: "Add missing metrics for ADPF 25Q2 features."
+ bug: "367803904"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "adpf_gpu_report_actual_work_duration"
is_exported: true
namespace: "game"
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b7e2962..e7bca14 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -13317,10 +13317,18 @@
public static final String CONTEXTUAL_SEARCH_PACKAGE = "contextual_search_package";
/**
- * Inetger property which determines whether advanced protection is on or not.
+ * Integer property which determines whether advanced protection is on or not.
* @hide
*/
public static final String ADVANCED_PROTECTION_MODE = "advanced_protection_mode";
+
+ /**
+ * Integer property which determines whether advanced protection USB data protection
+ * feature is on or not.
+ *
+ * @hide
+ */
+ public static final String AAPM_USB_DATA_PROTECTION = "aapm_usb_data_protection";
}
/**
diff --git a/core/java/android/service/dreams/flags.aconfig b/core/java/android/service/dreams/flags.aconfig
index d3a230d..971942e 100644
--- a/core/java/android/service/dreams/flags.aconfig
+++ b/core/java/android/service/dreams/flags.aconfig
@@ -84,3 +84,11 @@
description: "Allow dreaming when device is stationary and upright"
bug: "383208131"
}
+
+flag {
+ name: "dreams_v2"
+ namespace: "systemui"
+ description: "Enables various improvements to the dream experience "
+ "such as new triggers and various bug fixes"
+ bug: "375689917"
+}
diff --git a/core/java/android/view/IDisplayWindowListener.aidl b/core/java/android/view/IDisplayWindowListener.aidl
index 67ae743..79f61f3 100644
--- a/core/java/android/view/IDisplayWindowListener.aidl
+++ b/core/java/android/view/IDisplayWindowListener.aidl
@@ -64,4 +64,9 @@
* Called when the keep clear ares on a display have changed.
*/
void onKeepClearAreasChanged(int displayId, in List<Rect> restricted, in List<Rect> unrestricted);
+
+ /**
+ * Called when the eligibility of the desktop mode for a display have changed.
+ */
+ void onDesktopModeEligibleChanged(int displayId);
}
diff --git a/core/java/android/view/translation/ListenerGroup.java b/core/java/android/view/ListenerGroup.java
similarity index 77%
rename from core/java/android/view/translation/ListenerGroup.java
rename to core/java/android/view/ListenerGroup.java
index 5c70805..889caec 100644
--- a/core/java/android/view/translation/ListenerGroup.java
+++ b/core/java/android/view/ListenerGroup.java
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-package android.view.translation;
+package android.view;
import android.annotation.NonNull;
-import android.view.ListenerWrapper;
import java.util.ArrayList;
import java.util.List;
@@ -32,26 +31,39 @@
*/
public class ListenerGroup<T> {
private final List<ListenerWrapper<T>> mListeners = new ArrayList<>();
+ @NonNull
+ private T mLastValue;
+
+ /**
+ * Constructs a {@link ListenerGroup} that will replay the last reported value whenever a new
+ * listener is registered.
+ * @param value the initial value
+ */
+ public ListenerGroup(@NonNull T value) {
+ mLastValue = value;
+ }
/**
* Relays the value to all the registered {@link java.util.function.Consumer}
*/
public void accept(@NonNull T value) {
- Objects.requireNonNull(value);
+ mLastValue = Objects.requireNonNull(value);
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).accept(value);
}
}
/**
- * Adds a {@link Consumer} to the group. If the {@link Consumer} is already present then this
- * is a no op.
+ * Adds a {@link Consumer} to the group and replays the last reported value. If the
+ * {@link Consumer} is already present then this is a no op.
*/
public void addListener(@NonNull Executor executor, @NonNull Consumer<T> consumer) {
if (isConsumerPresent(consumer)) {
return;
}
- mListeners.add(new ListenerWrapper<>(executor, consumer));
+ final ListenerWrapper<T> listenerWrapper = new ListenerWrapper<>(executor, consumer);
+ mListeners.add(listenerWrapper);
+ listenerWrapper.accept(mLastValue);
}
/**
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index c4347f0..c7ae328 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -28,6 +28,7 @@
import android.Manifest;
import android.annotation.CallbackExecutor;
+import android.annotation.DurationNanosLong;
import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.IntDef;
@@ -469,9 +470,9 @@
private final long mFrameVsyncId;
private final @JankType int mJankType;
- private final long mFrameIntervalNs;
- private final long mScheduledAppFrameTimeNs;
- private final long mActualAppFrameTimeNs;
+ private final @DurationNanosLong long mFrameIntervalNs;
+ private final @DurationNanosLong long mScheduledAppFrameTimeNs;
+ private final @DurationNanosLong long mActualAppFrameTimeNs;
/**
* @hide
@@ -512,7 +513,7 @@
* @return the frame interval in ns
* @hide
*/
- public long getFrameIntervalNanos() {
+ public @DurationNanosLong long getFrameIntervalNanos() {
return mFrameIntervalNs;
}
@@ -525,7 +526,7 @@
*
* @return scheduled app time in ns
*/
- public long getScheduledAppFrameTimeNanos() {
+ public @DurationNanosLong long getScheduledAppFrameTimeNanos() {
return mScheduledAppFrameTimeNs;
}
@@ -534,7 +535,7 @@
*
* @return the actual app time in ns
*/
- public long getActualAppFrameTimeNanos() {
+ public @DurationNanosLong long getActualAppFrameTimeNanos() {
return mActualAppFrameTimeNs;
}
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index b97f28d..5fdb387 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -44,7 +44,6 @@
import android.util.Pair;
import android.util.SparseArray;
import android.view.inputmethod.InputMethodManager;
-import android.view.translation.ListenerGroup;
import android.window.ITrustedPresentationListener;
import android.window.InputTransferToken;
import android.window.TrustedPresentationThresholds;
@@ -154,7 +153,8 @@
* @hide
*/
@GuardedBy("mLock")
- private final ListenerGroup<List<View>> mWindowViewsListenerGroup = new ListenerGroup<>();
+ private final ListenerGroup<List<View>> mWindowViewsListenerGroup =
+ new ListenerGroup<>(new ArrayList<>());
@UnsupportedAppUsage
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
@UnsupportedAppUsage
@@ -339,7 +339,6 @@
return;
}
mWindowViewsListenerGroup.addListener(executor, consumer);
- executor.execute(() -> consumer.accept(getWindowViews()));
}
}
diff --git a/core/java/android/window/DesktopExperienceFlags.java b/core/java/android/window/DesktopExperienceFlags.java
index 5e8ce5e..04e6c68 100644
--- a/core/java/android/window/DesktopExperienceFlags.java
+++ b/core/java/android/window/DesktopExperienceFlags.java
@@ -64,6 +64,7 @@
ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX(Flags::enableDynamicRadiusComputationBugfix, false),
ENABLE_KEYBOARD_SHORTCUTS_TO_SWITCH_DESKS(Flags::keyboardShortcutsToSwitchDesks, false),
ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT(Flags::enableMoveToNextDisplayShortcut, true),
+ ENABLE_MULTIDISPLAY_TRACKPAD_BACK_GESTURE(Flags::enableMultidisplayTrackpadBackGesture, false),
ENABLE_MULTIPLE_DESKTOPS_BACKEND(Flags::enableMultipleDesktopsBackend, false),
ENABLE_MULTIPLE_DESKTOPS_FRONTEND(Flags::enableMultipleDesktopsFrontend, false),
ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS(
diff --git a/core/java/android/window/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java
index d2893a4..28a922d 100644
--- a/core/java/android/window/DesktopModeFlags.java
+++ b/core/java/android/window/DesktopModeFlags.java
@@ -66,16 +66,16 @@
ENABLE_DESKTOP_INDICATOR_IN_SEPARATE_THREAD_BUGFIX(
Flags::enableDesktopIndicatorInSeparateThreadBugfix, false),
ENABLE_DESKTOP_OPENING_DEEPLINK_MINIMIZE_ANIMATION_BUGFIX(
- Flags::enableDesktopOpeningDeeplinkMinimizeAnimationBugfix, false),
+ Flags::enableDesktopOpeningDeeplinkMinimizeAnimationBugfix, true),
ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX(
- Flags::enableDesktopRecentsTransitionsCornersBugfix, false),
+ Flags::enableDesktopRecentsTransitionsCornersBugfix, true),
ENABLE_DESKTOP_SKIP_COMPAT_UI_EDUCATION_IN_DESKTOP_MODE_BUGFIX(
Flags::skipCompatUiEducationInDesktopMode, true),
ENABLE_DESKTOP_SYSTEM_DIALOGS_TRANSITIONS(Flags::enableDesktopSystemDialogsTransitions, true),
ENABLE_DESKTOP_TAB_TEARING_MINIMIZE_ANIMATION_BUGFIX(
- Flags::enableDesktopTabTearingMinimizeAnimationBugfix, false),
+ Flags::enableDesktopTabTearingMinimizeAnimationBugfix, true),
ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX(
- Flags::enableDesktopTrampolineCloseAnimationBugfix, false),
+ Flags::enableDesktopTrampolineCloseAnimationBugfix, true),
ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER(
Flags::enableDesktopWallpaperActivityForSystemUser, true),
ENABLE_DESKTOP_WINDOWING_APP_TO_WEB(Flags::enableDesktopWindowingAppToWeb, true),
@@ -85,7 +85,7 @@
ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS_BUGFIX(
Flags::enableDesktopWindowingEnterTransitionBugfix, true),
ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX(
- Flags::enableDesktopWindowingExitByMinimizeTransitionBugfix, false),
+ Flags::enableDesktopWindowingExitByMinimizeTransitionBugfix, true),
ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS_BUGFIX(
Flags::enableDesktopWindowingExitTransitionsBugfix, true),
ENABLE_DESKTOP_WINDOWING_HSUM(Flags::enableDesktopWindowingHsum, true),
@@ -107,7 +107,7 @@
true),
ENABLE_DRAG_RESIZE_SET_UP_IN_BG_THREAD(Flags::enableDragResizeSetUpInBgThread, true),
ENABLE_DRAG_TO_DESKTOP_INCOMING_TRANSITIONS_BUGFIX(
- Flags::enableDragToDesktopIncomingTransitionsBugfix, false),
+ Flags::enableDragToDesktopIncomingTransitionsBugfix, true),
ENABLE_FULLY_IMMERSIVE_IN_DESKTOP(Flags::enableFullyImmersiveInDesktop, true),
ENABLE_HANDLE_INPUT_FIX(Flags::enableHandleInputFix, true),
ENABLE_HOLD_TO_DRAG_APP_HANDLE(Flags::enableHoldToDragAppHandle, true),
@@ -134,7 +134,7 @@
ENABLE_TOP_VISIBLE_ROOT_TASK_PER_USER_TRACKING(Flags::enableTopVisibleRootTaskPerUserTracking,
true),
ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX(
- Flags::enableVisualIndicatorInTransitionBugfix, false),
+ Flags::enableVisualIndicatorInTransitionBugfix, true),
ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS(Flags::enableWindowingDynamicInitialBounds, true),
ENABLE_WINDOWING_EDGE_DRAG_RESIZE(Flags::enableWindowingEdgeDragResize, true),
ENABLE_WINDOWING_SCALED_RESIZING(Flags::enableWindowingScaledResizing, true),
@@ -148,7 +148,7 @@
INCLUDE_TOP_TRANSPARENT_FULLSCREEN_TASK_IN_DESKTOP_HEURISTIC(
Flags::includeTopTransparentFullscreenTaskInDesktopHeuristic, true),
INHERIT_TASK_BOUNDS_FOR_TRAMPOLINE_TASK_LAUNCHES(
- Flags::inheritTaskBoundsForTrampolineTaskLaunches, false),
+ Flags::inheritTaskBoundsForTrampolineTaskLaunches, true),
SKIP_DECOR_VIEW_RELAYOUT_WHEN_CLOSING_BUGFIX(
Flags::skipDecorViewRelayoutWhenClosingBugfix, false),
// go/keep-sorted end
diff --git a/core/java/android/window/TaskSnapshot.java b/core/java/android/window/TaskSnapshot.java
index 53c64bd..4ddd733 100644
--- a/core/java/android/window/TaskSnapshot.java
+++ b/core/java/android/window/TaskSnapshot.java
@@ -37,6 +37,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.function.Consumer;
/**
* Represents a task snapshot.
@@ -76,6 +77,7 @@
// Must be one of the named color spaces, otherwise, always use SRGB color space.
private final ColorSpace mColorSpace;
private int mInternalReferences;
+ private Consumer<HardwareBuffer> mSafeSnapshotReleaser;
/** Keep in cache, doesn't need reference. */
public static final int REFERENCE_NONE = 0;
@@ -365,10 +367,26 @@
mInternalReferences &= ~usage;
if (Flags.releaseSnapshotAggressively() && mInternalReferences == 0 && mSnapshot != null
&& !mSnapshot.isClosed()) {
- mSnapshot.close();
+ if (mSafeSnapshotReleaser != null) {
+ mSafeSnapshotReleaser.accept(mSnapshot);
+ } else {
+ mSnapshot.close();
+ }
}
}
+ /**
+ * Register a safe release callback, instead of immediately closing the hardware buffer when
+ * no more reference, to let the system server decide when to close it.
+ * Only used in core.
+ */
+ public synchronized void setSafeRelease(Consumer<HardwareBuffer> releaser) {
+ if (!Flags.safeReleaseSnapshotAggressively()) {
+ return;
+ }
+ mSafeSnapshotReleaser = releaser;
+ }
+
public static final @NonNull Creator<TaskSnapshot> CREATOR = new Creator<TaskSnapshot>() {
public TaskSnapshot createFromParcel(Parcel source) {
return new TaskSnapshot(source);
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 8dd0457..59dd322 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -516,6 +516,17 @@
}
flag {
+ name: "safe_release_snapshot_aggressively"
+ namespace: "windowing_frontend"
+ description: "Protect task snapshot memory from premature release, which can occur when a local variable holds a reference while the snapshot is removed from the cache."
+ bug: "238206323"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "scramble_snapshot_file_name"
namespace: "windowing_frontend"
description: "Scramble the file name of task snapshot."
@@ -524,4 +535,22 @@
metadata {
purpose: PURPOSE_BUGFIX
}
+}
+
+flag {
+ name: "delegate_back_gesture_to_shell"
+ namespace: "windowing_frontend"
+ description: "Delegate back gesture event to back animation controller."
+ bug: "394599430"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "enable_multidisplay_trackpad_back_gesture"
+ namespace: "lse_desktop_experience"
+ description: "Adds support for trackpad back gestures on connected displays"
+ bug: "382774299"
}
\ No newline at end of file
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 94e87c7..2fd295e 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -125,7 +125,7 @@
}
flag {
- namespace: "windowing_sdk"
+ namespace: "car_framework"
name: "safe_region_letterboxing"
description: "Enables letterboxing for a safe region"
bug: "380132497"
diff --git a/core/java/com/android/internal/app/MediaRouteChooserContentManager.java b/core/java/com/android/internal/app/MediaRouteChooserContentManager.java
index 09c6f5e..64538fd 100644
--- a/core/java/com/android/internal/app/MediaRouteChooserContentManager.java
+++ b/core/java/com/android/internal/app/MediaRouteChooserContentManager.java
@@ -17,21 +17,57 @@
package com.android.internal.app;
import android.content.Context;
+import android.media.MediaRouter;
+import android.text.TextUtils;
import android.view.Gravity;
+import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
+import android.widget.TextView;
import com.android.internal.R;
+import java.util.Comparator;
+
public class MediaRouteChooserContentManager {
+ /**
+ * A delegate interface that a MediaRouteChooser UI should implement. It allows the content
+ * manager to inform the UI of any UI changes that need to be made in response to content
+ * updates.
+ */
+ public interface Delegate {
+ /**
+ * Dismiss the UI to transition to a different workflow.
+ */
+ void dismissView();
+
+ /**
+ * Returns true if the progress bar should be shown when the list view is empty.
+ */
+ boolean showProgressBarWhenEmpty();
+ }
+
Context mContext;
+ Delegate mDelegate;
- private final boolean mShowProgressBarWhenEmpty;
+ private final MediaRouter mRouter;
+ private final MediaRouterCallback mCallback;
- public MediaRouteChooserContentManager(Context context, boolean showProgressBarWhenEmpty) {
+ private int mRouteTypes;
+ private RouteAdapter mAdapter;
+ private boolean mAttachedToWindow;
+
+ public MediaRouteChooserContentManager(Context context, Delegate delegate) {
mContext = context;
- mShowProgressBarWhenEmpty = showProgressBarWhenEmpty;
+ mDelegate = delegate;
+
+ mRouter = context.getSystemService(MediaRouter.class);
+ mCallback = new MediaRouterCallback();
+ mAdapter = new RouteAdapter(mContext);
}
/**
@@ -41,9 +77,11 @@
public void bindViews(View containerView) {
View emptyView = containerView.findViewById(android.R.id.empty);
ListView listView = containerView.findViewById(R.id.media_route_list);
+ listView.setAdapter(mAdapter);
+ listView.setOnItemClickListener(mAdapter);
listView.setEmptyView(emptyView);
- if (!mShowProgressBarWhenEmpty) {
+ if (!mDelegate.showProgressBarWhenEmpty()) {
containerView.findViewById(R.id.media_route_progress_bar).setVisibility(View.GONE);
// Center the empty view when the progress bar is not shown.
@@ -53,4 +91,170 @@
emptyView.setLayoutParams(params);
}
}
+
+ /**
+ * Called when this UI is attached to a window..
+ */
+ public void onAttachedToWindow() {
+ mAttachedToWindow = true;
+ mRouter.addCallback(mRouteTypes, mCallback, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
+ refreshRoutes();
+ }
+
+ /**
+ * Called when this UI is detached from a window..
+ */
+ public void onDetachedFromWindow() {
+ mAttachedToWindow = false;
+ mRouter.removeCallback(mCallback);
+ }
+
+ /**
+ * Gets the media route types for filtering the routes that the user can
+ * select using the media route chooser dialog.
+ *
+ * @return The route types.
+ */
+ public int getRouteTypes() {
+ return mRouteTypes;
+ }
+
+ /**
+ * Sets the types of routes that will be shown in the media route chooser dialog
+ * launched by this button.
+ *
+ * @param types The route types to match.
+ */
+ public void setRouteTypes(int types) {
+ if (mRouteTypes != types) {
+ mRouteTypes = types;
+
+ if (mAttachedToWindow) {
+ mRouter.removeCallback(mCallback);
+ mRouter.addCallback(types, mCallback,
+ MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
+ }
+
+ refreshRoutes();
+ }
+ }
+
+ /**
+ * Refreshes the list of routes that are shown in the chooser dialog.
+ */
+ public void refreshRoutes() {
+ if (mAttachedToWindow) {
+ mAdapter.update();
+ }
+ }
+
+ /**
+ * Returns true if the route should be included in the list.
+ * <p>
+ * The default implementation returns true for enabled non-default routes that
+ * match the route types. Subclasses can override this method to filter routes
+ * differently.
+ * </p>
+ *
+ * @param route The route to consider, never null.
+ * @return True if the route should be included in the chooser dialog.
+ */
+ public boolean onFilterRoute(MediaRouter.RouteInfo route) {
+ return !route.isDefault() && route.isEnabled() && route.matchesTypes(mRouteTypes);
+ }
+
+ private final class RouteAdapter extends ArrayAdapter<MediaRouter.RouteInfo>
+ implements AdapterView.OnItemClickListener {
+ private final LayoutInflater mInflater;
+
+ RouteAdapter(Context context) {
+ super(context, 0);
+ mInflater = LayoutInflater.from(context);
+ }
+
+ public void update() {
+ clear();
+ final int count = mRouter.getRouteCount();
+ for (int i = 0; i < count; i++) {
+ MediaRouter.RouteInfo route = mRouter.getRouteAt(i);
+ if (onFilterRoute(route)) {
+ add(route);
+ }
+ }
+ sort(RouteComparator.sInstance);
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return getItem(position).isEnabled();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View view = convertView;
+ if (view == null) {
+ view = mInflater.inflate(R.layout.media_route_list_item, parent, false);
+ }
+ MediaRouter.RouteInfo route = getItem(position);
+ TextView text1 = view.findViewById(android.R.id.text1);
+ TextView text2 = view.findViewById(android.R.id.text2);
+ text1.setText(route.getName());
+ CharSequence description = route.getDescription();
+ if (TextUtils.isEmpty(description)) {
+ text2.setVisibility(View.GONE);
+ text2.setText("");
+ } else {
+ text2.setVisibility(View.VISIBLE);
+ text2.setText(description);
+ }
+ view.setEnabled(route.isEnabled());
+ return view;
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ MediaRouter.RouteInfo route = getItem(position);
+ if (route.isEnabled()) {
+ route.select();
+ mDelegate.dismissView();
+ }
+ }
+ }
+
+ private static final class RouteComparator implements Comparator<MediaRouter.RouteInfo> {
+ public static final RouteComparator sInstance = new RouteComparator();
+
+ @Override
+ public int compare(MediaRouter.RouteInfo lhs, MediaRouter.RouteInfo rhs) {
+ return lhs.getName().toString().compareTo(rhs.getName().toString());
+ }
+ }
+
+ private final class MediaRouterCallback extends MediaRouter.SimpleCallback {
+ @Override
+ public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) {
+ refreshRoutes();
+ }
+
+ @Override
+ public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo info) {
+ refreshRoutes();
+ }
+
+ @Override
+ public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo info) {
+ refreshRoutes();
+ }
+
+ @Override
+ public void onRouteSelected(MediaRouter router, int type, MediaRouter.RouteInfo info) {
+ mDelegate.dismissView();
+ }
+ }
}
diff --git a/core/java/com/android/internal/app/MediaRouteChooserDialog.java b/core/java/com/android/internal/app/MediaRouteChooserDialog.java
index 5030a14..fc7ed89 100644
--- a/core/java/com/android/internal/app/MediaRouteChooserDialog.java
+++ b/core/java/com/android/internal/app/MediaRouteChooserDialog.java
@@ -19,23 +19,14 @@
import android.app.AlertDialog;
import android.content.Context;
import android.media.MediaRouter;
-import android.media.MediaRouter.RouteInfo;
import android.os.Bundle;
-import android.text.TextUtils;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
import android.widget.Button;
-import android.widget.ListView;
-import android.widget.TextView;
import com.android.internal.R;
-import java.util.Comparator;
-
/**
* This class implements the route chooser dialog for {@link MediaRouter}.
* <p>
@@ -47,15 +38,11 @@
*
* TODO: Move this back into the API, as in the support library media router.
*/
-public class MediaRouteChooserDialog extends AlertDialog {
- private final MediaRouter mRouter;
- private final MediaRouterCallback mCallback;
-
- private int mRouteTypes;
+public class MediaRouteChooserDialog extends AlertDialog implements
+ MediaRouteChooserContentManager.Delegate {
private View.OnClickListener mExtendedSettingsClickListener;
- private RouteAdapter mAdapter;
private Button mExtendedSettingsButton;
- private boolean mAttachedToWindow;
+ private final boolean mShowProgressBarWhenEmpty;
private final MediaRouteChooserContentManager mContentManager;
@@ -66,19 +53,8 @@
public MediaRouteChooserDialog(Context context, int theme, boolean showProgressBarWhenEmpty) {
super(context, theme);
- mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
- mCallback = new MediaRouterCallback();
- mContentManager = new MediaRouteChooserContentManager(context, showProgressBarWhenEmpty);
- }
-
- /**
- * Gets the media route types for filtering the routes that the user can
- * select using the media route chooser dialog.
- *
- * @return The route types.
- */
- public int getRouteTypes() {
- return mRouteTypes;
+ mShowProgressBarWhenEmpty = showProgressBarWhenEmpty;
+ mContentManager = new MediaRouteChooserContentManager(context, this);
}
/**
@@ -88,17 +64,7 @@
* @param types The route types to match.
*/
public void setRouteTypes(int types) {
- if (mRouteTypes != types) {
- mRouteTypes = types;
-
- if (mAttachedToWindow) {
- mRouter.removeCallback(mCallback);
- mRouter.addCallback(types, mCallback,
- MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
- }
-
- refreshRoutes();
- }
+ mContentManager.setRouteTypes(types);
}
public void setExtendedSettingsClickListener(View.OnClickListener listener) {
@@ -108,21 +74,6 @@
}
}
- /**
- * Returns true if the route should be included in the list.
- * <p>
- * The default implementation returns true for enabled non-default routes that
- * match the route types. Subclasses can override this method to filter routes
- * differently.
- * </p>
- *
- * @param route The route to consider, never null.
- * @return True if the route should be included in the chooser dialog.
- */
- public boolean onFilterRoute(MediaRouter.RouteInfo route) {
- return !route.isDefault() && route.isEnabled() && route.matchesTypes(mRouteTypes);
- }
-
@Override
protected void onCreate(Bundle savedInstanceState) {
// Note: setView must be called before super.onCreate().
@@ -130,7 +81,7 @@
R.layout.media_route_chooser_dialog, null);
setView(containerView);
- setTitle(mRouteTypes == MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY
+ setTitle(mContentManager.getRouteTypes() == MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY
? R.string.media_route_chooser_title_for_remote_display
: R.string.media_route_chooser_title);
@@ -139,11 +90,6 @@
super.onCreate(savedInstanceState);
- mAdapter = new RouteAdapter(getContext());
- ListView listView = findViewById(R.id.media_route_list);
- listView.setAdapter(mAdapter);
- listView.setOnItemClickListener(mAdapter);
-
mExtendedSettingsButton = findViewById(R.id.media_route_extended_settings_button);
updateExtendedSettingsButton();
@@ -161,27 +107,23 @@
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
-
- mAttachedToWindow = true;
- mRouter.addCallback(mRouteTypes, mCallback, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
- refreshRoutes();
+ mContentManager.onAttachedToWindow();
}
@Override
public void onDetachedFromWindow() {
- mAttachedToWindow = false;
- mRouter.removeCallback(mCallback);
-
+ mContentManager.onDetachedFromWindow();
super.onDetachedFromWindow();
}
- /**
- * Refreshes the list of routes that are shown in the chooser dialog.
- */
- public void refreshRoutes() {
- if (mAttachedToWindow) {
- mAdapter.update();
- }
+ @Override
+ public void dismissView() {
+ dismiss();
+ }
+
+ @Override
+ public boolean showProgressBarWhenEmpty() {
+ return mShowProgressBarWhenEmpty;
}
static boolean isLightTheme(Context context) {
@@ -189,99 +131,4 @@
return context.getTheme().resolveAttribute(R.attr.isLightTheme, value, true)
&& value.data != 0;
}
-
- private final class RouteAdapter extends ArrayAdapter<MediaRouter.RouteInfo>
- implements ListView.OnItemClickListener {
- private final LayoutInflater mInflater;
-
- public RouteAdapter(Context context) {
- super(context, 0);
- mInflater = LayoutInflater.from(context);
- }
-
- public void update() {
- clear();
- final int count = mRouter.getRouteCount();
- for (int i = 0; i < count; i++) {
- MediaRouter.RouteInfo route = mRouter.getRouteAt(i);
- if (onFilterRoute(route)) {
- add(route);
- }
- }
- sort(RouteComparator.sInstance);
- notifyDataSetChanged();
- }
-
- @Override
- public boolean areAllItemsEnabled() {
- return false;
- }
-
- @Override
- public boolean isEnabled(int position) {
- return getItem(position).isEnabled();
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View view = convertView;
- if (view == null) {
- view = mInflater.inflate(R.layout.media_route_list_item, parent, false);
- }
- MediaRouter.RouteInfo route = getItem(position);
- TextView text1 = view.findViewById(android.R.id.text1);
- TextView text2 = view.findViewById(android.R.id.text2);
- text1.setText(route.getName());
- CharSequence description = route.getDescription();
- if (TextUtils.isEmpty(description)) {
- text2.setVisibility(View.GONE);
- text2.setText("");
- } else {
- text2.setVisibility(View.VISIBLE);
- text2.setText(description);
- }
- view.setEnabled(route.isEnabled());
- return view;
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- MediaRouter.RouteInfo route = getItem(position);
- if (route.isEnabled()) {
- route.select();
- dismiss();
- }
- }
- }
-
- private final class MediaRouterCallback extends MediaRouter.SimpleCallback {
- @Override
- public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) {
- refreshRoutes();
- }
-
- @Override
- public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo info) {
- refreshRoutes();
- }
-
- @Override
- public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo info) {
- refreshRoutes();
- }
-
- @Override
- public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
- dismiss();
- }
- }
-
- private static final class RouteComparator implements Comparator<MediaRouter.RouteInfo> {
- public static final RouteComparator sInstance = new RouteComparator();
-
- @Override
- public int compare(MediaRouter.RouteInfo lhs, MediaRouter.RouteInfo rhs) {
- return lhs.getName().toString().compareTo(rhs.getName().toString());
- }
- }
}
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index f1c47a7..3fc74c9 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -79,7 +79,7 @@
private static final String TAG = "BatteryStatsHistory";
// Current on-disk Parcel version. Must be updated when the format of the parcelable changes
- private static final int VERSION = 213;
+ private static final int VERSION = 214;
// Part of initial delta int that specifies the time delta.
static final int DELTA_TIME_MASK = 0x7ffff;
@@ -316,7 +316,6 @@
}
private final Parcel mHistoryBuffer;
- private final HistoryStepDetailsCalculator mStepDetailsCalculator;
private final Clock mClock;
private int mMaxHistoryBufferSize;
@@ -337,25 +336,6 @@
*/
private List<Parcel> mHistoryParcels = null;
- /**
- * When iterating history files, the current file index.
- */
- private BatteryHistoryFragment mCurrentFragment;
-
- /**
- * When iterating history files, the current file parcel.
- */
- private Parcel mCurrentParcel;
- /**
- * When iterating history file, the current parcel's Parcel.dataSize().
- */
- private int mCurrentParcelEnd;
- /**
- * Used when BatteryStatsImpl object is created from deserialization of a parcel,
- * such as Settings app or checkin file, to iterate over history parcels.
- */
- private int mParcelIndex = 0;
-
private final ReentrantLock mWriteLock = new ReentrantLock();
private final HistoryItem mHistoryCur = new HistoryItem();
@@ -384,28 +364,11 @@
// Monotonically increasing size of written history
private long mMonotonicHistorySize;
private final ArraySet<PowerStats.Descriptor> mWrittenPowerStatsDescriptors = new ArraySet<>();
- private byte mLastHistoryStepLevel = 0;
private boolean mMutable = true;
private int mIteratorCookie;
private final BatteryStatsHistory mWritableHistory;
/**
- * A delegate responsible for computing additional details for a step in battery history.
- */
- public interface HistoryStepDetailsCalculator {
- /**
- * Returns additional details for the current history step or null.
- */
- @Nullable
- HistoryStepDetails getHistoryStepDetails();
-
- /**
- * Resets the calculator to get ready for a new battery session
- */
- void clear();
- }
-
- /**
* A delegate for android.os.Trace to allow testing static calls. Due to
* limitations in Android Tracing (b/153319140), the delegate also records
* counter values in system properties which allows reading the value at the
@@ -472,21 +435,17 @@
* @param maxHistoryBufferSize the most amount of RAM to used for buffering of history steps
*/
public BatteryStatsHistory(Parcel historyBuffer, int maxHistoryBufferSize,
- @Nullable BatteryHistoryStore store, HistoryStepDetailsCalculator stepDetailsCalculator,
- Clock clock, MonotonicClock monotonicClock, TraceDelegate tracer,
- EventLogger eventLogger) {
- this(historyBuffer, maxHistoryBufferSize, store,
- stepDetailsCalculator,
- clock, monotonicClock, tracer, eventLogger, null);
+ @Nullable BatteryHistoryStore store, Clock clock, MonotonicClock monotonicClock,
+ TraceDelegate tracer, EventLogger eventLogger) {
+ this(historyBuffer, maxHistoryBufferSize, store, clock, monotonicClock, tracer, eventLogger,
+ null);
}
private BatteryStatsHistory(@Nullable Parcel historyBuffer, int maxHistoryBufferSize,
- @Nullable BatteryHistoryStore store,
- @NonNull HistoryStepDetailsCalculator stepDetailsCalculator, @NonNull Clock clock,
+ @Nullable BatteryHistoryStore store, @NonNull Clock clock,
@NonNull MonotonicClock monotonicClock, @NonNull TraceDelegate tracer,
@NonNull EventLogger eventLogger, @Nullable BatteryStatsHistory writableHistory) {
mMaxHistoryBufferSize = maxHistoryBufferSize;
- mStepDetailsCalculator = stepDetailsCalculator;
mTracer = tracer;
mClock = clock;
mMonotonicClock = monotonicClock;
@@ -527,7 +486,6 @@
mClock = Clock.SYSTEM_CLOCK;
mTracer = null;
mStore = null;
- mStepDetailsCalculator = null;
mEventLogger = new EventLogger();
mWritableHistory = null;
mMutable = false;
@@ -556,9 +514,6 @@
mNextHistoryTagIdx = 0;
mNumHistoryTagChars = 0;
mHistoryBufferLastPos = -1;
- if (mStepDetailsCalculator != null) {
- mStepDetailsCalculator.clear();
- }
}
/**
@@ -596,7 +551,7 @@
Parcel historyBufferCopy = Parcel.obtain();
historyBufferCopy.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
- return new BatteryStatsHistory(historyBufferCopy, 0, mStore, null,
+ return new BatteryStatsHistory(historyBufferCopy, 0, mStore,
null, null, null, mEventLogger, this);
}
} finally {
@@ -712,10 +667,6 @@
if (mStore != null) {
mStore.lock();
}
- mCurrentFragment = null;
- mCurrentParcel = null;
- mCurrentParcelEnd = 0;
- mParcelIndex = 0;
BatteryStatsHistoryIterator iterator = new BatteryStatsHistoryIterator(
this, startTimeMs, endTimeMs);
mIteratorCookie = System.identityHashCode(iterator);
@@ -1614,6 +1565,21 @@
}
/**
+ * Records an update containing HistoryStepDetails, except if the details are empty.
+ */
+ public void recordHistoryStepDetails(HistoryStepDetails details, long elapsedRealtimeMs,
+ long uptimeMs) {
+ if (details.isEmpty()) {
+ return;
+ }
+ synchronized (this) {
+ mHistoryCur.stepDetails = details;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ mHistoryCur.stepDetails = null;
+ }
+ }
+
+ /**
* Writes the current history item to history.
*/
public void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs) {
@@ -1632,8 +1598,8 @@
mHistoryAddTmp.processStateChange = null;
mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE;
mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG;
+ mHistoryAddTmp.stepDetails = null;
writeHistoryItem(wakeElapsedTimeMs, uptimeMs, mHistoryAddTmp);
-
}
}
mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG;
@@ -1952,15 +1918,8 @@
}
int firstToken = deltaTimeToken | (cur.states & BatteryStatsHistory.DELTA_STATE_MASK);
- if (cur.batteryLevel < mLastHistoryStepLevel || mLastHistoryStepLevel == 0) {
- cur.stepDetails = mStepDetailsCalculator.getHistoryStepDetails();
- if (cur.stepDetails != null) {
- batteryLevelInt |= BatteryStatsHistory.BATTERY_LEVEL_DETAILS_FLAG;
- mLastHistoryStepLevel = cur.batteryLevel;
- }
- } else {
- cur.stepDetails = null;
- mLastHistoryStepLevel = cur.batteryLevel;
+ if (cur.stepDetails != null) {
+ batteryLevelInt |= BatteryStatsHistory.BATTERY_LEVEL_DETAILS_FLAG;
}
final boolean batteryLevelIntChanged = batteryLevelInt != 0;
@@ -2055,6 +2014,7 @@
+ Integer.toHexString(cur.states2));
}
}
+ cur.tagsFirstOccurrence = false;
if (cur.wakelockTag != null || cur.wakeReasonTag != null) {
int wakeLockIndex;
int wakeReasonIndex;
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
index 6f7e5ad..7cecc39 100644
--- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -66,6 +66,7 @@
import com.android.internal.protolog.common.ILogger;
import com.android.internal.protolog.common.IProtoLog;
import com.android.internal.protolog.common.IProtoLogGroup;
+import com.android.internal.protolog.common.InvalidFormatStringException;
import com.android.internal.protolog.common.LogDataType;
import com.android.internal.protolog.common.LogLevel;
@@ -207,7 +208,12 @@
@Override
public void log(LogLevel logLevel, IProtoLogGroup group, String messageString, Object... args) {
- log(logLevel, group, new Message(messageString), args);
+ try {
+ log(logLevel, group, new Message(messageString), args);
+ } catch (InvalidFormatStringException e) {
+ Slog.e(LOG_TAG, "Invalid protolog string format", e);
+ log(logLevel, group, new Message("INVALID MESSAGE"), new Object[0]);
+ }
}
/**
@@ -831,7 +837,7 @@
this.mMessageString = null;
}
- private Message(@NonNull String messageString) {
+ private Message(@NonNull String messageString) throws InvalidFormatStringException {
this.mMessageHash = null;
final List<Integer> argTypes = LogDataType.parseFormatString(messageString);
this.mMessageMask = LogDataType.logDataTypesToBitMask(argTypes);
diff --git a/core/java/com/android/internal/protolog/common/LogDataType.java b/core/java/com/android/internal/protolog/common/LogDataType.java
index c05824a..10b07d9 100644
--- a/core/java/com/android/internal/protolog/common/LogDataType.java
+++ b/core/java/com/android/internal/protolog/common/LogDataType.java
@@ -86,8 +86,8 @@
case '%':
break;
default:
- throw new InvalidFormatStringException("Invalid format string field"
- + " %${messageString[i + 1]}");
+ throw new InvalidFormatStringException("Invalid Protolog message format in "
+ + "\"" + messageString + "\" at index " + i + ".");
}
i += 2;
} else {
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 3da1922..822ef34a 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -401,9 +401,19 @@
@RemotableViewMethod(asyncImpl = "setIsCollapsedAsync")
public void setIsCollapsed(boolean isCollapsed) {
mIsCollapsed = isCollapsed;
- mMessagingLinearLayout.setMaxDisplayedLines(isCollapsed
- ? TextUtils.isEmpty(mSummarizedContent) ? 1 : MAX_SUMMARIZATION_LINES
- : Integer.MAX_VALUE);
+ int maxLines = Integer.MAX_VALUE;
+ if (isCollapsed) {
+ if (!TextUtils.isEmpty(mSummarizedContent)) {
+ maxLines = MAX_SUMMARIZATION_LINES;
+ } else {
+ if (android.app.Flags.nmCollapsedLines()) {
+ maxLines = 2;
+ } else {
+ maxLines = 1;
+ }
+ }
+ }
+ mMessagingLinearLayout.setMaxDisplayedLines(maxLines);
updateExpandButton();
updateContentEndPaddings();
}
@@ -1177,7 +1187,9 @@
nameOverride = mNameReplacement;
}
newGroup.setShowingAvatar(!mIsOneToOne && !mIsCollapsed);
- newGroup.setSingleLine(mIsCollapsed && TextUtils.isEmpty(mSummarizedContent));
+ newGroup.setSingleLine(mIsCollapsed
+ ? !android.app.Flags.nmCollapsedLines() && TextUtils.isEmpty(mSummarizedContent)
+ : false);
newGroup.setIsCollapsed(mIsCollapsed);
newGroup.setSender(sender, nameOverride);
newGroup.setSending(groupIndex == (groups.size() - 1) && showSpinner);
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 4cc4b38..f9c8228 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -157,6 +157,10 @@
@RemotableViewMethod(asyncImpl = "setIsCollapsedAsync")
public void setIsCollapsed(boolean isCollapsed) {
mIsCollapsed = isCollapsed;
+ if (mIsCollapsed) {
+ mMessagingLinearLayout.setMaxDisplayedLines(
+ android.app.Flags.nmCollapsedLines() ? 2 : 1);
+ }
}
/**
@@ -549,7 +553,9 @@
if (sender != mUser && mNameReplacement != null) {
nameOverride = mNameReplacement;
}
- newGroup.setSingleLine(mIsCollapsed && TextUtils.isEmpty(mSummarizedContent));
+ newGroup.setSingleLine(mIsCollapsed
+ ? !android.app.Flags.nmCollapsedLines() && TextUtils.isEmpty(mSummarizedContent)
+ : false);
newGroup.setShowingAvatar(!mIsCollapsed);
newGroup.setIsCollapsed(mIsCollapsed);
newGroup.setSender(sender, nameOverride);
diff --git a/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java b/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java
index e8aeb86..d8093c4 100644
--- a/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java
+++ b/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java
@@ -233,6 +233,7 @@
private final boolean mMatchSystemAppsOnly;
private volatile ServiceChangedListener mListener;
+ private @Nullable String mUnstableService;
private CurrentUserServiceSupplier(Context context, String action,
@Nullable String explicitPackage, @Nullable String callerPermission,
@@ -330,6 +331,20 @@
}
}
+ // Prefer any service over the unstable service.
+ if (mUnstableService != null && serviceInfo != null && bestServiceInfo != null) {
+ if (mUnstableService.equals(serviceInfo.toString())) {
+ Log.d(TAG, "Not choosing unstable service " + mUnstableService
+ + " as we already have a service " + bestServiceInfo.toString());
+ continue;
+ } else if (mUnstableService.equals(bestServiceInfo.toString())) {
+ Log.d(TAG, "Choosing service " + serviceInfo.toString()
+ + " over the unstable service " + mUnstableService);
+ bestServiceInfo = serviceInfo;
+ continue;
+ }
+ }
+
if (sBoundServiceInfoComparator.compare(serviceInfo, bestServiceInfo) > 0) {
bestServiceInfo = serviceInfo;
}
@@ -338,6 +353,17 @@
return bestServiceInfo;
}
+ /**
+ * Alerts the supplier that the given service is unstable.
+ *
+ * The service marked as unstable will be unpreferred over any other services,
+ * which will last until the next device restart.
+ */
+ @Override
+ public void alertUnstableService(String unstableService) {
+ mUnstableService = unstableService;
+ }
+
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
diff --git a/core/java/com/android/server/servicewatcher/OWNERS b/core/java/com/android/server/servicewatcher/OWNERS
index ced619f..dbc598e 100644
--- a/core/java/com/android/server/servicewatcher/OWNERS
+++ b/core/java/com/android/server/servicewatcher/OWNERS
@@ -1,5 +1,5 @@
# Bug component: 25692
-sooniln@google.com
+dnchrist@google.com
wyattriley@google.com
diff --git a/core/java/com/android/server/servicewatcher/ServiceWatcher.java b/core/java/com/android/server/servicewatcher/ServiceWatcher.java
index 38872c9..12dad35 100644
--- a/core/java/com/android/server/servicewatcher/ServiceWatcher.java
+++ b/core/java/com/android/server/servicewatcher/ServiceWatcher.java
@@ -140,6 +140,11 @@
* null if no service currently meets the criteria. Only invoked while registered.
*/
@Nullable TBoundServiceInfo getServiceInfo();
+
+ /**
+ * Alerts the supplier that the given service is unstable.
+ */
+ void alertUnstableService(String unstableService);
}
/**
@@ -230,6 +235,19 @@
}
/**
+ * Creates a new ServiceWatcher instance.
+ */
+ static <TBoundServiceInfo extends BoundServiceInfo> ServiceWatcher create(
+ Context context,
+ String tag,
+ boolean unstableFallbackEnabled,
+ ServiceSupplier<TBoundServiceInfo> serviceSupplier,
+ @Nullable ServiceListener<? super TBoundServiceInfo> serviceListener) {
+ return create(context, FgThread.getHandler(), tag, unstableFallbackEnabled,
+ serviceSupplier, serviceListener);
+ }
+
+ /**
* Creates a new ServiceWatcher instance that runs on the given handler.
*/
static <TBoundServiceInfo extends BoundServiceInfo> ServiceWatcher create(
@@ -242,6 +260,20 @@
}
/**
+ * Creates a new ServiceWatcher instance that runs on the given handler.
+ */
+ static <TBoundServiceInfo extends BoundServiceInfo> ServiceWatcher create(
+ Context context,
+ Handler handler,
+ String tag,
+ boolean unstableFallbackEnabled,
+ ServiceSupplier<TBoundServiceInfo> serviceSupplier,
+ @Nullable ServiceListener<? super TBoundServiceInfo> serviceListener) {
+ return new ServiceWatcherImpl<>(context, handler, tag, unstableFallbackEnabled,
+ serviceSupplier, serviceListener);
+ }
+
+ /**
* Returns true if there is at least one service that the ServiceWatcher could hypothetically
* bind to, as selected by the {@link ServiceSupplier}.
*/
diff --git a/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java b/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java
index ccbab9f..30d8710 100644
--- a/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java
+++ b/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java
@@ -21,11 +21,13 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.location.flags.Flags;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Log;
@@ -52,12 +54,22 @@
static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
static final long RETRY_DELAY_MS = 15 * 1000;
+ /* Used for the unstable fallback logic, it is the time period in milliseconds where the number
+ * of disconnections is tracked in order to determine if the service is unstable. */
+ private static final long UNSTABLE_TIME_PERIOD_MS = 60 * 1000;
+ /* Used for the unstable fallback logic, it is the number of disconnections within the time
+ * period that will mark the service as unstable and allow the fallback to a stable service. */
+ private static final int DISCONNECTED_COUNT_BEFORE_MARKED_AS_UNSTABLE = 10;
final Context mContext;
final Handler mHandler;
final String mTag;
final ServiceSupplier<TBoundServiceInfo> mServiceSupplier;
final @Nullable ServiceListener<? super TBoundServiceInfo> mServiceListener;
+ private boolean mUnstableFallbackEnabled;
+ private @Nullable String mDisconnectedService;
+ private long mDisconnectedStartTime;
+ private int mDisconnectedCount;
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override
@@ -86,6 +98,20 @@
mServiceListener = serviceListener;
}
+ ServiceWatcherImpl(Context context, Handler handler, String tag,
+ boolean unstableFallbackEnabled,
+ ServiceSupplier<TBoundServiceInfo> serviceSupplier,
+ ServiceListener<? super TBoundServiceInfo> serviceListener) {
+ mContext = context;
+ mHandler = handler;
+ mTag = tag;
+ if (Flags.serviceWatcherUnstableFallback()) {
+ mUnstableFallbackEnabled = unstableFallbackEnabled;
+ }
+ mServiceSupplier = serviceSupplier;
+ mServiceListener = serviceListener;
+ }
+
@Override
public boolean checkServiceResolves() {
return mServiceSupplier.hasMatchingService();
@@ -178,6 +204,7 @@
// volatile so that isConnected can be called from any thread easily
private volatile @Nullable IBinder mBinder;
private @Nullable Runnable mRebinder;
+ private boolean mForcingRebind;
MyServiceConnection(@Nullable TBoundServiceInfo boundServiceInfo) {
mBoundServiceInfo = boundServiceInfo;
@@ -269,6 +296,11 @@
Log.i(TAG, "[" + mTag + "] connected to " + component.toShortString());
mBinder = binder;
+ /* Used to keep track of whether we are forcing a rebind, so that we don't force a
+ * rebind while in the process of already forcing a rebind. This is needed because
+ * onServiceDisconnected and onBindingDied can happen in quick succession and we only
+ * want one rebind to happen in this case. */
+ mForcingRebind = false;
if (mServiceListener != null) {
try {
@@ -295,6 +327,44 @@
if (mServiceListener != null) {
mServiceListener.onUnbind();
}
+
+ // If unstable fallback is not enabled or no current service is bound, then avoid the
+ // unstable fallback logic below and return early.
+ if (!mUnstableFallbackEnabled
+ || mBoundServiceInfo == null
+ || mBoundServiceInfo.toString() == null) {
+ return;
+ }
+
+ String currentService = mBoundServiceInfo.toString();
+ // If the service has already disconnected within the time period, increment the count.
+ // Otherwise, set the service as disconnected, set the start time, and reset the count.
+ if (Objects.equals(mDisconnectedService, currentService)
+ && mDisconnectedStartTime > 0
+ && (SystemClock.elapsedRealtime() - mDisconnectedStartTime
+ <= UNSTABLE_TIME_PERIOD_MS)) {
+ mDisconnectedCount++;
+ } else {
+ mDisconnectedService = currentService;
+ mDisconnectedStartTime = SystemClock.elapsedRealtime();
+ mDisconnectedCount = 1;
+ }
+ Log.d(TAG, "[" + mTag + "] Service disconnected : " + currentService + " Count = "
+ + mDisconnectedCount);
+ if (mDisconnectedCount >= DISCONNECTED_COUNT_BEFORE_MARKED_AS_UNSTABLE) {
+ Log.i(TAG, "[" + mTag + "] Service disconnected too many times, set as unstable : "
+ + mDisconnectedService);
+ // Alert this service as unstable will last until the next device restart.
+ mServiceSupplier.alertUnstableService(mDisconnectedService);
+ mDisconnectedService = null;
+ mDisconnectedStartTime = 0;
+ mDisconnectedCount = 0;
+ // Force rebind to allow the possibility of fallback to a stable service.
+ if (!mForcingRebind) {
+ mForcingRebind = true;
+ onServiceChanged(/*forceRebind=*/ true);
+ }
+ }
}
@Override
@@ -305,7 +375,10 @@
// introduce a small delay to prevent spamming binding over and over, since the likely
// cause of a binding dying is some package event that may take time to recover from
- mHandler.postDelayed(() -> onServiceChanged(true), 500);
+ if (!mForcingRebind) {
+ mForcingRebind = true;
+ mHandler.postDelayed(() -> onServiceChanged(/*forceRebind=*/ true), 500);
+ }
}
@Override
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 7daa4b4..03a31dd 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1808,9 +1808,9 @@
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"زيادة تعتيم الشاشة"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"سماعات الأذن الطبية"</string>
<string name="autoclick_feature_name" msgid="8149248738736949630">"النقر التلقائي"</string>
- <string name="hearing_device_status_disconnected" msgid="497547752953543832">"غير متّصل"</string>
- <string name="hearing_device_status_connected" msgid="2149385149669918764">"متّصل"</string>
- <string name="hearing_device_status_active" msgid="4770378695482566032">"متّصل حاليًا"</string>
+ <string name="hearing_device_status_disconnected" msgid="497547752953543832">"غير متّصلة"</string>
+ <string name="hearing_device_status_connected" msgid="2149385149669918764">"متّصلة"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"متّصلة حاليًا"</string>
<string name="hearing_device_status_loading" msgid="5717083847663109747">"غير متاح بعد"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"تم الضغط مع الاستمرار على مفتاحَي التحكّم في مستوى الصوت. تم تفعيل <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"تم الضغط مع الاستمرار على مفتاحَي التحكّم في مستوى الصوت. تم إيقاف <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 5d83f78..981c56d 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1451,12 +1451,12 @@
<string name="usb_power_notification_message" msgid="7284765627437897702">"Φόρτιση συνδεδεμένης συσκευής. Πατήστε για περισσότερες επιλογές."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Εντοπίστηκε αναλογικό αξεσουάρ ήχου"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Η συνδεδεμένη συσκευή δεν είναι συμβατή με αυτό το τηλέφωνο. Πατήστε για να μάθετε περισσότερα."</string>
- <string name="adb_active_notification_title" msgid="408390247354560331">"Eνεργός εντοπ. σφαλματών USB"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"Πατήστε για απενεργ. εντοπ. σφαλμ. USB"</string>
- <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Επιλογή για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string>
- <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Συνδέθηκε ο ασύρματος εντοπισμός σφαλμάτων"</string>
- <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Πατήστε, για να απενεργοποιήσετε τον ασύρματο εντοπισμό σφαλμάτων"</string>
- <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Επιλέξτε, για να απενεργοποιήσετε τον ασύρματο εντοπισμό σφαλμάτων."</string>
+ <string name="adb_active_notification_title" msgid="408390247354560331">"Eνεργή αποσφαλμάτωση USB"</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"Πατήστε για απενεργ. αποσφαλμάτ. USB"</string>
+ <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Επιλογή για απενεργοποίηση του αποσφαλμάτωσης USB."</string>
+ <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Συνδέθηκε η ασύρματη αποσφαλμάτωση"</string>
+ <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Πατήστε, για να απενεργοποιήσετε την ασύρματη αποσφαλμάτωση"</string>
+ <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Επιλέξτε, για να απενεργοποιήσετε την ασύρματη αποσφαλμάτωση."</string>
<string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Η λειτουργία περιβάλλοντος δοκιμών ενεργοποιήθηκε"</string>
<string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Εκτελέστε επαναφορά εργοστασιακών ρυθμίσεων για να απενεργοποιήσετε τη λειτουργία περιβάλλοντος δοκιμών."</string>
<string name="wrong_hsum_configuration_notification_title" msgid="7212758829332714385">"Λάθος διαμόρφωση κατασκευής HSUM"</string>
@@ -2127,7 +2127,7 @@
<string name="app_category_productivity" msgid="1844422703029557883">"Παραγωγικότητα"</string>
<string name="app_category_accessibility" msgid="6643521607848547683">"Προσβασιμότητα"</string>
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Αποθηκευτικός χώρος συσκευής"</string>
- <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Εντοπισμός σφαλμάτων USB"</string>
+ <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Αποσφαλμάτωση USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ώρα"</string>
<string name="time_picker_minute_label" msgid="8307452311269824553">"λεπτό"</string>
<string name="time_picker_header_text" msgid="9073802285051516688">"Ορισμός ώρας"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 7a49905..bbf4c99 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -2273,18 +2273,12 @@
<string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Egin gora eta behera"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausatu"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Ezarri posizioan"</string>
- <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) -->
- <skip />
+ <string name="accessibility_autoclick_scroll_up" msgid="2044948780797117443">"Egin gora"</string>
+ <string name="accessibility_autoclick_scroll_down" msgid="3733401063292018116">"Egin behera"</string>
+ <string name="accessibility_autoclick_scroll_left" msgid="8564421367992824198">"Egin ezkerrera"</string>
+ <string name="accessibility_autoclick_scroll_right" msgid="8932417330753984265">"Egin eskuinera"</string>
+ <string name="accessibility_autoclick_scroll_exit" msgid="3788610039146769696">"Irten gora/behera egiteko modutik"</string>
+ <string name="accessibility_autoclick_scroll_panel_title" msgid="7120598166296447036">"Gora/Behera egiteko panela"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Murriztuen edukiontzian ezarri da <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"erabiltzaileak irudi bat bidali du"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index dce063d..0083fd9 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1214,8 +1214,8 @@
<string name="Noon" msgid="6902418443846838189">"Keskipäivä"</string>
<string name="midnight" msgid="3646671134282785114">"keskiyö"</string>
<string name="Midnight" msgid="8176019203622191377">"Keskiyö"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="8689459651807876423">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="2302144714803345056">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_mm_ss" msgid="8689459651807876423">"<xliff:g id="MINUTES">%1$02d</xliff:g>.<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss" msgid="2302144714803345056">"<xliff:g id="HOURS">%1$d</xliff:g>.<xliff:g id="MINUTES">%2$02d</xliff:g>.<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="1532369154488982046">"Valitse kaikki"</string>
<string name="cut" msgid="2561199725874745819">"Leikkaa"</string>
<string name="copy" msgid="5472512047143665218">"Kopioi"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 6b1e284..1d2f975 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -2486,8 +2486,7 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"ઑફિસ 3"</string>
<string name="profile_label_test" msgid="9168641926186071947">"પરીક્ષણ કરો"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"કૉમ્યુનલ"</string>
- <!-- no translation found for profile_label_supervising (5649312778545745371) -->
- <skip />
+ <string name="profile_label_supervising" msgid="5649312778545745371">"નિરીક્ષણ કરનાર"</string>
<string name="accessibility_label_managed_profile" msgid="3366526886209832641">"ઑફિસની પ્રોફાઇલ"</string>
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"ખાનગી સ્પેસ"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ક્લોન"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 5e32b96..b3ce1c8 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -2486,8 +2486,7 @@
<string name="profile_label_work_3" msgid="4834572253956798917">"कार्य प्रोफाइल ३"</string>
<string name="profile_label_test" msgid="9168641926186071947">"परीक्षण"</string>
<string name="profile_label_communal" msgid="8743921499944800427">"सामुदायिक"</string>
- <!-- no translation found for profile_label_supervising (5649312778545745371) -->
- <skip />
+ <string name="profile_label_supervising" msgid="5649312778545745371">"सुपरिवेक्षण गरिँदै छ"</string>
<string name="accessibility_label_managed_profile" msgid="3366526886209832641">"कार्य प्रोफाइल"</string>
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"निजी स्पेस"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"क्लोन"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index a15cf4e..5c9bece 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -2273,18 +2273,12 @@
<string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Lëviz"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Vendos në pauzë"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozicioni"</string>
- <!-- no translation found for accessibility_autoclick_scroll_up (2044948780797117443) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_scroll_down (3733401063292018116) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_scroll_left (8564421367992824198) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_scroll_right (8932417330753984265) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_scroll_exit (3788610039146769696) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_scroll_panel_title (7120598166296447036) -->
- <skip />
+ <string name="accessibility_autoclick_scroll_up" msgid="2044948780797117443">"Lëviz lart"</string>
+ <string name="accessibility_autoclick_scroll_down" msgid="3733401063292018116">"Lëviz poshtë"</string>
+ <string name="accessibility_autoclick_scroll_left" msgid="8564421367992824198">"Lëviz majtas"</string>
+ <string name="accessibility_autoclick_scroll_right" msgid="8932417330753984265">"Lëviz djathtas"</string>
+ <string name="accessibility_autoclick_scroll_exit" msgid="3788610039146769696">"Dil nga modaliteti i lëvizjes"</string>
+ <string name="accessibility_autoclick_scroll_panel_title" msgid="7120598166296447036">"Paneli i lëvizjes"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> është vendosur në grupin E KUFIZUAR"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"dërgoi një imazh"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1a74fe6..828461c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2125,14 +2125,27 @@
<!-- Package name providing fused location support. Used only when
config_enableFusedLocationOverlay is false. -->
<string name="config_fusedLocationProviderPackageName" translatable="false">com.android.location.fused</string>
+ <!-- If true, will fallback to use a different app if the chosen overlay app is determined to
+ be unstable. Used only when config_enableFusedLocationOverlay is true. -->
+ <bool name="config_fusedLocationOverlayUnstableFallback" translatable="false">false</bool>
<!-- If true will use the GNSS hardware implementation to service the GPS_PROVIDER. If false
will allow the GPS_PROVIDER to be replaced by an app at run-time (restricted to the package
specified by config_gnssLocationProviderPackageName). -->
<bool name="config_useGnssHardwareProvider" translatable="false">true</bool>
+ <!-- Whether to enable gnss location provider overlay which allows gnss location provider to
+ be replaced by an app at run-time. When disabled, only the
+ config_gnssLocationProviderPackageName package will be searched for gnss location
+ provider, otherwise any system package is eligible. Anyone who wants to disable the overlay
+ mechanism can set it to false. Used only when config_useGnssHardwareProvider is false -->
+ <bool name="config_enableGnssLocationOverlay" translatable="false">true</bool>
<!-- Package name providing GNSS location support. Used only when
config_useGnssHardwareProvider is false. -->
<string name="config_gnssLocationProviderPackageName" translatable="false">@null</string>
+ <!-- If true, will fallback to use a different app if the chosen overlay app is determined to
+ be unstable. Used only when config_useGnssHardwareProvider is false and
+ config_enableGnssLocationOverlay is true. -->
+ <bool name="config_gnssLocationOverlayUnstableFallback" translatable="false">false</bool>
<!-- Default value for the ADAS GNSS Location Enabled setting if this setting has never been
set before. -->
@@ -3209,6 +3222,10 @@
Note that HSUM devices without this enabled will not automatically have a main user. -->
<bool name="config_isMainUserPermanentAdmin">true</bool>
+ <!-- Whether all secondary users (and the system user) are eligible to have profiles.
+ If false, only the MainUser is eligible to have profiles. -->
+ <bool name="config_supportProfilesOnNonMainUser">false</bool>
+
<!-- Whether switch to headless system user is allowed. If allowed,
headless system user can run in the foreground even though it is not a full user. -->
<bool name="config_canSwitchToHeadlessSystemUser">false</bool>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 849ca28..fc46418 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -262,7 +262,22 @@
carrier_supported_satellite_services_per_provider_bundle does not support them.
-->
<string-array name="config_satellite_providers" translatable="false">
+ <!-- T-Mobile - USA -->
<item>"310830"</item>
+ <!-- Entel Chile - Chile -->
+ <item>"73029"</item>
+ <!-- KDDI - Japan -->
+ <item>"44055"</item>
+ <!-- Kyivstar - Ukraine -->
+ <item>"255707"</item>
+ <!-- One NZ - New Zealand -->
+ <item>"53013"</item>
+ <!-- Optus - Australia -->
+ <item>"50559"</item>
+ <!-- Rogers - Canada -->
+ <item>"302723"</item>
+ <!-- Telstra - Australia -->
+ <item>"50511"</item>
</string-array>
<java-symbol type="array" name="config_satellite_providers" />
@@ -303,6 +318,11 @@
<bool name="config_send_satellite_datagram_to_modem_in_demo_mode">false</bool>
<java-symbol type="bool" name="config_send_satellite_datagram_to_modem_in_demo_mode" />
+ <!-- Whether the device supports disabling satellite while satellite enabling is in progress.
+ -->
+ <bool name="config_support_disable_satellite_while_enable_in_progress">true</bool>
+ <java-symbol type="bool" name="config_support_disable_satellite_while_enable_in_progress" />
+
<!-- List of country codes where oem-enabled satellite services are either allowed or disallowed
by the device. Each country code is a lowercase 2 character ISO-3166-1 alpha-2.
-->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a37ca28..219ac3f8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -363,6 +363,7 @@
<java-symbol type="bool" name="config_speed_up_audio_on_mt_calls" />
<java-symbol type="bool" name="config_useFixedVolume" />
<java-symbol type="bool" name="config_isMainUserPermanentAdmin"/>
+ <java-symbol type="bool" name="config_supportProfilesOnNonMainUser"/>
<java-symbol type="bool" name="config_canSwitchToHeadlessSystemUser"/>
<java-symbol type="bool" name="config_enableMultiUserUI"/>
<java-symbol type="bool" name="config_enableMultipleAdmins"/>
@@ -2049,6 +2050,9 @@
<java-symbol type="bool" name="config_enableActivityRecognitionHardwareOverlay" />
<java-symbol type="bool" name="config_defaultAdasGnssLocationEnabled" />
<java-symbol type="bool" name="config_enableFusedLocationOverlay" />
+ <java-symbol type="bool" name="config_enableGnssLocationOverlay" />
+ <java-symbol type="bool" name="config_fusedLocationOverlayUnstableFallback" />
+ <java-symbol type="bool" name="config_gnssLocationOverlayUnstableFallback" />
<java-symbol type="bool" name="config_useGnssHardwareProvider" />
<java-symbol type="bool" name="config_enableGeocoderOverlay" />
<java-symbol type="bool" name="config_enableGeofenceOverlay" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 9b3a6cb..36564cd 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -358,7 +358,7 @@
<!-- USA: 5-6 digits (premium codes from https://www.premiumsmsrefunds.com/ShortCodes.htm),
visual voicemail code for T-Mobile: 122 -->
- <shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" standard="44567|244444" free="122|87902|21696|24614|28003|30356|33669|40196|41064|41270|43753|44034|46645|52413|56139|57969|61785|66975|75136|76227|81398|83952|85140|86566|86799|95737|96684|99245|611611|96831|10907" />
+ <shortcode country="us" pattern="\\d{5,6}" free="122|\\d{5,6}" />
<!--Uruguay : 1-6 digits (standard system default, not country specific) -->
<shortcode country="uy" pattern="\\d{1,6}" free="55002|191289" />
diff --git a/core/tests/coretests/src/android/util/ArrayMapTest.java b/core/tests/coretests/src/android/util/ArrayMapTest.java
index d71a603..a00f530 100644
--- a/core/tests/coretests/src/android/util/ArrayMapTest.java
+++ b/core/tests/coretests/src/android/util/ArrayMapTest.java
@@ -18,7 +18,6 @@
import static org.junit.Assert.fail;
-import android.platform.test.annotations.DisabledOnRavenwood;
import android.platform.test.annotations.Presubmit;
import android.platform.test.ravenwood.RavenwoodRule;
@@ -57,7 +56,6 @@
*/
@Test
@Ignore("Failing; b/399137661")
- @DisabledOnRavenwood(reason = "Long test runtime")
public void testConcurrentModificationException() throws Exception {
final int TEST_LEN_MS = 5000;
System.out.println("Starting ArrayMap concurrency test");
diff --git a/core/tests/coretests/src/android/util/ArraySetTest.java b/core/tests/coretests/src/android/util/ArraySetTest.java
index 8888991..dec7b59 100644
--- a/core/tests/coretests/src/android/util/ArraySetTest.java
+++ b/core/tests/coretests/src/android/util/ArraySetTest.java
@@ -22,6 +22,7 @@
import androidx.test.filters.LargeTest;
import org.junit.After;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,6 +51,7 @@
* internals.
*/
@Test
+ @Ignore("Failing; b/399137661")
public void testConcurrentModificationException() throws Exception {
final int testDurMs = 10_000;
System.out.println("Starting ArraySet concurrency test");
diff --git a/core/tests/coretests/src/com/android/internal/app/MediaRouteChooserContentManagerTest.kt b/core/tests/coretests/src/com/android/internal/app/MediaRouteChooserContentManagerTest.kt
new file mode 100644
index 0000000..bbed6e0
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/app/MediaRouteChooserContentManagerTest.kt
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.app
+
+import android.content.Context
+import android.media.MediaRouter
+import android.testing.TestableLooper.RunWithLooper
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.LinearLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.internal.R
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+
+@SmallTest
+@RunWithLooper(setAsMainLooper = true)
+@RunWith(AndroidJUnit4::class)
+class MediaRouteChooserContentManagerTest {
+ private val context: Context = getInstrumentation().context
+
+ @Test
+ fun bindViews_showProgressBarWhenEmptyTrue_progressBarVisible() {
+ val delegate = mock<MediaRouteChooserContentManager.Delegate> {
+ on { showProgressBarWhenEmpty() } doReturn true
+ }
+ val contentManager = MediaRouteChooserContentManager(context, delegate)
+ val containerView = inflateMediaRouteChooserDialog()
+ contentManager.bindViews(containerView)
+
+ assertThat(containerView.findViewById<View>(R.id.media_route_progress_bar).visibility)
+ .isEqualTo(View.VISIBLE)
+ }
+
+ @Test
+ fun bindViews_showProgressBarWhenEmptyFalse_progressBarNotVisible() {
+ val delegate = mock<MediaRouteChooserContentManager.Delegate> {
+ on { showProgressBarWhenEmpty() } doReturn false
+ }
+ val contentManager = MediaRouteChooserContentManager(context, delegate)
+ val containerView = inflateMediaRouteChooserDialog()
+ contentManager.bindViews(containerView)
+ val emptyView = containerView.findViewById<View>(android.R.id.empty)
+ val emptyViewLayout = emptyView.layoutParams as? LinearLayout.LayoutParams
+
+ assertThat(containerView.findViewById<View>(R.id.media_route_progress_bar).visibility)
+ .isEqualTo(View.GONE)
+ assertThat(emptyView.visibility).isEqualTo(View.VISIBLE)
+ assertThat(emptyViewLayout?.gravity).isEqualTo(Gravity.CENTER)
+ }
+
+ @Test
+ fun onFilterRoute_routeDefault_returnsFalse() {
+ val delegate: MediaRouteChooserContentManager.Delegate = mock()
+ val contentManager = MediaRouteChooserContentManager(context, delegate)
+ val route: MediaRouter.RouteInfo = mock<MediaRouter.RouteInfo> {
+ on { isDefault } doReturn true
+ }
+
+ assertThat(contentManager.onFilterRoute(route)).isEqualTo(false)
+ }
+
+ @Test
+ fun onFilterRoute_routeNotEnabled_returnsFalse() {
+ val delegate: MediaRouteChooserContentManager.Delegate = mock()
+ val contentManager = MediaRouteChooserContentManager(context, delegate)
+ val route: MediaRouter.RouteInfo = mock<MediaRouter.RouteInfo> {
+ on { isEnabled } doReturn false
+ }
+
+ assertThat(contentManager.onFilterRoute(route)).isEqualTo(false)
+ }
+
+ @Test
+ fun onFilterRoute_routeNotMatch_returnsFalse() {
+ val delegate: MediaRouteChooserContentManager.Delegate = mock()
+ val contentManager = MediaRouteChooserContentManager(context, delegate)
+ val route: MediaRouter.RouteInfo = mock<MediaRouter.RouteInfo> {
+ on { matchesTypes(anyInt()) } doReturn false
+ }
+
+ assertThat(contentManager.onFilterRoute(route)).isEqualTo(false)
+ }
+
+ @Test
+ fun onFilterRoute_returnsTrue() {
+ val delegate: MediaRouteChooserContentManager.Delegate = mock()
+ val contentManager = MediaRouteChooserContentManager(context, delegate)
+ val route: MediaRouter.RouteInfo = mock<MediaRouter.RouteInfo> {
+ on { isDefault } doReturn false
+ on { isEnabled } doReturn true
+ on { matchesTypes(anyInt()) } doReturn true
+ }
+
+ assertThat(contentManager.onFilterRoute(route)).isEqualTo(true)
+ }
+
+ @Test
+ fun onAttachedToWindow() {
+ val delegate: MediaRouteChooserContentManager.Delegate = mock()
+ val mediaRouter: MediaRouter = mock()
+ val layoutInflater: LayoutInflater = mock()
+ val context: Context = mock<Context> {
+ on { getSystemServiceName(MediaRouter::class.java) } doReturn Context.MEDIA_ROUTER_SERVICE
+ on { getSystemService(MediaRouter::class.java) } doReturn mediaRouter
+ on { getSystemService(Context.LAYOUT_INFLATER_SERVICE) } doReturn layoutInflater
+ }
+ val contentManager = MediaRouteChooserContentManager(context, delegate)
+ contentManager.routeTypes = MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY
+
+ contentManager.onAttachedToWindow()
+
+ verify(mediaRouter).addCallback(eq(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY), any(),
+ eq(MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN))
+ }
+
+ @Test
+ fun onDetachedFromWindow() {
+ val delegate: MediaRouteChooserContentManager.Delegate = mock()
+ val layoutInflater: LayoutInflater = mock()
+ val mediaRouter: MediaRouter = mock()
+ val context: Context = mock<Context> {
+ on { getSystemServiceName(MediaRouter::class.java) } doReturn Context.MEDIA_ROUTER_SERVICE
+ on { getSystemService(MediaRouter::class.java) } doReturn mediaRouter
+ on { getSystemService(Context.LAYOUT_INFLATER_SERVICE) } doReturn layoutInflater
+ }
+ val contentManager = MediaRouteChooserContentManager(context, delegate)
+
+ contentManager.onDetachedFromWindow()
+
+ verify(mediaRouter).removeCallback(any())
+ }
+
+ @Test
+ fun setRouteTypes() {
+ val delegate: MediaRouteChooserContentManager.Delegate = mock()
+ val mediaRouter: MediaRouter = mock()
+ val layoutInflater: LayoutInflater = mock()
+ val context: Context = mock<Context> {
+ on { getSystemServiceName(MediaRouter::class.java) } doReturn Context.MEDIA_ROUTER_SERVICE
+ on { getSystemService(MediaRouter::class.java) } doReturn mediaRouter
+ on { getSystemService(Context.LAYOUT_INFLATER_SERVICE) } doReturn layoutInflater
+ }
+ val contentManager = MediaRouteChooserContentManager(context, delegate)
+ contentManager.onAttachedToWindow()
+
+ contentManager.routeTypes = MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY
+
+ assertThat(contentManager.routeTypes).isEqualTo(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY)
+ verify(mediaRouter).addCallback(eq(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY), any(),
+ eq(MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN))
+ }
+
+ private fun inflateMediaRouteChooserDialog(): View {
+ return LayoutInflater.from(context)
+ .inflate(R.layout.media_route_chooser_dialog, null, false)
+ }
+}
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 8f85617..98278f4 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -184,6 +184,14 @@
}
prebuilt_etc {
+ name: "privapp_whitelist_com.android.statementservice",
+ system_ext_specific: true,
+ sub_dir: "permissions",
+ src: "com.android.statementservice.xml",
+ filename_from_src: true,
+}
+
+prebuilt_etc {
name: "privapp_whitelist_com.android.settings.intelligence",
product_specific: true,
sub_dir: "permissions",
diff --git a/data/etc/com.android.statementservice.xml b/data/etc/com.android.statementservice.xml
new file mode 100644
index 0000000..e102af2
--- /dev/null
+++ b/data/etc/com.android.statementservice.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<permissions>
+ <privapp-permissions package="com.android.statementservice">
+ <permission name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
+ <permission name="android.permission.DOMAIN_VERIFICATION_AGENT"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ </privapp-permissions>
+</permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 9234902..1dd0465 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -623,12 +623,6 @@
<permission name="android.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE"/>
</privapp-permissions>
- <privapp-permissions package="com.android.statementservice">
- <permission name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
- <permission name="android.permission.DOMAIN_VERIFICATION_AGENT"/>
- <permission name="android.permission.INTERACT_ACROSS_USERS"/>
- </privapp-permissions>
-
<privapp-permissions package="com.android.soundpicker">
<permission name="android.permission.INTERACT_ACROSS_USERS" />
</privapp-permissions>
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index bcb6c4f5..033c934 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -26,9 +26,11 @@
java_library {
name: "wm_shell_protolog-groups",
srcs: [
- ":protolog-common-src",
"src/com/android/wm/shell/protolog/ShellProtoLogGroup.java",
],
+ static_libs: [
+ "protolog-common-lib",
+ ],
}
filegroup {
@@ -159,12 +161,12 @@
android_library {
name: "WindowManager-Shell",
srcs: [
- ":wm_shell_protolog_src",
// TODO(b/168581922) protologtool do not support kotlin(*.kt)
- "src/com/android/wm/shell/EventLogTags.logtags",
":wm_shell-aidls",
":wm_shell-shared-aidls",
":wm_shell-sources-kt",
+ ":wm_shell_protolog_src",
+ "src/com/android/wm/shell/EventLogTags.logtags",
],
resource_dirs: [
"res",
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index 19455a3..e873dc7 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -179,6 +179,16 @@
}
flag {
+ name: "fix_missing_user_change_callbacks"
+ namespace: "multitasking"
+ description: "Fix a race condition that could make Shell miss a user change callback."
+ bug: "404251029"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "enable_bubble_bar_on_phones"
namespace: "multitasking"
description: "Try out bubble bar on phones"
diff --git a/libs/WindowManager/Shell/res/drawable/desktop_windowing_transition_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_windowing_transition_background.xml
index dd1a1b1..75ec2ab 100644
--- a/libs/WindowManager/Shell/res/drawable/desktop_windowing_transition_background.xml
+++ b/libs/WindowManager/Shell/res/drawable/desktop_windowing_transition_background.xml
@@ -18,15 +18,15 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<item android:id="@+id/indicator_solid">
<shape android:shape="rectangle">
- <solid android:color="@androidprv:color/materialColorPrimaryContainer" />
+ <solid android:color="@androidprv:color/materialColorPrimaryFixed" />
<corners android:radius="28dp" />
</shape>
</item>
<item android:id="@+id/indicator_stroke">
<shape android:shape="rectangle">
<corners android:radius="28dp" />
- <stroke android:width="1dp"
- android:color="@androidprv:color/materialColorPrimaryContainer"/>
+ <stroke android:width="2dp"
+ android:color="@androidprv:color/materialColorPrimaryFixed"/>
</shape>
</item>
</layer-list>
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index 05c4c56..f42fea6 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Nuwe venster"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Bestuur vensters"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Verander aspekverhouding"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Maak toe"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Maak kieslys toe"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (werkskermvensters)"</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index 450419d..c65bb38 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"አዲስ መስኮት"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"መስኮቶችን አስተዳድር"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ምጥጥነ ገፅታ ለውጥ"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"ዝጋ"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"ምናሌ ዝጋ"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ዴስክቶፕ መስኮት)"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 70a23b7..d06d992 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -100,8 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ألم يتم حل المشكلة؟\nانقر للعودة"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"أليس هناك مشاكل في الكاميرا؟ انقر للإغلاق."</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"يمكن العثور على قائمة التطبيقات هنا"</string>
- <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) -->
- <skip />
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"يمكنك الدخول إلى وضع عرض المحتوى في النافذة الحالية على سطح المكتب لفتح عدة تطبيقات معًا"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"يمكنك الرجوع إلى وضع ملء الشاشة في أي وقت من قائمة التطبيقات"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"استخدام تطبيقات متعدّدة في وقت واحد"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"اسحب تطبيقًا آخر لاستخدام وضع تقسيم الشاشة."</string>
@@ -122,8 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"مقبض التطبيق"</string>
<string name="app_icon_text" msgid="2823268023931811747">"رمز التطبيق"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"ملء الشاشة"</string>
- <!-- no translation found for desktop_text (9058641752519570266) -->
- <skip />
+ <string name="desktop_text" msgid="9058641752519570266">"عرض المحتوى في النافذة الحالية على سطح المكتب"</string>
<string name="split_screen_text" msgid="1396336058129570886">"تقسيم الشاشة"</string>
<string name="more_button_text" msgid="3655388105592893530">"المزيد"</string>
<string name="float_button_text" msgid="9221657008391364581">"نافذة عائمة"</string>
@@ -134,10 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"نافذة جديدة"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"إدارة النوافذ"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"تغيير نسبة العرض إلى الارتفاع"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"إغلاق"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"إغلاق القائمة"</string>
- <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) -->
- <skip />
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (عرض المحتوى في النافذة الحالية على سطح المكتب)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"تكبير الشاشة إلى أقصى حدّ"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"تغيير الحجم"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"لا يمكن نقل التطبيق إلى هنا"</string>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index b1826db..1d1a048 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"নতুন ৱিণ্ড’"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ৱিণ্ড’ পৰিচালনা কৰক"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"আকাৰৰ অনুপাত সলনি কৰক"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"বন্ধ কৰক"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"মেনু বন্ধ কৰক"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ডেস্কটপ ৱিণ্ড’ৱিং)"</string>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index c5493b5..2770ede1a 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Yeni pəncərə"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Pəncərələri idarə edin"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Tərəflər nisbətini dəyişin"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Bağlayın"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Menyunu bağlayın"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Masaüstü pəncərə rejimi)"</string>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index 307c47a..615b558 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Novi prozor"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Upravljajte prozorima"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promeni razmeru"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Zatvorite"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite meni"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (prozorski prikaz za računare)"</string>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index c53e37c..d83ed57 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Новае акно"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Кіраваць вокнамі"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Змяніць суадносіны бакоў"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Закрыць"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Закрыць меню"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (рэжым вокнаў працоўнага стала)"</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index 29af2ed..9b91d3d 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Нов прозорец"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Управление на прозорците"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промяна на съотношението"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Затваряне"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Затваряне на менюто"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (режим за настолни компютри)"</string>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index d4488a2..9fd156f 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -100,8 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এখনও সমাধান হয়নি?\nরিভার্ট করার জন্য ট্যাপ করুন"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ক্যামেরা সংক্রান্ত সমস্যা নেই? বাতিল করতে ট্যাপ করুন।"</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"অ্যাপ মেনু এখানে খুঁজে পাওয়া যাবে"</string>
- <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) -->
- <skip />
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"একসাথে একাধিক অ্যাপ খোলার জন্য ডেস্কটপ উইন্ডোইংয়ে এন্টার করুন"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"অ্যাপ মেনু থেকে ফুল-স্ক্রিন মোডে যেকোনও সময়ে ফিরে আসুন"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"দেখুন ও আরও অনেক কিছু করুন"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"স্প্লিট স্ক্রিনের ক্ষেত্রে অন্য কোনও অ্যাপ টেনে আনুন"</string>
@@ -122,8 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"অ্যাপের হ্যান্ডেল"</string>
<string name="app_icon_text" msgid="2823268023931811747">"অ্যাপ আইকন"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"ফুলস্ক্রিন"</string>
- <!-- no translation found for desktop_text (9058641752519570266) -->
- <skip />
+ <string name="desktop_text" msgid="9058641752519570266">"ডেস্কটপ উইন্ডোইং"</string>
<string name="split_screen_text" msgid="1396336058129570886">"স্প্লিট স্ক্রিন"</string>
<string name="more_button_text" msgid="3655388105592893530">"আরও"</string>
<string name="float_button_text" msgid="9221657008391364581">"ফ্লোট"</string>
@@ -134,10 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"নতুন উইন্ডো"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"উইন্ডো ম্যানেজ করুন"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"অ্যাস্পেক্ট রেশিও পরিবর্তন করুন"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"বন্ধ করুন"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"\'মেনু\' বন্ধ করুন"</string>
- <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) -->
- <skip />
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ডেস্কটপ উইন্ডোইং)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্রিন বড় করুন"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ছোট বড় করুন"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"অ্যাপটি এখানে সরানো যাবে না"</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 537afdc..4834ad8 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -100,7 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nije popravljeno?\nDodirnite da vratite"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nema problema s kamerom? Dodirnite da odbacite."</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Ovdje možete pronaći meni aplikacije"</string>
- <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"Otvorite prikaz u prozorima na računalu da biste otvorili više aplikacija zajedno"</string>
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"Ulazak u računarski prikaz prozora radi istovremenog otvaranja više aplikacija"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Povratak na prikaz preko cijelog ekrana bilo kada putem menija aplikacije"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Pogledajte i učinite više"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Prevucite još jednu aplikaciju za podijeljeni ekran"</string>
@@ -121,7 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"Ručica aplikacije"</string>
<string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Cijeli ekran"</string>
- <string name="desktop_text" msgid="9058641752519570266">"Prikaz u prozorima na računalu"</string>
+ <string name="desktop_text" msgid="9058641752519570266">"Računarski prikaz prozora"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Podijeljeni ekran"</string>
<string name="more_button_text" msgid="3655388105592893530">"Više"</string>
<string name="float_button_text" msgid="9221657008391364581">"Lebdeći"</string>
@@ -132,9 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"Novi prozor"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Upravljanje prozorima"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promjena formata slike"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Zatvaranje"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Zatvaranje menija"</string>
- <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (prikaz u prozorima na računalu)"</string>
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (računarski prikaz prozora)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiziraj ekran"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Promijeni veličinu"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ne možete premjestiti aplikaciju ovdje"</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 42b07ef..662bd81 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Finestra nova"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gestiona les finestres"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Canvia la relació d\'aspecte"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Tanca"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Tanca el menú"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (enfinestrament d\'escriptori)"</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index 4454868..12c9e29 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Nové okno"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Spravovat okna"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Změnit poměr stran"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Zavřít"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Zavřít nabídku"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (okna na ploše)"</string>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index 4d14f93..5df06ea 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Nyt vindue"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Administrer vinduer"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Skift billedformat"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Luk"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Luk menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (vinduer på skrivebordet)"</string>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index 82bbfc4..b3444e0 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Neues Fenster"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Fenster verwalten"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Seitenverhältnis ändern"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Schließen"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Menü schließen"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Desktop-Freiform-Fenster)"</string>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index a8696af..c137513 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Νέο παράθυρο"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Διαχείριση παραθύρων"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Αλλαγή λόγου διαστάσεων"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Κλείσιμο"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Κλείσιμο μενού"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Προσαρμογή σε παράθυρο στην επιφάνεια εργασίας)"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index 61b68a2..a3156bc 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -132,9 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"New window"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Manage windows"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Close"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
- <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (desktop windowing)"</string>
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Desktop windowing)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index 0802f83..3e2de7c 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -132,6 +132,7 @@
<string name="new_window_text" msgid="6318648868380652280">"New Window"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Manage Windows"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string>
+ <string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimize View"</string>
<string name="close_text" msgid="4986518933445178928">"Close"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Close Menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Desktop windowing)"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index 61b68a2..a3156bc 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -132,9 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"New window"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Manage windows"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Close"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
- <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (desktop windowing)"</string>
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Desktop windowing)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index 61b68a2..a3156bc 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -132,9 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"New window"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Manage windows"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Close"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
- <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (desktop windowing)"</string>
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Desktop windowing)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index bb70f6e..6027f7d 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -100,8 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se resolvió?\nPresiona para revertir los cambios"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No tienes problemas con la cámara? Presionar para descartar."</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"El menú de la app se encuentra aquí"</string>
- <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) -->
- <skip />
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"Entra a la renderización en ventanas de escritorio para abrir varias apps a la vez"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Regresa a pantalla completa en cualquier momento desde el menú de la app"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Aprovecha más"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arrastra otra app para el modo de pantalla dividida"</string>
@@ -122,8 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"Controlador de la app"</string>
<string name="app_icon_text" msgid="2823268023931811747">"Ícono de la app"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string>
- <!-- no translation found for desktop_text (9058641752519570266) -->
- <skip />
+ <string name="desktop_text" msgid="9058641752519570266">"Renderización en ventanas de escritorio"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Pantalla dividida"</string>
<string name="more_button_text" msgid="3655388105592893530">"Más"</string>
<string name="float_button_text" msgid="9221657008391364581">"Flotante"</string>
@@ -134,10 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"Nueva ventana"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Administrar ventanas"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambiar relación de aspecto"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Cerrar"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string>
- <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) -->
- <skip />
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (renderización en ventanas de escritorio)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Dividir pantalla"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"No se puede mover la app aquí"</string>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index a6595aa..81c9e1b 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -100,8 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se ha solucionado?\nToca para revertir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No hay problemas con la cámara? Toca para cerrar."</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"El menú de la aplicación se encuentra aquí"</string>
- <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) -->
- <skip />
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"Entra en el escritorio basado en ventanas si quieres abrir varias aplicaciones a la vez"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Vuelve a la pantalla completa en cualquier momento desde el menú de aplicaciones"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Consulta más información y haz más"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arrastra otra aplicación para activar la pantalla dividida"</string>
@@ -122,8 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"Controlador de la aplicación"</string>
<string name="app_icon_text" msgid="2823268023931811747">"Icono de la aplicación"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string>
- <!-- no translation found for desktop_text (9058641752519570266) -->
- <skip />
+ <string name="desktop_text" msgid="9058641752519570266">"Escritorio basado en ventanas"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Pantalla dividida"</string>
<string name="more_button_text" msgid="3655388105592893530">"Más"</string>
<string name="float_button_text" msgid="9221657008391364581">"Flotante"</string>
@@ -134,10 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"Ventana nueva"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gestionar ventanas"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambiar relación de aspecto"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Cerrar"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string>
- <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) -->
- <skip />
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (escritorio basado en ventanas)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Dividir pantalla"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"La aplicación no se puede mover aquí"</string>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index c0e4eb3..f43348d 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Uus aken"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Akende haldamine"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Kuvasuhte muutmine"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Sule"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Sule menüü"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (töölaua aknad)"</string>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index 446839a..4ac27c2 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -100,8 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ez al da konpondu?\nLeheneratzeko, sakatu hau."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ez daukazu arazorik kamerarekin? Baztertzeko, sakatu hau."</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Aplikazioaren menua dago hemen"</string>
- <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) -->
- <skip />
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"Sartu ordenagailuan leihoak erabiltzeko modua aplikazio bat baino gehiago batera irekitzeko"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Pantaila osoko modura itzultzeko, erabili aplikazioaren menua"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Ikusi eta egin gauza gehiago"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Pantaila zatitua ikusteko, arrastatu beste aplikazio bat"</string>
@@ -122,8 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"Aplikazioaren kontrol-puntua"</string>
<string name="app_icon_text" msgid="2823268023931811747">"Aplikazioaren ikonoa"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Pantaila osoa"</string>
- <!-- no translation found for desktop_text (9058641752519570266) -->
- <skip />
+ <string name="desktop_text" msgid="9058641752519570266">"Ordenagailuan leihoak erabiltzeko modua"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Pantaila zatitzea"</string>
<string name="more_button_text" msgid="3655388105592893530">"Gehiago"</string>
<string name="float_button_text" msgid="9221657008391364581">"Leiho gainerakorra"</string>
@@ -134,10 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"Leiho berria"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Kudeatu leihoak"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Aldatu aspektu-erlazioa"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Itxi"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Itxi menua"</string>
- <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) -->
- <skip />
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ordenagailuan leihoak erabiltzeko modua)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Handitu pantaila"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Aldatu tamaina"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikazioa ezin da hona ekarri"</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index 4879965..93a9438 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"پنجره جدید"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"مدیریت کردن پنجرهها"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"تغییر نسبت ابعادی"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"بستن"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"بستن منو"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (پردازش پنجرهای رایانه)"</string>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index 8fd6b1b..7c9e6e6 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Uusi ikkuna"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Hallinnoi ikkunoita"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Vaihda kuvasuhdetta"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Sulje"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Sulje valikko"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (työpöydän ikkunointi)"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index b729ece..c78b313 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Nouvelle fenêtre"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gérer les fenêtres"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Modifier les proportions"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Fermer"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (fenêtrage du bureau)"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index ed87a13..708212f 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Nouvelle fenêtre"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gérer les fenêtres"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Modifier le format"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Fermer"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (fenêtrage de bureau)"</string>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index a2b87112..a0a4df1 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Ventá nova"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Xestionar as ventás"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambiar a proporción"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Pechar"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Pechar o menú"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (escritorio baseado en ventás)"</string>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index ddef9e1..2a546fa 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"નવી વિન્ડો"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"વિન્ડો મેનેજ કરો"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"સાપેક્ષ ગુણોત્તર બદલો"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"બંધ કરો"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"મેનૂ બંધ કરો"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ડેસ્કટૉપ વિન્ડોઇંગ)"</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index bbe43a1..c2eb2b2 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"नई विंडो"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"विंडो मैनेज करें"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) बदलें"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"बंद करें"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"मेन्यू बंद करें"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (डेस्कटॉप विंडोविंग)"</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 80ee561..41315fe 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Novi prozor"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Upravljanje prozorima"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promijeni omjer slike"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Zatvorite"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite izbornik"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (prikaz u prozorima na računalu)"</string>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index d24e4da..0ebf2cb 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -100,7 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nem sikerült a hiba kijavítása?\nKoppintson a visszaállításhoz."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nincsenek problémái kamerával? Koppintson az elvetéshez."</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Az alkalmazásmenü itt található"</string>
- <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"Asztali ablakkezelési módba lépve több alkalmazást nyithat meg egyidejűleg"</string>
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"Asztali ablakkezelési módba lépve egyidejűleg több alkalmazást is megnyithat"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Az alkalmazásmenüből bármikor visszatérhet a teljes képernyőre"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Több mindent láthat és tehet"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Húzzon ide egy másik alkalmazást az osztott képernyő használatához"</string>
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Új ablak"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Ablakok kezelése"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Méretarány módosítása"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Bezárás"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Menü bezárása"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Asztali ablakkezelési mód)"</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 6bc3c37..a792f5bd 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Նոր պատուհան"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Կառավարել պատուհանները"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Փոխել կողմերի հարաբերակցությունը"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Փակել"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Փակել ընտրացանկը"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (համակարգչային պատուհաններ)"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index c15c2ea..7201045 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Jendela Baru"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Kelola Jendela"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Ubah rasio aspek"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Tutup"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Mode jendela desktop)"</string>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 7d98d3b..8488c30 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Nýr gluggi"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Stjórna gluggum"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Breyta myndhlutfalli"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Loka"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Loka valmynd"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (gluggastilling í tölvu)"</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index 72f80569..4fc60dd 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Nuova finestra"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gestisci finestre"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambia proporzioni"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Chiudi"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Chiudi il menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (windowing del desktop)"</string>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index c3e8523..be14b00 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -100,8 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"הבעיה לא נפתרה?\nאפשר ללחוץ כדי לחזור לגרסה הקודמת"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"אין בעיות במצלמה? אפשר ללחוץ כדי לסגור."</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"תפריט האפליקציה נמצא כאן"</string>
- <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) -->
- <skip />
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"כדי לפתוח כמה אפליקציות יחד, צריך להיכנס למצב \"שינוי דינמי של חלונות במחשב\" (desktop windowing)"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"אפשר לחזור למסך מלא בכל שלב מתפריט האפליקציה"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"רוצה לראות ולעשות יותר?"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"צריך לגרור אפליקציה אחרת כדי להשתמש במסך המפוצל"</string>
@@ -122,8 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"נקודת אחיזה לאפליקציה"</string>
<string name="app_icon_text" msgid="2823268023931811747">"סמל האפליקציה"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"מסך מלא"</string>
- <!-- no translation found for desktop_text (9058641752519570266) -->
- <skip />
+ <string name="desktop_text" msgid="9058641752519570266">"שינוי דינמי של חלונות במחשב"</string>
<string name="split_screen_text" msgid="1396336058129570886">"מסך מפוצל"</string>
<string name="more_button_text" msgid="3655388105592893530">"עוד"</string>
<string name="float_button_text" msgid="9221657008391364581">"בלונים"</string>
@@ -134,10 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"חלון חדש"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ניהול החלונות"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"שינוי יחס הגובה-רוחב"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"סגירה"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"סגירת התפריט"</string>
- <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) -->
- <skip />
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (שינוי דינמי של חלונות במחשב)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"הגדלת המסך"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"שינוי הגודל"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"לא ניתן להעביר את האפליקציה לכאן"</string>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index c95ec4e..761df5c 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"新しいウィンドウ"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ウィンドウを管理する"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"アスペクト比を変更"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"閉じる"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"メニューを閉じる"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g>(デスクトップ ウィンドウ)"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 0c7264c..d5c44fb 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"ახალი ფანჯარა"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ფანჯრების მართვა"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"თანაფარდობის შეცვლა"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"დახურვა"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"მენიუს დახურვა"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (დესკტოპის ფანჯრის რეჟიმი)"</string>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index c1085db..3a9711e 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -100,7 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Жөнделмеді ме?\nҚайтару үшін түртіңіз."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада қателер шықпады ма? Жабу үшін түртіңіз."</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Қолданба мәзірін осы жерден табуға болады."</string>
- <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"Бірнеше қолданбаны бірге ашу үшін жұмыс үстелі көрінісіне кіріңіз."</string>
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"Бірнеше қолданбаны бірге ашу үшін компьютерлік терезелер режиміне кіріңіз."</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Қолданба мәзірінен кез келген уақытта толық экранға оралыңыз."</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Қосымша ақпаратты қарап, әрекеттер жасау"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Экранды бөлу үшін басқа қолданбаға өтіңіз."</string>
@@ -121,7 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"Қолданба идентификаторы"</string>
<string name="app_icon_text" msgid="2823268023931811747">"Қолданба белгішесі"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Толық экран"</string>
- <string name="desktop_text" msgid="9058641752519570266">"Жұмыс үстелі көрінісі"</string>
+ <string name="desktop_text" msgid="9058641752519570266">"Компьютерлік терезелер режимі"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Экранды бөлу"</string>
<string name="more_button_text" msgid="3655388105592893530">"Қосымша"</string>
<string name="float_button_text" msgid="9221657008391364581">"Қалқыма"</string>
@@ -132,9 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"Жаңа терезе"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Терезелерді басқару"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Арақатынасты өзгерту"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Жабу"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Мәзірді жабу"</string>
- <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (жұмыс үстелі көрінісі)"</string>
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (компьютерлік терезелер режимі)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Экранды ұлғайту"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Өлшемін өзгерту"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Қолданба бұл жерге қойылмайды."</string>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index afbd9e0..c4b5a9b 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"វិនដូថ្មី"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"គ្រប់គ្រងវិនដូ"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ប្ដូរសមាមាត្រ"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"បិទ"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"បិទម៉ឺនុយ"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (មុខងារវិនដូកុំព្យូទ័រ)"</string>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 34076e8..9d3ec2a 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"ಹೊಸ ವಿಂಡೋ"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ವಿಂಡೋಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ದೃಶ್ಯಾನುಪಾತವನ್ನು ಬದಲಾಯಿಸಿ"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"ಮುಚ್ಚಿ"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"ಮೆನು ಮುಚ್ಚಿ"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ಡೆಸ್ಕ್ಟಾಪ್ ವಿಂಡೋಯಿಂಗ್)"</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index a0fa7e4..5206b83 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"새 창"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"창 관리"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"가로세로 비율 변경"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"닫기"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"메뉴 닫기"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g>(데스크톱 윈도윙)"</string>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 629070c..810a638 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Жаңы терезе"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Терезелерди тескөө"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Тараптардын катнашын өзгөртүү"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Жабуу"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Менюну жабуу"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Иш тактанын терезелери)"</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index f2d0e6b..7a4fb61 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"ໜ້າຈໍໃໝ່"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ຈັດການໜ້າຈໍ"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ປ່ຽນອັດຕາສ່ວນຮູບ"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"ປິດ"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"ປິດເມນູ"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ໜ້າຈໍເດັສທັອບ)"</string>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index ed4b14c..75619ea 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Naujas langas"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Tvarkyti langus"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Keisti kraštinių santykį"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Uždaryti"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Uždaryti meniu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ (versijos staliniams kompiuteriams rodinys)"</string>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index c24b43a..5eea17c 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Jauns logs"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Pārvaldīt logus"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Mainīt malu attiecību"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Aizvērt"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Aizvērt izvēlni"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (darbvirsmas logošana)"</string>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index 06ed323..4653aa2 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Нов прозорец"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Управувајте со прозорците"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промени го соодносот"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Затворете"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Затворете го менито"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (режим со прозорци на работната површина)"</string>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index dd4ec1b..50c2f6e 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"പുതിയ വിന്ഡോ"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"വിൻഡോകൾ മാനേജ് ചെയ്യുക"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"വീക്ഷണ അനുപാതം മാറ്റുക"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"അടയ്ക്കുക"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"മെനു അടയ്ക്കുക"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ഡെസ്ക്ടോപ്പ് വിൻഡോയിംഗ്)"</string>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index 8683827..80e83a5 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Шинэ цонх"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Цонхнуудыг удирдах"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Аспектын харьцааг өөрчлөх"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Хаах"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Цэсийг хаах"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Дэлгэцийн цонх үүсгэх онцлог)"</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index b7b3fb6..deb0baf 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"नवीन विंडो"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"विंडो व्यवस्थापित करा"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"आस्पेक्ट रेशो बदला"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"बंद करा"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"मेनू बंद करा"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (डेस्कटॉप विंडोइंग)"</string>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index 0896b5e..1f56033 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Tetingkap Baharu"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Urus Tetingkap"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Tukar nisbah bidang"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Tutup"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Tetingkap desktop)"</string>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index 0f336e8..061ad04 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"ဝင်းဒိုးအသစ်"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ဝင်းဒိုးများ စီမံရန်"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"အချိုးအစား ပြောင်းရန်"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"ပိတ်ရန်"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"မီနူး ပိတ်ရန်"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ဒက်စ်တော့ဝင်းဒိုးမုဒ်)"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 3207614..232fb2b 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Nytt vindu"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Administrer vinduene"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Endre høyde/bredde-forholdet"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Lukk"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Lukk menyen"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (datamaskin-vindusvisning)"</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index 2c7be99..2d6ab7d 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"नयाँ विन्डो"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"विन्डोहरू व्यवस्थापन गर्नुहोस्"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"एस्पेक्ट रेसियो परिवर्तन गर्नुहोस्"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"बन्द गर्नुहोस्"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"मेनु बन्द गर्नुहोस्"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (डेस्कटप विन्डोइङ)"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 099f875..23f251f 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Nieuw venster"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Vensters beheren"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Beeldverhouding wijzigen"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Sluiten"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Menu sluiten"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (desktopvensterfunctie)"</string>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index 19cc8ced..8b7f0c7 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -100,8 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ଏହାର ସମାଧାନ ହୋଇନାହିଁ?\nଫେରିଯିବା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"କ୍ୟାମେରାରେ କିଛି ସମସ୍ୟା ନାହିଁ? ଖାରଜ କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"ଆପ ମେନୁ ଏଠାରେ ମିଳିପାରିବ"</string>
- <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) -->
- <skip />
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"ଏକାଠି ଏକାଧିକ ଆପ୍ସ ଖୋଲିବାକୁ ଡେସ୍କଟପ ୱିଣ୍ଡୋଇଂରେ ଏଣ୍ଟର କରନ୍ତୁ"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"ଆପ ମେନୁରୁ ଯେ କୌଣସି ସମୟରେ ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନକୁ ଫେରନ୍ତୁ"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"ଦେଖନ୍ତୁ ଏବଂ ଆହୁରି ଅନେକ କିଛି କରନ୍ତୁ"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ପାଇଁ ଅନ୍ୟ ଏକ ଆପକୁ ଡ୍ରାଗ କରନ୍ତୁ"</string>
@@ -122,8 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"ଆପର ହେଣ୍ଡେଲ"</string>
<string name="app_icon_text" msgid="2823268023931811747">"ଆପ ଆଇକନ"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"ପୂର୍ଣ୍ଣସ୍କ୍ରିନ"</string>
- <!-- no translation found for desktop_text (9058641752519570266) -->
- <skip />
+ <string name="desktop_text" msgid="9058641752519570266">"ଡେସ୍କଟପ ୱିଣ୍ଡୋଇଂ"</string>
<string name="split_screen_text" msgid="1396336058129570886">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ"</string>
<string name="more_button_text" msgid="3655388105592893530">"ଅଧିକ"</string>
<string name="float_button_text" msgid="9221657008391364581">"ଫ୍ଲୋଟ"</string>
@@ -134,10 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"ନୂଆ ୱିଣ୍ଡୋ"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ୱିଣ୍ଡୋଗୁଡ଼ିକୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ଚଉଡ଼ା ଓ ଉଚ୍ଚତାର ଅନୁପାତ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"ମେନୁ ବନ୍ଦ କରନ୍ତୁ"</string>
- <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) -->
- <skip />
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ଡେସ୍କଟପ ୱିଣ୍ଡୋଇଂ)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ସ୍କ୍ରିନକୁ ବଡ଼ କରନ୍ତୁ"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ରିସାଇଜ କରନ୍ତୁ"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ଆପକୁ ଏଠାକୁ ମୁଭ କରାଯାଇପାରିବ ନାହିଁ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index 50e3cd6..e074a07 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"ਨਵੀਂ ਵਿੰਡੋ"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ਵਿੰਡੋਆਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ਆਕਾਰ ਅਨੁਪਾਤ ਬਦਲੋ"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"ਬੰਦ ਕਰੋ"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"ਮੀਨੂ ਬੰਦ ਕਰੋ"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ਡੈਸਕਟਾਪ ਵਿੰਡੋ)"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index 58a691f..861d9472 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -100,8 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Naprawa się nie udała?\nKliknij, aby cofnąć"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Brak problemów z aparatem? Kliknij, aby zamknąć"</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Tu znajdziesz menu aplikacji"</string>
- <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) -->
- <skip />
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"Aby otworzyć kilka aplikacji jednocześnie, przejdź do trybu okien na pulpicie"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Z menu aplikacji w każdej chwili możesz wrócić do pełnego ekranu"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Zobacz i zrób więcej"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Aby podzielić ekran, przeciągnij drugą aplikację"</string>
@@ -122,8 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"Uchwyt aplikacji"</string>
<string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacji"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Pełny ekran"</string>
- <!-- no translation found for desktop_text (9058641752519570266) -->
- <skip />
+ <string name="desktop_text" msgid="9058641752519570266">"Tryb okien na pulpicie"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Podzielony ekran"</string>
<string name="more_button_text" msgid="3655388105592893530">"Więcej"</string>
<string name="float_button_text" msgid="9221657008391364581">"Pływające"</string>
@@ -134,10 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"Nowe okno"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Zarządzaj oknami"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Zmień format obrazu"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Zamknij"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Zamknij menu"</string>
- <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) -->
- <skip />
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (tryb okien na pulpicie)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksymalizuj ekran"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Zmień rozmiar"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Nie można przenieść aplikacji tutaj"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 2d9bc2b..53db421 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -100,8 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"O menu do app está aqui"</string>
- <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) -->
- <skip />
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"Abra vários apps ao mesmo tempo usando o modo janela para computador"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Volte para a tela cheia a qualquer momento no menu do app"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arraste outro app para dividir a tela"</string>
@@ -122,8 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"Identificador do app"</string>
<string name="app_icon_text" msgid="2823268023931811747">"Ícone do app"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Tela cheia"</string>
- <!-- no translation found for desktop_text (9058641752519570266) -->
- <skip />
+ <string name="desktop_text" msgid="9058641752519570266">"Modo janela para computador"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Tela dividida"</string>
<string name="more_button_text" msgid="3655388105592893530">"Mais"</string>
<string name="float_button_text" msgid="9221657008391364581">"Ponto flutuante"</string>
@@ -134,10 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"Nova janela"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gerenciar janelas"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Mudar a proporção"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Fechar"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>
- <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) -->
- <skip />
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (modo janela para computador)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ampliar tela"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionar"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Não é possível mover o app para cá"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index d553518..5a4da3c 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Nova janela"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gerir janelas"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Alterar formato"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Fechar"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (janelas de computador)"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 2d9bc2b..53db421 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -100,8 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"O menu do app está aqui"</string>
- <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) -->
- <skip />
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"Abra vários apps ao mesmo tempo usando o modo janela para computador"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"Volte para a tela cheia a qualquer momento no menu do app"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Veja e faça mais"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Arraste outro app para dividir a tela"</string>
@@ -122,8 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"Identificador do app"</string>
<string name="app_icon_text" msgid="2823268023931811747">"Ícone do app"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Tela cheia"</string>
- <!-- no translation found for desktop_text (9058641752519570266) -->
- <skip />
+ <string name="desktop_text" msgid="9058641752519570266">"Modo janela para computador"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Tela dividida"</string>
<string name="more_button_text" msgid="3655388105592893530">"Mais"</string>
<string name="float_button_text" msgid="9221657008391364581">"Ponto flutuante"</string>
@@ -134,10 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"Nova janela"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gerenciar janelas"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Mudar a proporção"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Fechar"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>
- <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) -->
- <skip />
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (modo janela para computador)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ampliar tela"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionar"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Não é possível mover o app para cá"</string>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 286443c..1590400 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Fereastră nouă"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Gestionează ferestrele"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Schimbă raportul de dimensiuni"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Închide"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Închide meniul"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ferestre pe desktop)"</string>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index 472a239..bd7fa6e 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Новое окно"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Управление окнами"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Изменить соотношение сторон"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Закрыть"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Закрыть меню"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (режим компьютерных окон)"</string>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index 6c91955..7a72f99 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"නව කවුළුව"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"කවුළු කළමනාකරණය කරන්න"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"දර්ශන අනුපාතය වෙනස් කරන්න"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"වසන්න"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"මෙනුව වසන්න"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ඩෙස්ක්ටොප් කවුළුකරණය)"</string>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index 08404d0..f0f3e50 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Nové okno"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Spravovať okná"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Zmeniť pomer strán"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Zavrieť"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Zavrieť ponuku"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (windowing na pracovnej ploche)"</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index deed0e0..d86cf6b 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Novo okno"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Upravljanje oken"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Sprememba razmerja stranic"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Zapri"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Zapri meni"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (namizni način prikaza več oken hkrati)"</string>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index c6b8c6d..ca4fe6fd3 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Dritare e re"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Menaxho dritaret"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Ndrysho raportin e pamjes"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Mbyll"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Mbyll menynë"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ndërfaqja me dritare në desktop)"</string>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index 3fe25f9..58d9398 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Нови прозор"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Управљајте прозорима"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промени размеру"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Затворите"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Затворите мени"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (прозорски приказ за рачунаре)"</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 404bdaf..5231a67 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Nytt fönster"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Hantera fönster"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Ändra bildformat"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Stäng"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Stäng menyn"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (fönsterstapling)"</string>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 3bd7988..9c3c107 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Dirisha Jipya"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Dhibiti Windows"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Badilisha uwiano"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Funga"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Funga Menyu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Kupanga madirisha ya kompyuta ya mezani)"</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 12780df..811fce3 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"புதிய சாளரம்"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"சாளரங்களை நிர்வகிக்கலாம்"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"தோற்ற விகிதத்தை மாற்று"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"மூடும்"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"மெனுவை மூடும்"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (டெஸ்க்டாப் சாளரமாக்குதல்)"</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 2044fe7..7a809f4 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"కొత్త విండో"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"విండోలను మేనేజ్ చేయండి"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ఆకార నిష్పత్తిని మార్చండి"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"మూసివేయండి"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"మెనూను మూసివేయండి"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (డెస్క్టాప్ వీక్షణ)"</string>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 60632ad..6699635 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -100,8 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"หากไม่ได้แก้ไข\nแตะเพื่อเปลี่ยนกลับ"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"หากไม่พบปัญหากับกล้อง แตะเพื่อปิด"</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"ดูเมนูแอปที่นี่ได้"</string>
- <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) -->
- <skip />
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"เข้าสู่หน้าต่างเดสก์ท็อปเพื่อเปิดหลายแอปพร้อมกัน"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"กลับไปที่โหมดเต็มหน้าจอได้ทุกเมื่อจากเมนูแอป"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"รับชมและทำสิ่งต่างๆ ได้มากขึ้น"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"ลากไปไว้ในแอปอื่นเพื่อแยกหน้าจอ"</string>
@@ -122,8 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"แฮนเดิลแอป"</string>
<string name="app_icon_text" msgid="2823268023931811747">"ไอคอนแอป"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"เต็มหน้าจอ"</string>
- <!-- no translation found for desktop_text (9058641752519570266) -->
- <skip />
+ <string name="desktop_text" msgid="9058641752519570266">"หน้าต่างเดสก์ท็อป"</string>
<string name="split_screen_text" msgid="1396336058129570886">"แยกหน้าจอ"</string>
<string name="more_button_text" msgid="3655388105592893530">"เพิ่มเติม"</string>
<string name="float_button_text" msgid="9221657008391364581">"ล่องลอย"</string>
@@ -134,10 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"หน้าต่างใหม่"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"จัดการหน้าต่าง"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"เปลี่ยนสัดส่วนการแสดงผล"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"ปิด"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"ปิดเมนู"</string>
- <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) -->
- <skip />
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (หน้าต่างเดสก์ท็อป)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ขยายหน้าจอให้ใหญ่สุด"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ปรับขนาด"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ย้ายแอปมาที่นี่ไม่ได้"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 586d655..82c085b 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Bagong Window"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Pamahalaan ang Mga Window"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Baguhin ang aspect ratio"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Isara"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Isara ang Menu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Desktop windowing)"</string>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index 9605acf..4d6775a 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Yeni Pencere"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Pencereleri yönet"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"En boy oranını değiştir"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Kapat"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Menüyü kapat"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (masaüstü pencereleme)"</string>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index 54af067..4b2aad0 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -100,8 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблему не вирішено?\nНатисніть, щоб скасувати зміни"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немає проблем із камерою? Торкніться, щоб закрити."</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"Тут ви знайдете меню додатка"</string>
- <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) -->
- <skip />
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"Щоб відкрити кілька додатків одночасно, перейдіть у режим вікон робочого стола"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"З меню додатка можна будь-коли повернутися в повноекранний режим"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Більше простору та можливостей"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Щоб перейти в режим розділення екрана, перетягніть сюди інший додаток"</string>
@@ -122,8 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"Дескриптор додатка"</string>
<string name="app_icon_text" msgid="2823268023931811747">"Значок додатка"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"На весь екран"</string>
- <!-- no translation found for desktop_text (9058641752519570266) -->
- <skip />
+ <string name="desktop_text" msgid="9058641752519570266">"Режим вікон робочого стола"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Розділити екран"</string>
<string name="more_button_text" msgid="3655388105592893530">"Більше"</string>
<string name="float_button_text" msgid="9221657008391364581">"Плаваюче вікно"</string>
@@ -134,10 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"Нове вікно"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Керувати вікнами"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Змінити формат"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Закрити"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Закрити меню"</string>
- <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) -->
- <skip />
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (режим вікон робочого стола)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Розгорнути екран"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Змінити розмір"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Сюди не можна перемістити додаток"</string>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 9614ce9..f9972d2 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"نئی ونڈو"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ونڈوز کا نظم کریں"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"تناسبی شرح کو تبدیل کریں"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"بند کریں"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"مینیو بند کریں"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ڈیسک ٹاپ ونڈوئنگ)"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 6025467..231cb73 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Yangi oyna"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Oynalarni boshqarish"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Tomonlar nisbatini oʻzgartirish"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Yopish"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Menyuni yopish"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Desktop rejimidagi oynalar)"</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index 4c394b2..88ef071 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -121,7 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"Ô điều khiển ứng dụng"</string>
<string name="app_icon_text" msgid="2823268023931811747">"Biểu tượng ứng dụng"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"Toàn màn hình"</string>
- <string name="desktop_text" msgid="9058641752519570266">"Cửa sổ trên máy tính"</string>
+ <string name="desktop_text" msgid="9058641752519570266">"Chế độ cửa sổ trên máy tính"</string>
<string name="split_screen_text" msgid="1396336058129570886">"Chia đôi màn hình"</string>
<string name="more_button_text" msgid="3655388105592893530">"Tuỳ chọn khác"</string>
<string name="float_button_text" msgid="9221657008391364581">"Nổi"</string>
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Cửa sổ mới"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Quản lý cửa sổ"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Thay đổi tỷ lệ khung hình"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Đóng"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Đóng trình đơn"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Chế độ cửa sổ trên máy tính)"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index b29711d..a07767d 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -100,8 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"没有解决此问题?\n点按即可恢复"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相机没有问题?点按即可忽略。"</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"您可以在此处找到应用菜单"</string>
- <!-- no translation found for windowing_desktop_mode_image_button_education_tooltip (7171915734817051666) -->
- <skip />
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"进入桌面设备窗口化模式可同时打开多个应用"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"随时从应用菜单返回全屏模式"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"查看和处理更多任务"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"拖入另一个应用,即可使用分屏模式"</string>
@@ -122,8 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"应用手柄"</string>
<string name="app_icon_text" msgid="2823268023931811747">"应用图标"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"全屏"</string>
- <!-- no translation found for desktop_text (9058641752519570266) -->
- <skip />
+ <string name="desktop_text" msgid="9058641752519570266">"桌面设备窗口化"</string>
<string name="split_screen_text" msgid="1396336058129570886">"分屏"</string>
<string name="more_button_text" msgid="3655388105592893530">"更多"</string>
<string name="float_button_text" msgid="9221657008391364581">"悬浮"</string>
@@ -134,10 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"新窗口"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"管理窗口"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"更改宽高比"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"关闭"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"关闭菜单"</string>
- <!-- no translation found for desktop_mode_app_header_chip_text (7617377295944971651) -->
- <skip />
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g>(桌面设备窗口化)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"最大化屏幕"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"调整大小"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"无法将应用移至此处"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index fda5c74..103ee60 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -100,7 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未能修正問題?\n輕按即可還原"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機冇問題?㩒一下就可以即可閂咗佢。"</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"你可在這裡找到應用程式選單"</string>
- <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"進入電腦分割視窗模式可同時開啟多個應用程式"</string>
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"進入桌面電腦視窗模式以同時開啟多個應用程式"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"你可隨時從應用程式選單返回全螢幕"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"瀏覽更多內容及執行更多操作"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"拖入另一個應用程式即可分割螢幕"</string>
@@ -121,7 +121,7 @@
<string name="handle_text" msgid="4419667835599523257">"應用程式控點"</string>
<string name="app_icon_text" msgid="2823268023931811747">"應用程式圖示"</string>
<string name="fullscreen_text" msgid="1162316685217676079">"全螢幕"</string>
- <string name="desktop_text" msgid="9058641752519570266">"電腦分割視窗"</string>
+ <string name="desktop_text" msgid="9058641752519570266">"桌面電腦視窗模式"</string>
<string name="split_screen_text" msgid="1396336058129570886">"分割螢幕"</string>
<string name="more_button_text" msgid="3655388105592893530">"更多"</string>
<string name="float_button_text" msgid="9221657008391364581">"浮動"</string>
@@ -132,9 +132,11 @@
<string name="new_window_text" msgid="6318648868380652280">"新視窗"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"管理視窗"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"變更長寬比"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"關閉"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string>
- <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (電腦分割視窗)"</string>
+ <string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (桌面電腦視窗模式)"</string>
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"畫面最大化"</string>
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"調整大小"</string>
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"應用程式無法移至這裡"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index e83c647..a3d81fc 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -100,7 +100,7 @@
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未修正問題嗎?\n輕觸即可還原"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機沒問題嗎?輕觸即可關閉。"</string>
<string name="windowing_app_handle_education_tooltip" msgid="2929643449849791854">"你可以在這裡查看應用程式選單"</string>
- <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"進入電腦分割視窗模式可同時開啟多個應用程式"</string>
+ <string name="windowing_desktop_mode_image_button_education_tooltip" msgid="7171915734817051666">"進入電腦分割視窗模式後,可同時開啟多個應用程式"</string>
<string name="windowing_desktop_mode_exit_education_tooltip" msgid="5225660258192054132">"你隨時可以從應用程式選單返回全螢幕模式"</string>
<string name="letterbox_education_dialog_title" msgid="7739895354143295358">"瀏覽更多內容及執行更多操作"</string>
<string name="letterbox_education_split_screen_text" msgid="449233070804658627">"拖進另一個應用程式即可使用分割畫面模式"</string>
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"新視窗"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"管理視窗"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"變更顯示比例"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"關閉"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (電腦分割視窗)"</string>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index 4d658f2..81d9200 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -132,6 +132,8 @@
<string name="new_window_text" msgid="6318648868380652280">"Iwindi Elisha"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Phatha Amawindi"</string>
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Shintsha ukubukeka kwesilinganiselo"</string>
+ <!-- no translation found for handle_menu_restart_text (3907767216238298098) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Vala"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Vala Imenyu"</string>
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Ukwenziwa kwamawindi amaningi kwedeskithophu)"</string>
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index 8d18f95..5732fc9 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -68,8 +68,6 @@
<color name="desktop_mode_caption_button_on_hover_light">#11000000</color>
<color name="desktop_mode_caption_button_on_hover_dark">#11FFFFFF</color>
<color name="desktop_mode_caption_button">#00000000</color>
- <color name="tiling_divider_background_light">#C9C7B6</color>
- <color name="tiling_divider_background_dark">#4A4739</color>
<color name="tiling_handle_background_light">#000000</color>
<color name="tiling_handle_background_dark">#FFFFFF</color>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 733f3bb..ca18c97 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -304,6 +304,8 @@
<dimen name="bubble_transform_area_width">140dp</dimen>
<!-- Width of the box at the corner of the screen where drag leads to app moving to bubble -->
<dimen name="bubble_transform_area_height">140dp</dimen>
+ <!-- How much elevation a bubble ui needs when dragged, must be above drop target & dismiss. -->
+ <dimen name="dragged_bubble_elevation">3dp</dimen>
<!-- Bottom and end margin for compat buttons. -->
<dimen name="compat_button_margin">24dp</dimen>
diff --git a/libs/WindowManager/Shell/shared/res/values/dimen.xml b/libs/WindowManager/Shell/shared/res/values/dimen.xml
index 3b504cf..74b6023 100644
--- a/libs/WindowManager/Shell/shared/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/shared/res/values/dimen.xml
@@ -39,9 +39,9 @@
<dimen name="drag_zone_v_split_from_expanded_view_height_fold_short">100dp</dimen>
<!-- Bubble drop target dimensions -->
- <dimen name="drop_target_elevation">1dp</dimen>
+ <dimen name="drop_target_elevation">2dp</dimen>
<dimen name="drop_target_radius">28dp</dimen>
- <dimen name="drop_target_stroke">1dp</dimen>
+ <dimen name="drop_target_stroke">2dp</dimen>
<dimen name="drop_target_full_screen_padding">20dp</dimen>
<dimen name="drop_target_desktop_window_padding_small">100dp</dimen>
<dimen name="drop_target_desktop_window_padding_large">130dp</dimen>
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/IHomeTransitionListener.aidl b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/IHomeTransitionListener.aidl
index 8481c44..8dcda53 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/IHomeTransitionListener.aidl
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/IHomeTransitionListener.aidl
@@ -18,6 +18,7 @@
import android.window.RemoteTransition;
import android.window.TransitionFilter;
+import android.view.InsetsState;
/**
* Listener interface that Launcher attaches to SystemUI to get home activity transition callbacks
@@ -29,5 +30,10 @@
* Called when a transition changes the visibility of the home activity on the default display.
*/
void onHomeVisibilityChanged(in boolean isVisible);
+
+ /**
+ * Called when the insets at display-level change.
+ */
+ void onDisplayInsetsChanged(in InsetsState insets);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ContextUtils.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/ContextUtils.kt
similarity index 96%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ContextUtils.kt
rename to libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/ContextUtils.kt
index 0b36f45..27db529 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ContextUtils.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/ContextUtils.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.bubbles
+package com.android.wm.shell.shared.bubbles
import android.content.Context
import android.view.View
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetView.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetView.kt
index 7327731..df101fe 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetView.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetView.kt
@@ -30,15 +30,15 @@
class DropTargetView(context: Context) : View(context) {
private val rectPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
- color = context.getColor(com.android.internal.R.color.materialColorPrimaryContainer)
+ color = context.getColor(com.android.internal.R.color.materialColorPrimaryFixed)
style = Paint.Style.FILL
alpha = (0.35f * 255).toInt()
}
private val strokePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
- color = context.getColor(com.android.internal.R.color.materialColorPrimaryContainer)
+ color = context.getColor(com.android.internal.R.color.materialColorPrimaryFixed)
style = Paint.Style.STROKE
- strokeWidth = 1.dpToPx()
+ strokeWidth = 2.dpToPx()
}
private val cornerRadius = 28.dpToPx()
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
index e5a4cd0..a9224b0 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
@@ -451,6 +451,6 @@
pw.println(maxTaskLimitHandle == null ? "null" : maxTaskLimitHandle.getInt(/* def= */ -1));
pw.print(innerPrefix); pw.print("showAppHandle config override=");
- pw.print(overridesShowAppHandle(context));
+ pw.println(overridesShowAppHandle(context));
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java
index 8e78686..8e3dc4c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java
@@ -66,7 +66,7 @@
* The maximum of stretching applied to any surface during interpolation (since the animation
* is a combination of stretching/cropping/fading).
*/
- private static final float SCALE_FACTOR = 0.7f;
+ private static final float DEFAULT_SCALE_FACTOR = 0.7f;
/**
* Since this animation is made of several sub-animations, we want to pre-arrange the
@@ -82,13 +82,27 @@
*/
private static final int ANIMATION_RESOLUTION = 1000;
+ /**
+ * Initialize a size-change animation from start to end bounds
+ */
public SizeChangeAnimation(Rect startBounds, Rect endBounds) {
- this(startBounds, endBounds, 1f);
+ this(startBounds, endBounds, 1f, DEFAULT_SCALE_FACTOR);
}
- public SizeChangeAnimation(Rect startBounds, Rect endBounds, float initialScale) {
- mAnimation = buildContainerAnimation(startBounds, endBounds, initialScale);
- mSnapshotAnim = buildSnapshotAnimation(startBounds, endBounds);
+ /**
+ * Initialize a size-change animation from start to end bounds.
+ * <p>
+ * Allows specifying the initial scale factor, {@code initialScale}, that is applied to the
+ * start bounds. This can be useful for example when a task is scaled down when the size change
+ * animation starts.
+ * <p>
+ * By default the max scale applied to any surface is {@link #DEFAULT_SCALE_FACTOR}. Use
+ * {@code scaleFactor} to override it.
+ */
+ public SizeChangeAnimation(Rect startBounds, Rect endBounds, float initialScale,
+ float scaleFactor) {
+ mAnimation = buildContainerAnimation(startBounds, endBounds, initialScale, scaleFactor);
+ mSnapshotAnim = buildSnapshotAnimation(startBounds, endBounds, scaleFactor);
}
/**
@@ -172,15 +186,15 @@
/** Animation for the whole container (snapshot is inside this container). */
private static AnimationSet buildContainerAnimation(Rect startBounds, Rect endBounds,
- float initialScale) {
+ float initialScale, float scaleFactor) {
final long duration = ANIMATION_RESOLUTION;
boolean growing = endBounds.width() - startBounds.width()
+ endBounds.height() - startBounds.height() >= 0;
- long scalePeriod = (long) (duration * SCALE_FACTOR);
- float startScaleX = SCALE_FACTOR * ((float) startBounds.width()) / endBounds.width()
- + (1.f - SCALE_FACTOR);
- float startScaleY = SCALE_FACTOR * ((float) startBounds.height()) / endBounds.height()
- + (1.f - SCALE_FACTOR);
+ long scalePeriod = (long) (duration * scaleFactor);
+ float startScaleX = scaleFactor * ((float) startBounds.width()) / endBounds.width()
+ + (1.f - scaleFactor);
+ float startScaleY = scaleFactor * ((float) startBounds.height()) / endBounds.height()
+ + (1.f - scaleFactor);
final AnimationSet animSet = new AnimationSet(true);
final Animation scaleAnim = new ScaleAnimation(startScaleX, 1, startScaleY, 1);
@@ -218,15 +232,16 @@
}
/** The snapshot surface is assumed to be a child of the container surface. */
- private static AnimationSet buildSnapshotAnimation(Rect startBounds, Rect endBounds) {
+ private static AnimationSet buildSnapshotAnimation(Rect startBounds, Rect endBounds,
+ float scaleFactor) {
final long duration = ANIMATION_RESOLUTION;
boolean growing = endBounds.width() - startBounds.width()
+ endBounds.height() - startBounds.height() >= 0;
- long scalePeriod = (long) (duration * SCALE_FACTOR);
- float endScaleX = 1.f / (SCALE_FACTOR * ((float) startBounds.width()) / endBounds.width()
- + (1.f - SCALE_FACTOR));
- float endScaleY = 1.f / (SCALE_FACTOR * ((float) startBounds.height()) / endBounds.height()
- + (1.f - SCALE_FACTOR));
+ long scalePeriod = (long) (duration * scaleFactor);
+ float endScaleX = 1.f / (scaleFactor * ((float) startBounds.width()) / endBounds.width()
+ + (1.f - scaleFactor));
+ float endScaleY = 1.f / (scaleFactor * ((float) startBounds.height()) / endBounds.height()
+ + (1.f - scaleFactor));
AnimationSet snapAnimSet = new AnimationSet(true);
// Animation for the "old-state" snapshot that is atop the task.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationBackground.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationBackground.java
index 26f7b36..98cae5a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationBackground.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationBackground.java
@@ -19,6 +19,8 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+import static com.android.window.flags.Flags.enableMultidisplayTrackpadBackGesture;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Color;
@@ -59,9 +61,9 @@
* @param statusbarHeight The height of the statusbar (in px).
*/
public void ensureBackground(Rect startRect, int color,
- @NonNull SurfaceControl.Transaction transaction, int statusbarHeight) {
+ @NonNull SurfaceControl.Transaction transaction, int statusbarHeight, int displayId) {
ensureBackground(startRect, color, transaction, statusbarHeight,
- null /* cropBounds */, 0 /* cornerRadius */);
+ null /* cropBounds */, 0 /* cornerRadius */, displayId);
}
/**
@@ -76,7 +78,7 @@
*/
public void ensureBackground(Rect startRect, int color,
@NonNull SurfaceControl.Transaction transaction, int statusbarHeight,
- @Nullable Rect cropBounds, float cornerRadius) {
+ @Nullable Rect cropBounds, float cornerRadius, int displayId) {
if (mBackgroundSurface != null) {
return;
}
@@ -91,7 +93,11 @@
.setCallsite("BackAnimationBackground")
.setColorLayer();
- mRootTaskDisplayAreaOrganizer.attachToDisplayArea(DEFAULT_DISPLAY, colorLayerBuilder);
+ if (enableMultidisplayTrackpadBackGesture()) {
+ mRootTaskDisplayAreaOrganizer.attachToDisplayArea(displayId, colorLayerBuilder);
+ } else {
+ mRootTaskDisplayAreaOrganizer.attachToDisplayArea(DEFAULT_DISPLAY, colorLayerBuilder);
+ }
mBackgroundSurface = colorLayerBuilder.build();
transaction.setColor(mBackgroundSurface, colorComponents)
.setLayer(mBackgroundSurface, BACKGROUND_LAYER)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 81cf031..746632f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -286,6 +286,7 @@
this::createExternalInterface, this);
mShellCommandHandler.addDumpCallback(this::dump, this);
mShellController.addConfigurationChangeListener(this);
+ registerBackGestureDelegate();
}
public BackAnimation getBackAnimationImpl() {
@@ -1144,6 +1145,32 @@
mBackAnimationAdapter = new BackAnimationAdapter(runner);
}
+ private void registerBackGestureDelegate() {
+ if (!Flags.delegateBackGestureToShell()) {
+ return;
+ }
+ final RemoteCallback requestBackMonitor = new RemoteCallback(
+ new RemoteCallback.OnResultListener() {
+ @Override
+ public void onResult(@Nullable Bundle result) {
+ mShellExecutor.execute(() -> {
+ if (mBackGestureStarted) {
+ Log.w(TAG, "Back gesture is running, ignore request");
+ return;
+ }
+ onMotionEvent(0, 0, KeyEvent.ACTION_DOWN, EDGE_NONE);
+ setTriggerBack(true);
+ onMotionEvent(0, 0, KeyEvent.ACTION_UP, EDGE_NONE);
+ });
+ }
+ });
+ try {
+ mActivityTaskManager.registerBackGestureDelegate(requestBackMonitor);
+ } catch (RemoteException remoteException) {
+ Log.w(TAG, "Failed register back gesture request ", remoteException);
+ }
+ }
+
/**
* Description of current BackAnimationController state.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
index 7e5a82e..6c41c97 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
@@ -52,6 +52,7 @@
import com.android.internal.policy.ScreenDecorationsUtils
import com.android.internal.policy.SystemBarUtils
import com.android.internal.protolog.ProtoLog
+import com.android.window.flags.Flags.enableMultidisplayTrackpadBackGesture
import com.android.window.flags.Flags.predictiveBackTimestampApi
import com.android.wm.shell.R
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
@@ -210,7 +211,8 @@
statusbarHeight,
if (closingTarget!!.windowConfiguration.tasksAreFloating())
closingTarget!!.localBounds else null,
- cornerRadius
+ cornerRadius,
+ closingTarget!!.taskInfo.getDisplayId()
)
ensureScrimLayer()
if (isLetterboxed && enteringHasSameLetterbox) {
@@ -409,7 +411,12 @@
.setOpaque(false)
.setHidden(false)
- rootTaskDisplayAreaOrganizer.attachToDisplayArea(Display.DEFAULT_DISPLAY, scrimBuilder)
+ if (enableMultidisplayTrackpadBackGesture()) {
+ rootTaskDisplayAreaOrganizer.attachToDisplayArea(
+ closingTarget!!.taskInfo.getDisplayId(), scrimBuilder)
+ } else {
+ rootTaskDisplayAreaOrganizer.attachToDisplayArea(Display.DEFAULT_DISPLAY, scrimBuilder)
+ }
scrimLayer = scrimBuilder.build()
val colorComponents = floatArrayOf(0f, 0f, 0f)
maxScrimAlpha = if (isDarkTheme) MAX_SCRIM_ALPHA_DARK else MAX_SCRIM_ALPHA_LIGHT
@@ -473,7 +480,13 @@
.setOpaque(true)
.setHidden(false)
- rootTaskDisplayAreaOrganizer.attachToDisplayArea(Display.DEFAULT_DISPLAY, letterboxBuilder)
+ if (enableMultidisplayTrackpadBackGesture()) {
+ rootTaskDisplayAreaOrganizer.attachToDisplayArea(
+ closingTarget!!.taskInfo.getDisplayId(), letterboxBuilder)
+ } else {
+ rootTaskDisplayAreaOrganizer.attachToDisplayArea(
+ Display.DEFAULT_DISPLAY, letterboxBuilder)
+ }
val layer = letterboxBuilder.build()
val colorComponents =
floatArrayOf(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
index f48b3ff..f5b0e35 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
@@ -175,7 +175,8 @@
// Draw background.
mBackground.ensureBackground(mClosingTarget.windowConfiguration.getBounds(),
- BACKGROUNDCOLOR, mTransaction, mStatusbarHeight);
+ BACKGROUNDCOLOR, mTransaction, mStatusbarHeight,
+ mClosingTarget.taskInfo.getDisplayId());
mInterWindowMargin = mContext.getResources()
.getDimension(R.dimen.cross_task_back_inter_window_margin);
mVerticalMargin = mContext.getResources()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 81eff6f..6a7b5cc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -81,6 +81,7 @@
import android.view.WindowManager;
import android.window.ScreenCapture;
import android.window.ScreenCapture.SynchronousScreenCaptureListener;
+import android.window.TransitionInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -120,6 +121,7 @@
import com.android.wm.shell.shared.bubbles.BubbleBarLocation.UpdateSource;
import com.android.wm.shell.shared.bubbles.BubbleBarUpdate;
import com.android.wm.shell.shared.bubbles.BubbleDropTargetBoundsProvider;
+import com.android.wm.shell.shared.bubbles.ContextUtils;
import com.android.wm.shell.shared.bubbles.DeviceConfig;
import com.android.wm.shell.shared.draganddrop.DragAndDropConstants;
import com.android.wm.shell.sysui.ConfigurationChangeListener;
@@ -155,7 +157,7 @@
*/
public class BubbleController implements ConfigurationChangeListener,
RemoteCallable<BubbleController>, Bubbles.SysuiProxy.Provider,
- BubbleBarDragListener {
+ BubbleBarDragListener, BubbleTaskUnfoldTransitionMerger {
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleController" : TAG_BUBBLES;
@@ -2174,6 +2176,32 @@
});
}
+ @Override
+ public boolean mergeTaskWithUnfold(@NonNull ActivityManager.RunningTaskInfo taskInfo,
+ @NonNull TransitionInfo.Change change,
+ @NonNull SurfaceControl.Transaction startT,
+ @NonNull SurfaceControl.Transaction finishT) {
+ if (!mBubbleTransitions.mTaskViewTransitions.isTaskViewTask(taskInfo)) {
+ // if this task isn't managed by bubble transitions just bail.
+ return false;
+ }
+ if (isShowingAsBubbleBar()) {
+ // if bubble bar is enabled, the task view will switch to a new surface on unfold, so we
+ // should not merge the transition.
+ return false;
+ }
+
+ boolean merged = mBubbleTransitions.mTaskViewTransitions.updateBoundsForUnfold(
+ change.getEndAbsBounds(), startT, finishT, change.getTaskInfo(), change.getLeash());
+ if (merged) {
+ BubbleViewProvider selectedBubble = mBubbleData.getSelectedBubble();
+ if (selectedBubble != null && selectedBubble.getExpandedView() != null) {
+ selectedBubble.getExpandedView().onContainerClipUpdate();
+ }
+ }
+ return merged;
+ }
+
/** When bubbles are floating, this will be used to notify the floating views. */
private final BubbleViewCallback mBubbleStackViewCallback = new BubbleViewCallback() {
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 290ef16..ac83935 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -843,7 +843,8 @@
onContainerClipUpdate();
}
- private void onContainerClipUpdate() {
+ /** Updates the clip bounds. */
+ public void onContainerClipUpdate() {
if (mTopClip == 0 && mBottomClip == 0 && mRightClip == 0 && mLeftClip == 0) {
if (mIsClipping) {
mIsClipping = false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 166f172..7ae9de8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -94,6 +94,7 @@
import com.android.wm.shell.shared.animation.Interpolators;
import com.android.wm.shell.shared.animation.PhysicsAnimator;
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
+import com.android.wm.shell.shared.bubbles.ContextUtils;
import com.android.wm.shell.shared.bubbles.DeviceConfig;
import com.android.wm.shell.shared.bubbles.DismissView;
import com.android.wm.shell.shared.bubbles.RelativeTouchListener;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskUnfoldTransitionMerger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskUnfoldTransitionMerger.kt
new file mode 100644
index 0000000..13fabc8
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskUnfoldTransitionMerger.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.bubbles
+
+import android.app.ActivityManager
+import android.view.SurfaceControl
+import android.window.TransitionInfo
+
+/** Merges a bubble task transition with the unfold transition. */
+interface BubbleTaskUnfoldTransitionMerger {
+
+ /** Attempts to merge the transition. Returns `true` if the change was merged. */
+ fun mergeTaskWithUnfold(
+ taskInfo: ActivityManager.RunningTaskInfo,
+ change: TransitionInfo.Change,
+ startT: SurfaceControl.Transaction,
+ finishT: SurfaceControl.Transaction
+ ): Boolean
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index fa22a39..b89bfd5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -596,11 +596,11 @@
final Size size = getExpandedViewSize();
Point position = getExpandedViewRestPosition(size);
- final SizeChangeAnimation sca =
- new SizeChangeAnimation(
- new Rect(origBounds.left - position.x, origBounds.top - position.y,
- origBounds.right - position.x, origBounds.bottom - position.y),
- new Rect(0, 0, size.getWidth(), size.getHeight()), origScale);
+ Rect startBounds = new Rect(origBounds.left - position.x, origBounds.top - position.y,
+ origBounds.right - position.x, origBounds.bottom - position.y);
+ Rect endBounds = new Rect(0, 0, size.getWidth(), size.getHeight());
+ final SizeChangeAnimation sca = new SizeChangeAnimation(startBounds, endBounds,
+ origScale, /* scaleFactor= */ 1f);
sca.initialize(bbev, taskLeash, snapshot, startT);
Animator a = sca.buildViewAnimator(bbev, tvSf, snapshot, /* onFinish */ (va) -> {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
index 3543556..44d859df 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
@@ -17,9 +17,11 @@
package com.android.wm.shell.bubbles.bar
import android.annotation.SuppressLint
+import android.content.Context
import android.view.MotionEvent
import android.view.View
import androidx.annotation.VisibleForTesting
+import com.android.wm.shell.R
import com.android.wm.shell.bubbles.BubblePositioner
import com.android.wm.shell.shared.bubbles.BubbleBarLocation
import com.android.wm.shell.shared.bubbles.DismissView
@@ -32,6 +34,7 @@
/** Controller for handling drag interactions with [BubbleBarExpandedView] */
@SuppressLint("ClickableViewAccessibility")
class BubbleBarExpandedViewDragController(
+ private val context: Context,
private val expandedView: BubbleBarExpandedView,
private val dismissView: DismissView,
private val animationHelper: BubbleBarAnimationHelper,
@@ -54,6 +57,8 @@
MagnetizedObject.magnetizeView(expandedView)
private val magnetizedDismissTarget: MagnetizedObject.MagneticTarget
+ private val draggedBubbleElevation: Float
+
init {
magnetizedExpandedView.magnetListener = MagnetListener()
magnetizedExpandedView.animateStuckToTarget =
@@ -70,6 +75,8 @@
MagnetizedObject.MagneticTarget(dismissView.circle, dismissView.circle.width)
magnetizedExpandedView.addTarget(magnetizedDismissTarget)
+ draggedBubbleElevation = context.resources.getDimension(
+ R.dimen.dragged_bubble_elevation)
val dragMotionEventHandler = HandleDragListener()
expandedView.handleView.setOnTouchListener { view, event ->
@@ -103,6 +110,7 @@
override fun onDown(v: View, ev: MotionEvent): Boolean {
// While animating, don't allow new touch events
if (expandedView.isAnimating) return false
+ expandedView.z = draggedBubbleElevation
if (dropTargetManager != null && dragZoneFactory != null) {
val draggedObject = DraggedObject.ExpandedView(
if (bubblePositioner.isBubbleBarOnLeft) {
@@ -154,11 +162,13 @@
velX: Float,
velY: Float,
) {
+ v.translationZ = 0f
finishDrag()
}
override fun onCancel(v: View, ev: MotionEvent, viewInitialX: Float, viewInitialY: Float) {
isStuckToDismiss = false
+ v.translationZ = 0f
finishDrag()
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index 2cc9387..dd86725 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -349,6 +349,7 @@
}
};
mDragController = new BubbleBarExpandedViewDragController(
+ mContext,
mExpandedView,
mDismissView,
mAnimationHelper,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
index 46f6e40..06d734c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
@@ -355,6 +355,19 @@
}
}
+ private void onDesktopModeEligibleChanged(int displayId) {
+ synchronized (mDisplays) {
+ if (mDisplays.get(displayId) == null || getDisplay(displayId) == null) {
+ Slog.w(TAG, "Skipping onDesktopModeEligibleChanged on unknown"
+ + " display, displayId=" + displayId);
+ return;
+ }
+ for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) {
+ mDisplayChangedListeners.get(i).onDesktopModeEligibleChanged(displayId);
+ }
+ }
+ }
+
private static class DisplayRecord {
private int mDisplayId;
private Context mContext;
@@ -422,6 +435,13 @@
new ArraySet<>(restricted), new ArraySet<>(unrestricted));
});
}
+
+ @Override
+ public void onDesktopModeEligibleChanged(int displayId) {
+ mMainExecutor.execute(() -> {
+ DisplayController.this.onDesktopModeEligibleChanged(displayId);
+ });
+ }
}
/**
@@ -467,5 +487,10 @@
* Called when the display topology has changed.
*/
default void onTopologyChanged(DisplayTopology topology) {}
+
+ /**
+ * Called when the eligibility of the desktop mode for a display have changed.
+ */
+ default void onDesktopModeEligibleChanged(int displayId) {}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerRoundedCorner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerRoundedCorner.java
index cf0ecae..a1e7ff0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerRoundedCorner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerRoundedCorner.java
@@ -106,31 +106,37 @@
* of non split screen.
*
* @param isSplitScreen Whether the divider is used by split screen or tiling.
- * @param isDarkMode Whether the mode is ui dark mode.
+ * @param color Rounded corner color.
*/
- public void setup(boolean isSplitScreen, boolean isDarkMode) {
+ public void setup(boolean isSplitScreen, int color) {
mIsSplitScreen = isSplitScreen;
if (!isSplitScreen) {
- mDividerBarBackground.setColor(getTilingHandleColor(isDarkMode));
+ mDividerBarBackground.setColor(color);
}
}
/**
- * Notifies the divider of ui mode change.
+ * Notifies the divider of ui mode change and provides a new color.
*
- * @param isDarkMode Whether the mode is ui dark mode.
+ * @param color The new divider rounded corner color.
*/
- public void onUiModeChange(boolean isDarkMode) {
+ public void onUiModeChange(int color) {
if (!mIsSplitScreen) {
- mDividerBarBackground.setColor(getTilingHandleColor(isDarkMode));
+ mDividerBarBackground.setColor(color);
invalidate();
}
}
- private int getTilingHandleColor(boolean isDarkMode) {
- return isDarkMode ? getResources().getColor(
- R.color.tiling_divider_background_dark, null /* theme */) : getResources().getColor(
- R.color.tiling_divider_background_light, null /* theme */);
+ /**
+ * Notifies rounded corner view of color change.
+ *
+ * @param color The new divider rounded corner color.
+ */
+ public void onCornerColorChange(int color) {
+ if (!mIsSplitScreen) {
+ mDividerBarBackground.setColor(color);
+ invalidate();
+ }
}
/**
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 f62fd819..b3c25d4 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
@@ -762,6 +762,7 @@
ShellTaskOrganizer organizer,
TransactionPool pool,
DisplayController displayController,
+ DisplayInsetsController displayInsetsController,
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler,
@ShellAnimationThread ShellExecutor animExecutor,
@@ -773,15 +774,19 @@
shellInit = new ShellInit(mainExecutor);
}
return new Transitions(context, shellInit, shellCommandHandler, shellController, organizer,
- pool, displayController, mainExecutor, mainHandler, animExecutor,
- rootTaskDisplayAreaOrganizer, homeTransitionObserver, focusTransitionObserver);
+ pool, displayController, displayInsetsController, mainExecutor, mainHandler,
+ animExecutor, rootTaskDisplayAreaOrganizer, homeTransitionObserver,
+ focusTransitionObserver);
}
@WMSingleton
@Provides
static HomeTransitionObserver provideHomeTransitionObserver(Context context,
- @ShellMainThread ShellExecutor mainExecutor) {
- return new HomeTransitionObserver(context, mainExecutor);
+ @ShellMainThread ShellExecutor mainExecutor,
+ DisplayInsetsController displayInsetsController,
+ ShellInit shellInit) {
+ return new HomeTransitionObserver(context, mainExecutor, displayInsetsController,
+ shellInit);
}
@WMSingleton
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 5fbbb0b..07745d4 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
@@ -62,6 +62,7 @@
import com.android.wm.shell.bubbles.BubbleLogger;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleResizabilityChecker;
+import com.android.wm.shell.bubbles.BubbleTaskUnfoldTransitionMerger;
import com.android.wm.shell.bubbles.bar.BubbleBarDragListener;
import com.android.wm.shell.bubbles.storage.BubblePersistentRepository;
import com.android.wm.shell.common.DisplayController;
@@ -244,6 +245,13 @@
context, logger, positioner, educationController, mainExecutor, bgExecutor);
}
+ @WMSingleton
+ @Provides
+ static Optional<BubbleTaskUnfoldTransitionMerger> provideBubbleTaskUnfoldTransitionMerger(
+ Optional<BubbleController> bubbleController) {
+ return bubbleController.map(controller -> controller);
+ }
+
// Note: Handler needed for LauncherApps.register
@WMSingleton
@Provides
@@ -705,7 +713,8 @@
Transitions transitions,
@ShellMainThread ShellExecutor executor,
@ShellMainThread Handler handler,
- ShellInit shellInit) {
+ ShellInit shellInit,
+ Optional<BubbleTaskUnfoldTransitionMerger> bubbleTaskUnfoldTransitionMerger) {
return new UnfoldTransitionHandler(
shellInit,
progressProvider.get(),
@@ -714,7 +723,8 @@
transactionPool,
executor,
handler,
- transitions);
+ transitions,
+ bubbleTaskUnfoldTransitionMerger);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt
index 3b98f81..25737c4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt
@@ -89,6 +89,15 @@
// TODO: b/362720497 - move desks in closing display to the remaining desk.
}
+ override fun onDesktopModeEligibleChanged(displayId: Int) {
+ if (
+ DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue &&
+ displayId != DEFAULT_DISPLAY
+ ) {
+ desktopDisplayModeController.refreshDisplayWindowingMode()
+ }
+ }
+
override fun onDeskRemoved(lastDisplayId: Int, deskId: Int) {
val remainingDesks = desktopRepository.getNumberOfDesks(lastDisplayId)
if (remainingDesks == 0) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
index 3c44fe8..5517951 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
@@ -22,7 +22,6 @@
import android.app.TaskInfo
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
import android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK
-import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.content.pm.ActivityInfo.LAUNCH_MULTIPLE
import android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE
import android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK
@@ -303,21 +302,19 @@
// Top task is an instance of launching activity. Activity will be launching in a new
// task with the existing task also being closed. Inherit existing task bounds to
// prevent new task jumping.
- (isLaunchingNewTask(launchMode, intentFlags) && isClosingExitingInstance(intentFlags)) ->
+ (isLaunchingNewSingleTask(launchMode) && isClosingExitingInstance(intentFlags)) ->
lastTask.configuration.windowConfiguration.bounds
else -> null
}
}
/**
- * Returns true if the launch mode or intent will result in a new task being created for the
- * activity.
+ * Returns true if the launch mode will result in a single new task being created for the activity.
*/
-private fun isLaunchingNewTask(launchMode: Int, intentFlags: Int) =
+private fun isLaunchingNewSingleTask(launchMode: Int) =
launchMode == LAUNCH_SINGLE_TASK ||
launchMode == LAUNCH_SINGLE_INSTANCE ||
- launchMode == LAUNCH_SINGLE_INSTANCE_PER_TASK ||
- (intentFlags and FLAG_ACTIVITY_NEW_TASK) != 0
+ launchMode == LAUNCH_SINGLE_INSTANCE_PER_TASK
/**
* Returns true if the intent will result in an existing task instance being closed if a new one
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
index 8495f71..25fdbb3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
@@ -1299,6 +1299,7 @@
deskByDisplayId[displayId]?.let { sequenceOf(it) } ?: emptySequence()
override fun remove(deskId: Int) {
+ setDeskInactive(deskId)
deskByDisplayId[deskId]?.clear()
}
@@ -1398,6 +1399,7 @@
desktopDisplays[displayId]?.orderedDesks?.asSequence() ?: emptySequence()
override fun remove(deskId: Int) {
+ setDeskInactive(deskId)
desktopDisplays.forEach { _, display ->
display.orderedDesks.removeIf { it.deskId == deskId }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 5849d4a..b60fd5b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -449,6 +449,11 @@
return false
}
+ // Secondary displays are always desktop-first
+ if (displayId != DEFAULT_DISPLAY) {
+ return true
+ }
+
val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)
// A non-organized display (e.g., non-trusted virtual displays used in CTS) doesn't have
// TDA.
@@ -1140,6 +1145,7 @@
}
val t =
if (remoteTransition == null) {
+ logV("startLaunchTransition -- no remoteTransition -- wct = $launchTransaction")
desktopMixedTransitionHandler.startLaunchTransition(
transitionType = transitionType,
wct = launchTransaction,
@@ -2793,11 +2799,14 @@
taskInfo: RunningTaskInfo,
deskId: Int?,
): RunOnTransitStart? {
- // This windowing mode is to get the transition animation started; once we complete
- // split select, we will change windowing mode to undefined and inherit from split stage.
- // Going to undefined here causes task to flicker to the top left.
- // Cancelling the split select flow will revert it to fullscreen.
- wct.setWindowingMode(taskInfo.token, WINDOWING_MODE_MULTI_WINDOW)
+ if (!DesktopModeFlags.ENABLE_INPUT_LAYER_TRANSITION_FIX.isTrue) {
+ // This windowing mode is to get the transition animation started; once we complete
+ // split select, we will change windowing mode to undefined and inherit from split
+ // stage.
+ // Going to undefined here causes task to flicker to the top left.
+ // Cancelling the split select flow will revert it to fullscreen.
+ wct.setWindowingMode(taskInfo.token, WINDOWING_MODE_MULTI_WINDOW)
+ }
// The task's density may have been overridden in freeform; revert it here as we don't
// want it overridden in multi-window.
wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi())
@@ -2892,7 +2901,7 @@
* null and may be used to run other desktop policies, such as minimizing another task if the
* task limit has been exceeded.
*/
- fun addDeskActivationChanges(
+ private fun addDeskActivationChanges(
deskId: Int,
wct: WindowContainerTransaction,
newTask: TaskInfo? = null,
@@ -2950,6 +2959,8 @@
}
}
}
+ val deactivatingDesk = taskRepository.getActiveDeskId(displayId)?.takeIf { it != deskId }
+ val deactivationRunnable = prepareDeskDeactivationIfNeeded(wct, deactivatingDesk)
return { transition ->
val activateDeskTransition =
if (newTaskIdInFront != null) {
@@ -2970,6 +2981,7 @@
taskIdToMinimize?.let { minimizingTask ->
addPendingMinimizeTransition(transition, minimizingTask, MinimizeReason.TASK_LIMIT)
}
+ deactivationRunnable?.invoke(transition)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index b3c1a92..d608413 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -663,6 +663,9 @@
mSession = null;
}
});
+ // notify bubbles of drag cancel
+ mCurrentBubbleBarTarget = null;
+ mBubbleBarDragListener.onItemDraggedOutsideBubbleBarDropZone();
// Reset the state if we previously force-ignore the bottom margin
mDropZoneView1.setForceIgnoreBottomMargin(false);
mDropZoneView2.setForceIgnoreBottomMargin(false);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
index e7492f1..2476ee1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
@@ -174,7 +174,7 @@
SurfaceControl.Transaction finishT) {
mTaskChangeListener.ifPresent(listener -> listener.onTaskChanging(change.getTaskInfo()));
mWindowDecorViewModel.onTaskChanging(
- change.getTaskInfo(), change.getLeash(), startT, finishT, change.getMode());
+ change.getTaskInfo(), change.getLeash(), startT, finishT);
}
private void onToFrontTransitionReady(
@@ -184,7 +184,7 @@
mTaskChangeListener.ifPresent(
listener -> listener.onTaskMovingToFront(change.getTaskInfo()));
mWindowDecorViewModel.onTaskChanging(
- change.getTaskInfo(), change.getLeash(), startT, finishT, change.getMode());
+ change.getTaskInfo(), change.getLeash(), startT, finishT);
}
private void onToBackTransitionReady(
@@ -194,7 +194,7 @@
mTaskChangeListener.ifPresent(
listener -> listener.onTaskMovingToBack(change.getTaskInfo()));
mWindowDecorViewModel.onTaskChanging(
- change.getTaskInfo(), change.getLeash(), startT, finishT, change.getMode());
+ change.getTaskInfo(), change.getLeash(), startT, finishT);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 014c810..10db5ca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -124,7 +124,6 @@
import android.view.WindowManager;
import android.widget.Toast;
import android.window.DesktopExperienceFlags;
-import android.window.DesktopModeFlags;
import android.window.DisplayAreaInfo;
import android.window.RemoteTransition;
import android.window.TransitionInfo;
@@ -684,8 +683,7 @@
if (!enteredSplitSelect) {
return null;
}
- if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue()
- && !DesktopModeFlags.ENABLE_INPUT_LAYER_TRANSITION_FIX.isTrue()) {
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue()) {
mTaskOrganizer.applyTransaction(wct);
return null;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
index a6f8726..22848c3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
@@ -728,6 +728,48 @@
taskView.notifyAppeared(newTask);
}
+ /**
+ * Updates bounds for the task view during an unfold transition.
+ *
+ * @return true if the task was found and a transition for this task is pending. false
+ * otherwise.
+ */
+ public boolean updateBoundsForUnfold(Rect bounds, SurfaceControl.Transaction startTransaction,
+ SurfaceControl.Transaction finishTransaction,
+ ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
+ final TaskViewTaskController taskView = findTaskView(taskInfo);
+ if (taskView == null) {
+ return false;
+ }
+
+ final PendingTransition pendingTransition = findPending(taskView, TRANSIT_CHANGE);
+ if (pendingTransition == null) {
+ return false;
+ }
+
+ mPending.remove(pendingTransition);
+
+ // reparent the task under the task view surface and set the bounds on it
+ startTransaction.reparent(leash, taskView.getSurfaceControl())
+ .setPosition(leash, 0, 0)
+ .setWindowCrop(leash, bounds.width(), bounds.height())
+ .show(leash);
+ // the finish transaction would reparent the task back to the transition root, so reparent
+ // it again to the task view surface
+ finishTransaction.reparent(leash, taskView.getSurfaceControl())
+ .setPosition(leash, 0, 0)
+ .setWindowCrop(leash, bounds.width(), bounds.height());
+ if (useRepo()) {
+ final TaskViewRepository.TaskViewState state = mTaskViewRepo.byTaskView(taskView);
+ if (state != null) {
+ state.mBounds.set(bounds);
+ }
+ } else {
+ updateBoundsState(taskView, bounds);
+ }
+ return true;
+ }
+
private void updateBounds(TaskViewTaskController taskView, Rect boundsOnScreen,
SurfaceControl.Transaction startTransaction,
SurfaceControl.Transaction finishTransaction,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultSurfaceAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultSurfaceAnimator.java
index ce98b03..bff08ba 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultSurfaceAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultSurfaceAnimator.java
@@ -42,9 +42,10 @@
@NonNull Animation anim, @NonNull SurfaceControl leash,
@NonNull Runnable finishCallback, @NonNull TransactionPool pool,
@NonNull ShellExecutor mainExecutor, @Nullable Point position, float cornerRadius,
- @Nullable Rect clipRect) {
+ @Nullable Rect clipRect,
+ @Nullable TransitionAnimationHelper.RoundedContentPerDisplay roundedBounds) {
final DefaultAnimationAdapter adapter = new DefaultAnimationAdapter(anim, leash,
- position, clipRect, cornerRadius);
+ position, clipRect, cornerRadius, roundedBounds);
buildSurfaceAnimation(animations, anim, finishCallback, pool, mainExecutor, adapter);
}
@@ -109,9 +110,17 @@
@Nullable final Rect mClipRect;
@Nullable private final Rect mAnimClipRect;
final float mCornerRadius;
+ final int mWindowBottom;
+
+ /**
+ * Inset changes aren't synchronized with transitions, so use a "provider" to track the
+ * bottom of the display content during the animation.
+ */
+ @Nullable final TransitionAnimationHelper.RoundedContentPerDisplay mRoundedContentBounds;
DefaultAnimationAdapter(@NonNull Animation anim, @NonNull SurfaceControl leash,
- @Nullable Point position, @Nullable Rect clipRect, float cornerRadius) {
+ @Nullable Point position, @Nullable Rect clipRect, float cornerRadius,
+ TransitionAnimationHelper.RoundedContentPerDisplay roundedBounds) {
super(leash);
mAnim = anim;
mPosition = (position != null && (position.x != 0 || position.y != 0))
@@ -119,6 +128,8 @@
mClipRect = (clipRect != null && !clipRect.isEmpty()) ? clipRect : null;
mAnimClipRect = mClipRect != null ? new Rect() : null;
mCornerRadius = cornerRadius;
+ mWindowBottom = clipRect != null ? clipRect.bottom : 0;
+ mRoundedContentBounds = roundedBounds;
}
@Override
@@ -136,6 +147,11 @@
if (mClipRect != null) {
boolean needCrop = false;
+ if (mRoundedContentBounds != null) {
+ mClipRect.bottom = Math.min(mRoundedContentBounds.mBounds.bottom,
+ mWindowBottom);
+ }
+
mAnimClipRect.set(mClipRect);
if (transformation.hasClipRect()) {
mAnimClipRect.intersectUnchecked(transformation.getClipRect());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index bf58003..e920083 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -59,13 +59,13 @@
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import static com.android.internal.jank.Cuj.CUJ_DEFAULT_TASK_TO_TASK_ANIMATION;
-import static com.android.internal.policy.TransitionAnimation.DEFAULT_APP_TRANSITION_DURATION;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_CHANGE;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_CLOSE;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_CLOSE;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_OPEN;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN;
+import static com.android.wm.shell.Flags.enableDynamicInsetsForAppLaunch;
import static com.android.wm.shell.transition.DefaultSurfaceAnimator.buildSurfaceAnimation;
import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet;
import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionTypeFromInfo;
@@ -111,11 +111,13 @@
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.animation.SizeChangeAnimation;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.TransitionUtil;
+import com.android.wm.shell.shared.animation.Interpolators;
import com.android.wm.shell.sysui.ShellInit;
import java.util.ArrayList;
@@ -125,6 +127,7 @@
/** The default handler that handles anything not already handled. */
public class DefaultTransitionHandler implements Transitions.TransitionHandler {
private static final int MAX_ANIMATION_DURATION = 3000;
+ private static final int SIZE_CHANGE_ANIMATION_DURATION = 400;
private final TransactionPool mTransactionPool;
private final DisplayController mDisplayController;
@@ -134,6 +137,7 @@
private final ShellExecutor mAnimExecutor;
private final TransitionAnimation mTransitionAnimation;
private final DevicePolicyManager mDevicePolicyManager;
+ private final TransitionAnimationHelper.RoundedContentTracker mRoundedContentBounds;
/** Keeps track of the currently-running animations associated with each transition. */
private final ArrayMap<IBinder, ArrayList<Animator>> mAnimations = new ArrayMap<>();
@@ -163,6 +167,7 @@
DefaultTransitionHandler(@NonNull Context context,
@NonNull ShellInit shellInit,
@NonNull DisplayController displayController,
+ @NonNull DisplayInsetsController displayInsetsController,
@NonNull TransactionPool transactionPool,
@NonNull ShellExecutor mainExecutor, @NonNull Handler mainHandler,
@NonNull ShellExecutor animExecutor,
@@ -179,6 +184,8 @@
mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
shellInit.addInitCallback(this::onInit, this);
mRootTDAOrganizer = rootTDAOrganizer;
+ mRoundedContentBounds = new TransitionAnimationHelper.RoundedContentTracker(
+ displayController, displayInsetsController);
mInteractionJankMonitor = interactionJankMonitor;
}
@@ -191,6 +198,7 @@
mMainHandler);
TransitionAnimation.initAttributeCache(mContext, mMainHandler);
+ mRoundedContentBounds.init();
}
private void updateEnterpriseThumbnailDrawable() {
@@ -297,6 +305,18 @@
return ROTATION_ANIMATION_SEAMLESS;
}
+ @Nullable
+ final TransitionAnimationHelper.RoundedContentPerDisplay getRoundedContentBounds(
+ TransitionInfo.Change change) {
+ if (!enableDynamicInsetsForAppLaunch()) {
+ return null;
+ }
+ if (change.getTaskInfo() == null && change.getActivityComponent() == null) {
+ return null;
+ }
+ return mRoundedContentBounds.forDisplay(change.getEndDisplayId());
+ }
+
@Override
public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@@ -556,7 +576,8 @@
change.getEndAbsBounds().left - animRoot.getOffset().x,
change.getEndAbsBounds().top - animRoot.getOffset().y);
- if (change.getActivityComponent() != null) {
+ final boolean isActivity = change.getActivityComponent() != null;
+ if (isActivity) {
// For appcompat letterbox: we intentionally report the task-bounds so that we
// can animate as-if letterboxes are "part of" the activity. This means we can't
// always rely solely on endAbsBounds and need to also max with endRelOffset.
@@ -564,7 +585,7 @@
animRelOffset.y = Math.max(animRelOffset.y, change.getEndRelOffset().y);
}
- if (change.getActivityComponent() != null && !isActivityLevel
+ if (isActivity && !isActivityLevel
&& !mRotator.isRotated(change)) {
// At this point, this is an independent activity change in a non-activity
// transition. This means that an activity transition got erroneously combined
@@ -589,8 +610,10 @@
}
buildSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish,
- mTransactionPool, mMainExecutor, animRelOffset, cornerRadius,
- clipRect);
+ mTransactionPool, mMainExecutor, animRelOffset, cornerRadius, clipRect,
+ isTask || isActivity
+ ? mRoundedContentBounds.forDisplay(change.getEndDisplayId())
+ : null);
final TransitionInfo.AnimationOptions options = change.getAnimationOptions();
if (options != null) {
@@ -779,15 +802,16 @@
private void startBoundsChangeAnimation(@NonNull SurfaceControl.Transaction startT,
@NonNull ArrayList<Animator> animations, @NonNull TransitionInfo.Change change,
@NonNull Runnable finishCb, @NonNull ShellExecutor mainExecutor) {
- final SizeChangeAnimation sca =
- new SizeChangeAnimation(change.getStartAbsBounds(), change.getEndAbsBounds());
+ final SizeChangeAnimation sca = new SizeChangeAnimation(change.getStartAbsBounds(),
+ change.getEndAbsBounds(), /* initialScale= */ 1f, /* scaleFactor= */ 1f);
sca.initialize(change.getLeash(), change.getSnapshot(), startT);
final ValueAnimator va = sca.buildAnimator(change.getLeash(), change.getSnapshot(),
(animator) -> mainExecutor.execute(() -> {
animations.remove(animator);
finishCb.run();
}));
- va.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+ va.setDuration(SIZE_CHANGE_ANIMATION_DURATION);
+ va.setInterpolator(Interpolators.EMPHASIZED);
animations.add(va);
}
@@ -932,7 +956,8 @@
a.restrictDuration(MAX_ANIMATION_DURATION);
a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
buildSurfaceAnimation(animations, a, wt.getSurface(), finisher, mTransactionPool,
- mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds());
+ mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds(),
+ getRoundedContentBounds(change));
}
private void attachThumbnailAnimation(@NonNull ArrayList<Animator> animations,
@@ -956,7 +981,8 @@
a.restrictDuration(MAX_ANIMATION_DURATION);
a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
buildSurfaceAnimation(animations, a, wt.getSurface(), finisher, mTransactionPool,
- mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds());
+ mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds(),
+ getRoundedContentBounds(change));
}
private static int getWallpaperTransitType(TransitionInfo info) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
index cca9821..c71458d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
@@ -29,15 +29,18 @@
import android.app.ActivityManager;
import android.content.Context;
import android.os.IBinder;
+import android.view.InsetsState;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SingleInstanceRemoteListener;
import com.android.wm.shell.shared.IHomeTransitionListener;
import com.android.wm.shell.shared.TransitionUtil;
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
+import com.android.wm.shell.sysui.ShellInit;
/**
* The {@link TransitionObserver} that observes for transitions involving the home
@@ -51,13 +54,30 @@
private @NonNull final Context mContext;
private @NonNull final ShellExecutor mMainExecutor;
+ private @NonNull final DisplayInsetsController mDisplayInsetsController;
private IBinder mPendingStartDragTransition;
private Boolean mPendingHomeVisibilityUpdate;
public HomeTransitionObserver(@NonNull Context context,
- @NonNull ShellExecutor mainExecutor) {
+ @NonNull ShellExecutor mainExecutor,
+ @NonNull DisplayInsetsController displayInsetsController,
+ @NonNull ShellInit shellInit) {
mContext = context;
mMainExecutor = mainExecutor;
+ mDisplayInsetsController = displayInsetsController;
+
+ shellInit.addInitCallback(this::onInit, this);
+ }
+
+ private void onInit() {
+ mDisplayInsetsController.addInsetsChangedListener(DEFAULT_DISPLAY,
+ new DisplayInsetsController.OnInsetsChangedListener() {
+ @Override
+ public void insetsChanged(InsetsState insetsState) {
+ if (mListener == null) return;
+ mListener.call(l -> l.onDisplayInsetsChanged(insetsState));
+ }
+ });
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index aa42b7f..8100f1d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -347,21 +347,21 @@
@NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
buildSurfaceAnimation(animations, mRotateEnterAnimation, getEnterSurface(), finishCallback,
mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
- null /* clipRect */);
+ null /* clipRect */, null);
}
private void startScreenshotRotationAnimation(@NonNull ArrayList<Animator> animations,
@NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
buildSurfaceAnimation(animations, mRotateExitAnimation, mAnimLeash, finishCallback,
mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
- null /* clipRect */);
+ null /* clipRect */, null);
}
private void buildScreenshotAlphaAnimation(@NonNull ArrayList<Animator> animations,
@NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
buildSurfaceAnimation(animations, mRotateAlphaAnimation, mAnimLeash, finishCallback,
mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
- null /* clipRect */);
+ null /* clipRect */, null);
}
private void buildLumaAnimation(@NonNull ArrayList<Animator> animations,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
index edfb560..48b4864 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
@@ -39,6 +39,11 @@
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.graphics.Color;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.util.SparseArray;
+import android.view.InsetsSource;
+import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.animation.Animation;
@@ -47,6 +52,9 @@
import com.android.internal.R;
import com.android.internal.policy.TransitionAnimation;
import com.android.internal.protolog.ProtoLog;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.TransitionUtil;
@@ -325,4 +333,77 @@
}
return false;
}
+
+ /**
+ * In some situations (eg. TaskBar) the content area of a display appears to be rounded. For
+ * these situations, we may want the animation to also express the same rounded corners (even
+ * though in steady-state, the app internally manages the insets). This class Keeps track of,
+ * and provides, the bounds of rounded-corner display content.
+ *
+ * This is used to enable already-running animations to adapt to changes in taskbar/navbar
+ * position live.
+ */
+ public static class RoundedContentPerDisplay implements
+ DisplayInsetsController.OnInsetsChangedListener {
+
+ /** The current bounds of the display content (post-inset). */
+ final Rect mBounds = new Rect();
+
+ @Override
+ public void insetsChanged(InsetsState insetsState) {
+ Insets insets = Insets.NONE;
+ for (int i = insetsState.sourceSize() - 1; i >= 0; i--) {
+ final InsetsSource source = insetsState.sourceAt(i);
+ if (!source.hasFlags(InsetsSource.FLAG_INSETS_ROUNDED_CORNER)) {
+ continue;
+ }
+ insets = Insets.max(source.calculateInsets(insetsState.getDisplayFrame(), false),
+ insets);
+ }
+ mBounds.set(insetsState.getDisplayFrame());
+ mBounds.inset(insets);
+ }
+ }
+
+ /**
+ * Keeps track of the bounds of rounded-corner display content (post-inset).
+ *
+ * @see RoundedContentPerDisplay
+ */
+ public static class RoundedContentTracker implements
+ DisplayController.OnDisplaysChangedListener {
+ final DisplayController mDisplayController;
+ final DisplayInsetsController mDisplayInsetsController;
+ final SparseArray<RoundedContentPerDisplay> mPerDisplay = new SparseArray<>();
+
+ RoundedContentTracker(DisplayController dc, DisplayInsetsController dic) {
+ mDisplayController = dc;
+ mDisplayInsetsController = dic;
+ }
+
+ void init() {
+ mDisplayController.addDisplayWindowListener(this);
+ }
+
+ RoundedContentPerDisplay forDisplay(int displayId) {
+ return mPerDisplay.get(displayId);
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ final RoundedContentPerDisplay perDisplay = new RoundedContentPerDisplay();
+ mDisplayInsetsController.addInsetsChangedListener(displayId, perDisplay);
+ mPerDisplay.put(displayId, perDisplay);
+ final DisplayLayout dl = mDisplayController.getDisplayLayout(displayId);
+ perDisplay.mBounds.set(0, 0, dl.width(), dl.height());
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ final RoundedContentPerDisplay listener = mPerDisplay.removeReturnOld(displayId);
+ if (listener != null) {
+ mDisplayInsetsController.removeInsetsChangedListener(displayId, listener);
+ }
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 4f49ebc..3dc8733 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -84,6 +84,7 @@
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
@@ -314,13 +315,14 @@
@NonNull ShellTaskOrganizer organizer,
@NonNull TransactionPool pool,
@NonNull DisplayController displayController,
+ @NonNull DisplayInsetsController displayInsetsController,
@NonNull ShellExecutor mainExecutor,
@NonNull Handler mainHandler,
@NonNull ShellExecutor animExecutor,
@NonNull HomeTransitionObserver homeTransitionObserver,
@NonNull FocusTransitionObserver focusTransitionObserver) {
this(context, shellInit, new ShellCommandHandler(), shellController, organizer, pool,
- displayController, mainExecutor, mainHandler, animExecutor,
+ displayController, displayInsetsController, mainExecutor, mainHandler, animExecutor,
new RootTaskDisplayAreaOrganizer(mainExecutor, context, shellInit),
homeTransitionObserver, focusTransitionObserver);
}
@@ -332,6 +334,7 @@
@NonNull ShellTaskOrganizer organizer,
@NonNull TransactionPool pool,
@NonNull DisplayController displayController,
+ @NonNull DisplayInsetsController displayInsetsController,
@NonNull ShellExecutor mainExecutor,
@NonNull Handler mainHandler,
@NonNull ShellExecutor animExecutor,
@@ -345,8 +348,8 @@
mDisplayController = displayController;
mPlayerImpl = new TransitionPlayerImpl();
mDefaultTransitionHandler = new DefaultTransitionHandler(context, shellInit,
- displayController, pool, mainExecutor, mainHandler, animExecutor, rootTDAOrganizer,
- InteractionJankMonitor.getInstance());
+ displayController, displayInsetsController, pool, mainExecutor, mainHandler,
+ animExecutor, rootTDAOrganizer, InteractionJankMonitor.getInstance());
mRemoteTransitionHandler = new RemoteTransitionHandler(mMainExecutor);
mShellCommandHandler = shellCommandHandler;
mShellController = shellController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
index 7fd19a7..706a366 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
@@ -38,6 +38,7 @@
import androidx.annotation.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
+import com.android.wm.shell.bubbles.BubbleTaskUnfoldTransitionMerger;
import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.TransitionUtil;
import com.android.wm.shell.sysui.ShellInit;
@@ -53,6 +54,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.Executor;
/**
@@ -80,6 +82,7 @@
private final ShellUnfoldProgressProvider mUnfoldProgressProvider;
private final Transitions mTransitions;
+ private final Optional<BubbleTaskUnfoldTransitionMerger> mBubbleTaskUnfoldTransitionMerger;
private final Executor mExecutor;
private final TransactionPool mTransactionPool;
private final Handler mHandler;
@@ -108,12 +111,14 @@
TransactionPool transactionPool,
Executor executor,
Handler handler,
- Transitions transitions) {
+ Transitions transitions,
+ Optional<BubbleTaskUnfoldTransitionMerger> bubbleTaskUnfoldTransitionMerger) {
mUnfoldProgressProvider = unfoldProgressProvider;
mTransitions = transitions;
mTransactionPool = transactionPool;
mExecutor = executor;
mHandler = handler;
+ mBubbleTaskUnfoldTransitionMerger = bubbleTaskUnfoldTransitionMerger;
mAnimators.add(splitUnfoldTaskAnimator);
mAnimators.add(fullscreenUnfoldAnimator);
@@ -237,14 +242,26 @@
}
// TODO (b/286928742) unfold transition handler should be part of mixed handler to
// handle merges better.
+
for (int i = 0; i < info.getChanges().size(); ++i) {
final TransitionInfo.Change change = info.getChanges().get(i);
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
if (taskInfo != null
&& taskInfo.configuration.windowConfiguration.isAlwaysOnTop()) {
- // Tasks that are always on top (e.g. bubbles), will handle their own transition
- // as they are on top of everything else. So skip merging transitions here.
- return;
+ // Tasks that are always on top, excluding bubbles, will handle their own transition
+ // as they are on top of everything else. If this is a transition for a bubble task,
+ // attempt to merge it. Otherwise skip merging transitions.
+ if (mBubbleTaskUnfoldTransitionMerger.isPresent()) {
+ boolean merged =
+ mBubbleTaskUnfoldTransitionMerger
+ .get()
+ .mergeTaskWithUnfold(taskInfo, change, startT, finishT);
+ if (!merged) {
+ return;
+ }
+ } else {
+ return;
+ }
}
}
// Apply changes happening during the unfold animation immediately
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 42321e56..7871179 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -49,7 +49,6 @@
import android.view.View;
import android.view.ViewConfiguration;
import android.window.DisplayAreaInfo;
-import android.window.TransitionInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -234,8 +233,7 @@
RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
SurfaceControl.Transaction startT,
- SurfaceControl.Transaction finishT,
- @TransitionInfo.TransitionMode int changeMode) {
+ SurfaceControl.Transaction finishT) {
final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
if (!shouldShowWindowDecor(taskInfo)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecorViewModel.java
index 4511fbe..2b2cdf8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecorViewModel.java
@@ -31,7 +31,6 @@
import android.view.KeyEvent;
import android.view.SurfaceControl;
import android.view.View;
-import android.window.TransitionInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -160,8 +159,7 @@
RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
SurfaceControl.Transaction startT,
- SurfaceControl.Transaction finishT,
- @TransitionInfo.TransitionMode int changeMode) {
+ SurfaceControl.Transaction finishT) {
final CarWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
if (!shouldShowWindowDecor(taskInfo)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 69e1f36..0082d79 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -27,7 +27,6 @@
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.WindowInsets.Type.statusBars;
-import static android.view.WindowManager.TRANSIT_TO_BACK;
import static com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU;
import static com.android.window.flags.Flags.enableDisplayFocusInShellTransitions;
@@ -80,7 +79,6 @@
import android.view.ViewRootImpl;
import android.window.DesktopModeFlags;
import android.window.TaskSnapshot;
-import android.window.TransitionInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -602,8 +600,7 @@
RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
SurfaceControl.Transaction startT,
- SurfaceControl.Transaction finishT,
- @TransitionInfo.TransitionMode int changeMode) {
+ SurfaceControl.Transaction finishT) {
final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
if (!shouldShowWindowDecor(taskInfo)) {
if (decoration != null) {
@@ -617,8 +614,7 @@
} else {
decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */,
false /* shouldSetTaskPositionAndCrop */,
- mFocusTransitionObserver.hasGlobalFocus(taskInfo), mExclusionRegion,
- /*isMovingToBack= */ changeMode == TRANSIT_TO_BACK);
+ mFocusTransitionObserver.hasGlobalFocus(taskInfo), mExclusionRegion);
}
}
@@ -633,7 +629,7 @@
decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */,
false /* shouldSetTaskPositionAndCrop */,
mFocusTransitionObserver.hasGlobalFocus(taskInfo),
- mExclusionRegion, /* isMovingToBack= */ false);
+ mExclusionRegion);
}
@Override
@@ -1892,7 +1888,7 @@
windowDecoration.relayout(taskInfo, startT, finishT,
false /* applyStartTransactionOnDraw */, false /* shouldSetTaskPositionAndCrop */,
mFocusTransitionObserver.hasGlobalFocus(taskInfo),
- mExclusionRegion, /* isMovingToBack= */ false);
+ mExclusionRegion);
if (!DesktopModeFlags.ENABLE_HANDLE_INPUT_FIX.isTrue()) {
incrementEventReceiverTasks(taskInfo.displayId);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 50bc7b5..d243081 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -217,7 +217,6 @@
private boolean mIsDragging = false;
private Runnable mLoadAppInfoRunnable;
private Runnable mSetAppInfoRunnable;
- private boolean mIsMovingToBack;
public DesktopModeWindowDecoration(
Context context,
@@ -479,7 +478,7 @@
// causes flickering. See b/270202228.
final boolean applyTransactionOnDraw = taskInfo.isFreeform();
relayout(taskInfo, t, t, applyTransactionOnDraw, shouldSetTaskVisibilityPositionAndCrop,
- hasGlobalFocus, displayExclusionRegion, mIsMovingToBack);
+ hasGlobalFocus, displayExclusionRegion);
if (!applyTransactionOnDraw) {
t.apply();
}
@@ -506,8 +505,7 @@
void relayout(ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
boolean applyStartTransactionOnDraw, boolean shouldSetTaskVisibilityPositionAndCrop,
- boolean hasGlobalFocus, @NonNull Region displayExclusionRegion,
- boolean isMovingToBack) {
+ boolean hasGlobalFocus, @NonNull Region displayExclusionRegion) {
Trace.beginSection("DesktopModeWindowDecoration#relayout");
if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_APP_TO_WEB.isTrue()) {
@@ -530,7 +528,6 @@
final boolean inFullImmersive = mDesktopUserRepositories.getProfile(taskInfo.userId)
.isTaskInFullImmersiveState(taskInfo.taskId);
- mIsMovingToBack = isMovingToBack;
updateRelayoutParams(mRelayoutParams, mContext, taskInfo, mSplitScreenController,
applyStartTransactionOnDraw, shouldSetTaskVisibilityPositionAndCrop,
mIsStatusBarVisible, mIsKeyguardVisibleAndOccluded, inFullImmersive,
@@ -539,8 +536,7 @@
/* shouldIgnoreCornerRadius= */ mIsRecentsTransitionRunning
&& DesktopModeFlags
.ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX.isTrue(),
- mDesktopModeCompatPolicy.shouldExcludeCaptionFromAppBounds(taskInfo),
- mIsRecentsTransitionRunning, mIsMovingToBack);
+ mDesktopModeCompatPolicy.shouldExcludeCaptionFromAppBounds(taskInfo));
final WindowDecorLinearLayout oldRootView = mResult.mRootView;
final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
@@ -633,6 +629,16 @@
mBgExecutor.execute(mLoadAppInfoRunnable);
}
+ private boolean showInputLayer() {
+ if (!DesktopModeFlags.ENABLE_INPUT_LAYER_TRANSITION_FIX.isTrue()) {
+ return isCaptionVisible();
+ }
+ // Don't show the input layer during the recents transition, otherwise it could become
+ // touchable while in overview, during quick-switch or even for a short moment after going
+ // Home.
+ return isCaptionVisible() && !mIsRecentsTransitionRunning;
+ }
+
private boolean isCaptionVisible() {
return mTaskInfo.isVisible && mIsCaptionVisible;
}
@@ -874,7 +880,7 @@
if (!isAppHandle(mWindowDecorViewHolder)) return;
asAppHandle(mWindowDecorViewHolder).bindData(new AppHandleViewHolder.HandleData(
mTaskInfo, determineHandlePosition(), mResult.mCaptionWidth,
- mResult.mCaptionHeight, /* showInputLayer= */ isCaptionVisible(),
+ mResult.mCaptionHeight, /* showInputLayer= */ showInputLayer(),
/* isCaptionVisible= */ isCaptionVisible()
));
}
@@ -959,9 +965,7 @@
boolean hasGlobalFocus,
@NonNull Region displayExclusionRegion,
boolean shouldIgnoreCornerRadius,
- boolean shouldExcludeCaptionFromAppBounds,
- boolean isRecentsTransitionRunning,
- boolean isMovingToBack) {
+ boolean shouldExcludeCaptionFromAppBounds) {
final int captionLayoutId = getDesktopModeWindowDecorLayoutId(taskInfo.getWindowingMode());
final boolean isAppHeader =
captionLayoutId == R.layout.desktop_mode_app_header;
@@ -979,19 +983,10 @@
relayoutParams.mAsyncViewHost = isAppHandle;
boolean showCaption;
- // If this relayout is occurring from an observed TRANSIT_TO_BACK transition, do not
- // show caption (this includes split select transition).
- if (DesktopModeFlags.ENABLE_INPUT_LAYER_TRANSITION_FIX.isTrue()
- && isMovingToBack && !isDragging) {
- showCaption = false;
- } else if (DesktopModeFlags.ENABLE_DESKTOP_IMMERSIVE_DRAG_BUGFIX.isTrue() && isDragging) {
+ if (DesktopModeFlags.ENABLE_DESKTOP_IMMERSIVE_DRAG_BUGFIX.isTrue() && isDragging) {
// If the task is being dragged, the caption should not be hidden so that it continues
// receiving input
showCaption = true;
- } else if (DesktopModeFlags.ENABLE_INPUT_LAYER_TRANSITION_FIX.isTrue()
- && isRecentsTransitionRunning) {
- // Caption should not be visible in recents.
- showCaption = false;
} else if (DesktopModeFlags.ENABLE_FULLY_IMMERSIVE_IN_DESKTOP.isTrue()) {
if (inFullImmersiveMode) {
showCaption = (isStatusBarVisible && !isKeyguardVisibleAndOccluded);
@@ -1895,18 +1890,9 @@
* <p> When a Recents transition is active we allow that transition to take ownership of the
* corner radius of its task surfaces, so each window decoration should stop updating the corner
* radius of its task surface during that time.
- *
- * We should not allow input to reach the input layer during a Recents transition, so
- * update the handle view holder accordingly if transition status changes.
*/
void setIsRecentsTransitionRunning(boolean isRecentsTransitionRunning) {
- if (mIsRecentsTransitionRunning != isRecentsTransitionRunning) {
- mIsRecentsTransitionRunning = isRecentsTransitionRunning;
- if (DesktopModeFlags.ENABLE_INPUT_LAYER_TRANSITION_FIX.isTrue()) {
- // We don't relayout decor on recents transition, so we need to call it directly.
- relayout(mTaskInfo, mHasGlobalFocus, mRelayoutParams.mDisplayExclusionRegion);
- }
- }
+ mIsRecentsTransitionRunning = isRecentsTransitionRunning;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index 8a8bdca..97a47c6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -435,7 +435,9 @@
}
// Removing this surface on the background thread to ensure that mInitInputChannels has
// already been finished.
- mSurfaceControlTransactionSupplier.get().remove(mDecorationSurface).apply();
+ // Do not |remove| the surface, the decoration might still be needed even if
+ // drag-resizing isn't.
+ mDecorationSurface.release();
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
index 25cf06b..cdadce5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
@@ -50,7 +50,6 @@
import androidx.core.view.isGone
import com.android.window.flags.Flags
import com.android.wm.shell.R
-import com.android.wm.shell.bubbles.ContextUtils.isRtl
import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger
import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum.A11Y_APP_HANDLE_MENU_DESKTOP_VIEW
import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum.A11Y_APP_HANDLE_MENU_FULLSCREEN
@@ -58,6 +57,7 @@
import com.android.wm.shell.shared.annotations.ShellBackgroundThread
import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper
+import com.android.wm.shell.shared.bubbles.ContextUtils.isRtl
import com.android.wm.shell.shared.split.SplitScreenConstants
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
index 5e4a0a5..1563259 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
@@ -18,7 +18,6 @@
import android.app.ActivityManager;
import android.view.SurfaceControl;
-import android.window.TransitionInfo;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -84,14 +83,12 @@
* @param taskSurface the surface of the task
* @param startT the start transaction to be applied before the transition
* @param finishT the finish transaction to restore states after the transition
- * @param changeMode the type of change to the task
*/
void onTaskChanging(
ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
SurfaceControl.Transaction startT,
- SurfaceControl.Transaction finishT,
- @TransitionInfo.TransitionMode int changeMode);
+ SurfaceControl.Transaction finishT);
/**
* Notifies that the given task is about to close to give the window decoration a chance to
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt
index c5057aa..f09f22f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt
@@ -92,4 +92,7 @@
Theme.LIGHT -> lightColors
Theme.DARK -> darkColors
}
+
+ fun getColorScheme(isDarkMode: Boolean): ColorScheme =
+ if (isDarkMode) darkColors else lightColors
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
index 57f8046..ab6b729 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
@@ -198,6 +198,11 @@
tilingDividerView?.onUiModeChange(isDarkMode)
}
+ /** Notifies the divider view of task info change and possible color change. */
+ fun onTaskInfoChange() {
+ tilingDividerView?.onTaskInfoChange()
+ }
+
/** Hides the divider bar. */
fun hideDividerBar() {
if (!dividerShown) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
index b579311..3e92d7d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
@@ -375,6 +375,7 @@
fun onTaskInfoChange(taskInfo: RunningTaskInfo) {
val isCurrentTaskInDarkMode = isTaskInDarkMode(taskInfo)
+ desktopTilingDividerWindowManager?.onTaskInfoChange()
if (isCurrentTaskInDarkMode == isDarkMode || !isTilingManagerInitialised) return
isDarkMode = isCurrentTaskInDarkMode
desktopTilingDividerWindowManager?.onUiModeChange(isDarkMode)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
index 54dcd2d..e9bd6f8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
@@ -29,6 +29,7 @@
import android.view.View
import android.view.ViewConfiguration
import android.widget.FrameLayout
+import androidx.compose.ui.graphics.toArgb
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
import com.android.wm.shell.R
@@ -36,6 +37,7 @@
import com.android.wm.shell.common.split.DividerRoundedCorner
import com.android.wm.shell.shared.animation.Interpolators
import com.android.wm.shell.windowdecor.DragDetector
+import com.android.wm.shell.windowdecor.common.DecorThemeUtil
/** Divider for tiling split screen, currently mostly a copy of [DividerView]. */
class TilingDividerView : FrameLayout, View.OnTouchListener, DragDetector.MotionEventHandler {
@@ -56,6 +58,9 @@
@VisibleForTesting var handleY: IntRange = 0..0
private var canResize = false
private var resized = false
+ private var isDarkMode = false
+ private var decorThemeUtil = DecorThemeUtil(context)
+
/**
* Tracks divider bar visible bounds in screen-based coordination. Used to calculate with
* insets.
@@ -90,10 +95,12 @@
) {
callback = dividerMoveCallback
this.dividerBounds.set(dividerBounds)
+ this.isDarkMode = isDarkMode
+ paint.color = decorThemeUtil.getColorScheme(isDarkMode).outlineVariant.toArgb()
handle.setIsLeftRightSplit(true)
handle.setup(/* isSplitScreen= */ false, isDarkMode)
corners.setIsLeftRightSplit(true)
- corners.setup(/* isSplitScreen= */ false, isDarkMode)
+ corners.setup(/* isSplitScreen= */ false, paint.color)
handleRegionHeight = handleRegionSize.height
handleRegionWidth = handleRegionSize.width
cornersRadius =
@@ -108,17 +115,22 @@
}
fun onUiModeChange(isDarkMode: Boolean) {
+ this.isDarkMode = isDarkMode
handle.onUiModeChange(isDarkMode)
- corners.onUiModeChange(isDarkMode)
- paint.color =
- if (isDarkMode) {
- resources.getColor(R.color.tiling_divider_background_dark, null /* theme */)
- } else {
- resources.getColor(R.color.tiling_divider_background_light, null /* theme */)
- }
+ paint.color = decorThemeUtil.getColorScheme(isDarkMode).outlineVariant.toArgb()
+ corners.onUiModeChange(paint.color)
invalidate()
}
+ fun onTaskInfoChange() {
+ decorThemeUtil = DecorThemeUtil(context)
+ if (paint.color != decorThemeUtil.getColorScheme(isDarkMode).outlineVariant.toArgb()) {
+ paint.color = decorThemeUtil.getColorScheme(isDarkMode).outlineVariant.toArgb()
+ corners.onCornerColorChange(paint.color)
+ invalidate()
+ }
+ }
+
override fun onFinishInflate() {
super.onFinishInflate()
dividerBar = requireViewById(R.id.divider_bar)
@@ -128,15 +140,10 @@
resources.getDimensionPixelSize(R.dimen.docked_stack_divider_lift_elevation)
setOnTouchListener(this)
setWillNotDraw(false)
- paint.color =
- if (
- context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
- Configuration.UI_MODE_NIGHT_YES
- ) {
- resources.getColor(R.color.tiling_divider_background_dark, /* theme= */null)
- } else {
- resources.getColor(R.color.tiling_divider_background_light, /* theme= */ null)
- }
+ val isDarkMode =
+ context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
+ Configuration.UI_MODE_NIGHT_YES
+ paint.color = decorThemeUtil.getColorScheme(isDarkMode).outlineVariant.toArgb()
paint.isAntiAlias = true
paint.style = Paint.Style.FILL
}
diff --git a/libs/WindowManager/Shell/tests/e2e/utils/src/com/android/wm/shell/SimulatedConnectedDisplayTestRule.kt b/libs/WindowManager/Shell/tests/e2e/utils/src/com/android/wm/shell/SimulatedConnectedDisplayTestRule.kt
index 68f7ef0..f9b69d3 100644
--- a/libs/WindowManager/Shell/tests/e2e/utils/src/com/android/wm/shell/SimulatedConnectedDisplayTestRule.kt
+++ b/libs/WindowManager/Shell/tests/e2e/utils/src/com/android/wm/shell/SimulatedConnectedDisplayTestRule.kt
@@ -41,7 +41,6 @@
class SimulatedConnectedDisplayTestRule : TestRule {
private val context = InstrumentationRegistry.getInstrumentation().targetContext
- private val uiAutomation = InstrumentationRegistry.getInstrumentation().uiAutomation
private val displayManager = context.getSystemService(DisplayManager::class.java)
private val addedDisplays = mutableListOf<Int>()
@@ -102,7 +101,8 @@
// Add the overlay displays
Settings.Global.putString(
InstrumentationRegistry.getInstrumentation().context.contentResolver,
- Settings.Global.OVERLAY_DISPLAY_DEVICES, displaySettings
+ Settings.Global.OVERLAY_DISPLAY_DEVICES,
+ displaySettings
)
withTimeoutOrNull(TIMEOUT) {
displayAddedFlow.take(displays.size).collect { displayId ->
@@ -125,10 +125,6 @@
}
private fun cleanupTestDisplays() = runBlocking {
- if (addedDisplays.isEmpty()) {
- return@runBlocking
- }
-
val displayRemovedFlow: Flow<Int> = callbackFlow {
val listener = object : DisplayListener {
override fun onDisplayAdded(displayId: Int) {}
@@ -146,16 +142,24 @@
}
}
- // Remove overlay displays
+ // Remove overlay displays. We'll execute this regardless of addedDisplays just to
+ // ensure all overlay displays are removed before and after the test.
+ // Note: If we want to restore the original overlay display added before this test (and its
+ // topology), it will be complicated as re-adding overlay display would lead to different
+ // displayId and topology could not be restored easily.
Settings.Global.putString(
InstrumentationRegistry.getInstrumentation().context.contentResolver,
- Settings.Global.OVERLAY_DISPLAY_DEVICES, null)
+ Settings.Global.OVERLAY_DISPLAY_DEVICES,
+ null
+ )
- withTimeoutOrNull(TIMEOUT) {
- displayRemovedFlow.take(addedDisplays.size).collect { displayId ->
- addedDisplays.remove(displayId)
- }
- } ?: error("Timed out waiting for displays to be removed.")
+ if (!addedDisplays.isEmpty()) {
+ withTimeoutOrNull(TIMEOUT) {
+ displayRemovedFlow.take(addedDisplays.size).collect { displayId ->
+ addedDisplays.remove(displayId)
+ }
+ } ?: error("Timed out waiting for displays to be removed: $addedDisplays")
+ }
}
private companion object {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt
index 9268db6..85a431b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt
@@ -23,6 +23,7 @@
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.dx.mockito.inline.extended.ExtendedMockito.never
import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.server.display.feature.flags.Flags as DisplayFlags
import com.android.window.flags.Flags
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTestCase
@@ -246,6 +247,13 @@
verify(desktopDisplayModeController).refreshDisplayWindowingMode()
}
+ @Test
+ @EnableFlags(DisplayFlags.FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT)
+ fun testDesktopModeEligibleChanged() {
+ onDisplaysChangedListenerCaptor.lastValue.onDesktopModeEligibleChanged(externalDisplayId)
+ verify(desktopDisplayModeController).refreshDisplayWindowingMode()
+ }
+
private class FakeDesktopRepositoryInitializer : DesktopRepositoryInitializer {
override var deskRecreationFactory: DesktopRepositoryInitializer.DeskRecreationFactory =
DesktopRepositoryInitializer.DeskRecreationFactory { _, _, deskId -> deskId }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
index 3fb0083..6ede990 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
@@ -1280,6 +1280,18 @@
@Test
@EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun removeDesk_multipleDesks_active_marksInactiveInDisplay() {
+ repo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 2)
+ repo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 3)
+ repo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 3)
+
+ repo.removeDesk(deskId = 3)
+
+ assertThat(repo.getActiveDeskId(displayId = DEFAULT_DISPLAY)).isNull()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
fun removeDesk_multipleDesks_inactive_removes() {
repo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 2)
repo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 3)
@@ -1292,6 +1304,18 @@
}
@Test
+ @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun removeDesk_multipleDesks_inactive_keepsOtherDeskActiveInDisplay() {
+ repo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 2)
+ repo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 3)
+ repo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 3)
+
+ repo.removeDesk(deskId = 2)
+
+ assertThat(repo.getActiveDeskId(displayId = DEFAULT_DISPLAY)).isEqualTo(3)
+ }
+
+ @Test
@EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND, FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE)
fun removeDesk_removesFromPersistence() =
runTest(StandardTestDispatcher()) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index b577667d..b8c2273 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -32,9 +32,9 @@
import android.content.ComponentName
import android.content.Context
import android.content.Intent
-import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.content.pm.ActivityInfo
import android.content.pm.ActivityInfo.CONFIG_DENSITY
+import android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE
import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
@@ -1200,9 +1200,11 @@
existingTask.topActivity = testComponent
existingTask.configuration.windowConfiguration.setBounds(Rect(0, 0, 500, 500))
// Set up new instance of already existing task.
- val launchingTask = setUpFullscreenTask()
+ val launchingTask =
+ setUpFullscreenTask().apply {
+ topActivityInfo = ActivityInfo().apply { launchMode = LAUNCH_SINGLE_INSTANCE }
+ }
launchingTask.topActivity = testComponent
- launchingTask.baseIntent.addFlags(FLAG_ACTIVITY_NEW_TASK)
// Move new instance to desktop. By default multi instance is not supported so first
// instance will close.
@@ -1224,10 +1226,12 @@
existingTask.topActivity = testComponent
existingTask.configuration.windowConfiguration.setBounds(Rect(0, 0, 500, 500))
// Set up new instance of already existing task.
- val launchingTask = setUpFreeformTask(active = false)
+ val launchingTask =
+ setUpFreeformTask(active = false).apply {
+ topActivityInfo = ActivityInfo().apply { launchMode = LAUNCH_SINGLE_INSTANCE }
+ }
taskRepository.removeTask(launchingTask.displayId, launchingTask.taskId)
launchingTask.topActivity = testComponent
- launchingTask.baseIntent.addFlags(FLAG_ACTIVITY_NEW_TASK)
// Move new instance to desktop. By default multi instance is not supported so first
// instance will close.
@@ -4283,6 +4287,25 @@
}
@Test
+ @EnableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
+ Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+ )
+ fun handleRequest_fullscreenTask_noInDesk_enforceDesktop_secondaryDisplay_movesToDesk() {
+ val deskId = 5
+ taskRepository.addDesk(displayId = SECONDARY_DISPLAY_ID, deskId = deskId)
+ taskRepository.setDeskInactive(deskId)
+ whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null)
+ whenever(DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context)).thenReturn(true)
+
+ val fullscreenTask = createFullscreenTask(displayId = SECONDARY_DISPLAY_ID)
+ val wct = controller.handleRequest(Binder(), createTransition(fullscreenTask))
+
+ assertNotNull(wct, "should handle request")
+ verify(desksOrganizer).moveTaskToDesk(wct, deskId, fullscreenTask)
+ }
+
+ @Test
fun handleRequest_fullscreenTask_notInDesk_enforceDesktop_fullscreenDisplay_returnNull() {
taskRepository.setDeskInactive(deskId = 0)
whenever(DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context)).thenReturn(true)
@@ -5639,6 +5662,33 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun activateDesk_otherDeskWasActive_deactivatesOtherDesk() {
+ val previouslyActiveDeskId = 1
+ val activatingDeskId = 0
+ val transition = Binder()
+ val deskChange = mock(TransitionInfo.Change::class.java)
+ whenever(transitions.startTransition(eq(TRANSIT_TO_FRONT), any(), anyOrNull()))
+ .thenReturn(transition)
+ whenever(desksOrganizer.isDeskActiveAtEnd(deskChange, activatingDeskId)).thenReturn(true)
+ // Make desk inactive by activating another desk.
+ taskRepository.addDesk(DEFAULT_DISPLAY, deskId = previouslyActiveDeskId)
+ taskRepository.setActiveDesk(DEFAULT_DISPLAY, deskId = previouslyActiveDeskId)
+
+ controller.activateDesk(activatingDeskId, RemoteTransition(TestRemoteTransition()))
+
+ verify(desksOrganizer).deactivateDesk(any(), eq(previouslyActiveDeskId))
+ verify(desksTransitionsObserver)
+ .addPendingTransition(
+ argThat {
+ this is DeskTransition.DeactivateDesk &&
+ this.token == transition &&
+ this.deskId == previouslyActiveDeskId
+ }
+ )
+ }
+
+ @Test
@EnableFlags(
Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION,
Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 077b355..82373ff 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -571,8 +571,7 @@
}
@Test
- @DisableFlags({Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
- Flags.FLAG_ENABLE_INPUT_LAYER_TRANSITION_FIX})
+ @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
public void testRequestEnterSplit_didNotEnterSplitSelect_doesNotApplyTransaction() {
final WindowContainerTransaction wct = new WindowContainerTransaction();
mStageCoordinator.registerSplitSelectListener(
@@ -629,9 +628,9 @@
private Transitions createTestTransitions() {
ShellInit shellInit = new ShellInit(mMainExecutor);
final Transitions t = new Transitions(mContext, shellInit, mock(ShellController.class),
- mTaskOrganizer, mTransactionPool, mock(DisplayController.class), mMainExecutor,
- mMainHandler, mAnimExecutor, mock(HomeTransitionObserver.class),
- mock(FocusTransitionObserver.class));
+ mTaskOrganizer, mTransactionPool, mock(DisplayController.class),
+ mDisplayInsetsController, mMainExecutor, mMainHandler, mAnimExecutor,
+ mock(HomeTransitionObserver.class), mock(FocusTransitionObserver.class));
shellInit.init();
return t;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
index 3a455ba..f11839a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
@@ -24,8 +24,12 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assume.assumeTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -77,16 +81,15 @@
@Mock
TaskViewTaskController mTaskViewTaskController;
@Mock
- ActivityManager.RunningTaskInfo mTaskInfo;
- @Mock
WindowContainerToken mToken;
@Mock
ShellTaskOrganizer mOrganizer;
@Mock
SyncTransactionQueue mSyncQueue;
- Executor mExecutor = command -> command.run();
+ Executor mExecutor = Runnable::run;
+ ActivityManager.RunningTaskInfo mTaskInfo;
TaskViewRepository mTaskViewRepository;
TaskViewTransitions mTaskViewTransitions;
@@ -305,4 +308,66 @@
verify(mTaskViewTaskController).setTaskNotFound();
}
+
+ @Test
+ public void updateBoundsForUnfold_taskNotFound_doesNothing() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+ ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+ taskInfo.token = mock(WindowContainerToken.class);
+ taskInfo.taskId = 666;
+ Rect bounds = new Rect(100, 50, 200, 250);
+ SurfaceControl.Transaction startTransaction = mock(SurfaceControl.Transaction.class);
+ SurfaceControl.Transaction finishTransaction = mock(SurfaceControl.Transaction.class);
+ assertThat(
+ mTaskViewTransitions.updateBoundsForUnfold(bounds, startTransaction,
+ finishTransaction, taskInfo, mock(SurfaceControl.class)))
+ .isFalse();
+
+ verify(startTransaction, never()).reparent(any(), any());
+ }
+
+ @Test
+ public void updateBoundsForUnfold_noPendingTransition_doesNothing() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+ Rect bounds = new Rect(100, 50, 200, 250);
+ mTaskViewTransitions.setTaskBounds(mTaskViewTaskController, bounds);
+ assertThat(mTaskViewTransitions.hasPending()).isFalse();
+
+ SurfaceControl.Transaction startTransaction = mock(SurfaceControl.Transaction.class);
+ SurfaceControl.Transaction finishTransaction = mock(SurfaceControl.Transaction.class);
+ assertThat(
+ mTaskViewTransitions.updateBoundsForUnfold(bounds, startTransaction,
+ finishTransaction, mTaskInfo, mock(SurfaceControl.class)))
+ .isFalse();
+ verify(startTransaction, never()).reparent(any(), any());
+ }
+
+ @Test
+ public void updateBoundsForUnfold() {
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+ Rect bounds = new Rect(100, 50, 200, 250);
+ mTaskViewTransitions.updateVisibilityState(mTaskViewTaskController, /* visible= */ true);
+ mTaskViewTransitions.setTaskBounds(mTaskViewTaskController, bounds);
+ assertThat(mTaskViewTransitions.hasPending()).isTrue();
+
+ SurfaceControl.Transaction startTransaction = createMockTransaction();
+ SurfaceControl.Transaction finishTransaction = createMockTransaction();
+ assertThat(
+ mTaskViewTransitions.updateBoundsForUnfold(bounds, startTransaction,
+ finishTransaction, mTaskInfo, mock(SurfaceControl.class)))
+ .isTrue();
+ assertThat(mTaskViewRepository.byTaskView(mTaskViewTaskController).mBounds)
+ .isEqualTo(bounds);
+ }
+
+ private SurfaceControl.Transaction createMockTransaction() {
+ SurfaceControl.Transaction transaction = mock(SurfaceControl.Transaction.class);
+ when(transaction.reparent(any(), any())).thenReturn(transaction);
+ when(transaction.setPosition(any(), anyFloat(), anyFloat())).thenReturn(transaction);
+ when(transaction.setWindowCrop(any(), anyInt(), anyInt())).thenReturn(transaction);
+ return transaction;
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java
index 18fdbef..6996d44 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java
@@ -53,6 +53,7 @@
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.sysui.ShellInit;
@@ -78,6 +79,8 @@
InstrumentationRegistry.getInstrumentation().getTargetContext();
private final DisplayController mDisplayController = mock(DisplayController.class);
+ private final DisplayInsetsController mDisplayInsetsController =
+ mock(DisplayInsetsController.class);
private final TransactionPool mTransactionPool = new MockTransactionPool();
private final TestShellExecutor mMainExecutor = new TestShellExecutor();
private final TestShellExecutor mAnimExecutor = new TestShellExecutor();
@@ -95,7 +98,7 @@
mContext,
mShellInit);
mTransitionHandler = new DefaultTransitionHandler(
- mContext, mShellInit, mDisplayController,
+ mContext, mShellInit, mDisplayController, mDisplayInsetsController,
mTransactionPool, mMainExecutor, mMainHandler, mAnimExecutor,
mRootTaskDisplayAreaOrganizer, mock(InteractionJankMonitor.class));
mShellInit.init();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
index 55bff09..52634c0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
@@ -61,6 +61,7 @@
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.shared.IHomeTransitionListener;
import com.android.wm.shell.shared.TransactionPool;
@@ -88,6 +89,8 @@
private final TestShellExecutor mMainExecutor = new TestShellExecutor();
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
private final DisplayController mDisplayController = mock(DisplayController.class);
+ private final DisplayInsetsController mDisplayInsetsController =
+ mock(DisplayInsetsController.class);
private IHomeTransitionListener mListener;
private Transitions mTransition;
@@ -98,10 +101,11 @@
mListener = mock(IHomeTransitionListener.class);
when(mListener.asBinder()).thenReturn(mock(IBinder.class));
- mHomeTransitionObserver = new HomeTransitionObserver(mContext, mMainExecutor);
+ mHomeTransitionObserver = new HomeTransitionObserver(mContext, mMainExecutor,
+ mDisplayInsetsController, mock(ShellInit.class));
mTransition = new Transitions(mContext, mock(ShellInit.class), mock(ShellController.class),
- mOrganizer, mTransactionPool, mDisplayController, mMainExecutor,
- mMainHandler, mAnimExecutor, mHomeTransitionObserver,
+ mOrganizer, mTransactionPool, mDisplayController, mDisplayInsetsController,
+ mMainExecutor, mMainHandler, mAnimExecutor, mHomeTransitionObserver,
mock(FocusTransitionObserver.class));
mHomeTransitionObserver.setHomeTransitionListener(mTransition, mListener);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 9849b11..44bb215 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -107,6 +107,7 @@
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.recents.IRecentsAnimationRunner;
@@ -145,6 +146,8 @@
private final ShellExecutor mAnimExecutor = new TestShellExecutor();
private final TestTransitionHandler mDefaultHandler = new TestTransitionHandler();
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+ private final DisplayInsetsController mDisplayInsets =
+ mock(DisplayInsetsController.class);
@Before
public void setUp() {
@@ -156,9 +159,9 @@
public void instantiate_addInitCallback() {
ShellInit shellInit = mock(ShellInit.class);
final Transitions t = new Transitions(mContext, shellInit, mock(ShellController.class),
- mOrganizer, mTransactionPool, createTestDisplayController(), mMainExecutor,
- mMainHandler, mAnimExecutor, mock(HomeTransitionObserver.class),
- mock(FocusTransitionObserver.class));
+ mOrganizer, mTransactionPool, createTestDisplayController(), mDisplayInsets,
+ mMainExecutor, mMainHandler, mAnimExecutor,
+ mock(HomeTransitionObserver.class), mock(FocusTransitionObserver.class));
// One from Transitions, one from RootTaskDisplayAreaOrganizer
verify(shellInit).addInitCallback(any(), eq(t));
verify(shellInit).addInitCallback(any(), isA(RootTaskDisplayAreaOrganizer.class));
@@ -169,9 +172,9 @@
ShellInit shellInit = new ShellInit(mMainExecutor);
ShellController shellController = mock(ShellController.class);
final Transitions t = new Transitions(mContext, shellInit, shellController,
- mOrganizer, mTransactionPool, createTestDisplayController(), mMainExecutor,
- mMainHandler, mAnimExecutor, mock(HomeTransitionObserver.class),
- mock(FocusTransitionObserver.class));
+ mOrganizer, mTransactionPool, createTestDisplayController(), mDisplayInsets,
+ mMainExecutor, mMainHandler, mAnimExecutor,
+ mock(HomeTransitionObserver.class), mock(FocusTransitionObserver.class));
shellInit.init();
verify(shellController, times(1)).addExternalInterface(
eq(IShellTransitions.DESCRIPTOR), any(), any());
@@ -1314,8 +1317,9 @@
ShellInit shellInit = new ShellInit(mMainExecutor);
final Transitions transitions =
new Transitions(mContext, shellInit, mock(ShellController.class), mOrganizer,
- mTransactionPool, createTestDisplayController(), mMainExecutor,
- mMainHandler, mAnimExecutor, mock(HomeTransitionObserver.class),
+ mTransactionPool, createTestDisplayController(), mDisplayInsets,
+ mMainExecutor, mMainHandler, mAnimExecutor,
+ mock(HomeTransitionObserver.class),
mock(FocusTransitionObserver.class));
final RecentTasksController mockRecentsTaskController = mock(RecentTasksController.class);
doReturn(mContext).when(mockRecentsTaskController).getContext();
@@ -1909,8 +1913,8 @@
private Transitions createTestTransitions() {
ShellInit shellInit = new ShellInit(mMainExecutor);
final Transitions t = new Transitions(mContext, shellInit, mock(ShellController.class),
- mOrganizer, mTransactionPool, createTestDisplayController(), mMainExecutor,
- mMainHandler, mAnimExecutor, mock(HomeTransitionObserver.class),
+ mOrganizer, mTransactionPool, createTestDisplayController(), mDisplayInsets,
+ mMainExecutor, mMainHandler, mAnimExecutor, mock(HomeTransitionObserver.class),
mock(FocusTransitionObserver.class));
shellInit.init();
return t;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
index aad18cb..e28d0ac 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
@@ -60,6 +60,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.Executor;
public class UnfoldTransitionHandlerTest extends ShellTestCase {
@@ -98,7 +99,8 @@
mTransactionPool,
executor,
mHandler,
- mTransitions
+ mTransitions,
+ /* bubbleTaskUnfoldTransitionMerger= */ Optional.empty()
);
shellInit.init();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelAppHandleOnlyTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelAppHandleOnlyTest.kt
index b1f9241..067dcec 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelAppHandleOnlyTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelAppHandleOnlyTest.kt
@@ -28,7 +28,6 @@
import android.view.Display
import android.view.Display.DEFAULT_DISPLAY
import android.view.SurfaceControl
-import android.view.WindowManager.TRANSIT_CHANGE
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean
import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
@@ -110,7 +109,7 @@
onTaskOpening(task, taskSurface)
assertTrue(windowDecorByTaskIdSpy.contains(task.taskId))
task.setActivityType(ACTIVITY_TYPE_UNDEFINED)
- onTaskChanging(task, taskSurface, TRANSIT_CHANGE)
+ onTaskChanging(task, taskSurface)
assertFalse(windowDecorByTaskIdSpy.contains(task.taskId))
verify(decoration).close()
@@ -166,7 +165,7 @@
setLargeScreen(false)
setUpMockDecorationForTask(task)
- onTaskChanging(task, taskSurface, TRANSIT_CHANGE)
+ onTaskChanging(task, taskSurface)
assertFalse(windowDecorByTaskIdSpy.contains(task.taskId))
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index ad3426e..40aa41b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -51,7 +51,6 @@
import android.view.View
import android.view.ViewRootImpl
import android.view.WindowInsets.Type.statusBars
-import android.view.WindowManager.TRANSIT_CHANGE
import android.window.WindowContainerTransaction
import android.window.WindowContainerTransaction.HierarchyOp
import androidx.test.filters.SmallTest
@@ -135,7 +134,7 @@
task.setWindowingMode(WINDOWING_MODE_UNDEFINED)
task.setActivityType(ACTIVITY_TYPE_UNDEFINED)
- onTaskChanging(task, taskSurface, TRANSIT_CHANGE)
+ onTaskChanging(task, taskSurface)
assertFalse(windowDecorByTaskIdSpy.contains(task.taskId))
verify(decoration).close()
@@ -150,12 +149,12 @@
val taskSurface = SurfaceControl()
setUpMockDecorationForTask(task)
- onTaskChanging(task, taskSurface, TRANSIT_CHANGE)
+ onTaskChanging(task, taskSurface)
assertFalse(windowDecorByTaskIdSpy.contains(task.taskId))
task.setWindowingMode(WINDOWING_MODE_FREEFORM)
task.setActivityType(ACTIVITY_TYPE_STANDARD)
- onTaskChanging(task, taskSurface, TRANSIT_CHANGE)
+ onTaskChanging(task, taskSurface)
assertTrue(windowDecorByTaskIdSpy.contains(task.taskId))
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
index 2126d1d..80dcd7d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
@@ -362,14 +362,12 @@
protected fun onTaskChanging(
task: RunningTaskInfo,
leash: SurfaceControl = SurfaceControl(),
- changeMode: Int
) {
desktopModeWindowDecorViewModel.onTaskChanging(
task,
leash,
StubTransaction(),
StubTransaction(),
- changeMode
)
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index 0908f56e1..a0171ea 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -174,8 +174,6 @@
private static final boolean DEFAULT_HAS_GLOBAL_FOCUS = true;
private static final boolean DEFAULT_SHOULD_IGNORE_CORNER_RADIUS = false;
private static final boolean DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS = false;
- private static final boolean DEFAULT_IS_RECENTS_TRANSITION_RUNNING = false;
- private static final boolean DEFAULT_IS_MOVING_TO_BACK = false;
@Mock
@@ -443,9 +441,7 @@
DEFAULT_HAS_GLOBAL_FOCUS,
mExclusionRegion,
/* shouldIgnoreCornerRadius= */ true,
- DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
- DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
- DEFAULT_IS_MOVING_TO_BACK);
+ DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS);
assertThat(relayoutParams.mCornerRadius).isEqualTo(INVALID_CORNER_RADIUS);
}
@@ -544,9 +540,7 @@
DEFAULT_HAS_GLOBAL_FOCUS,
mExclusionRegion,
/* shouldIgnoreCornerRadius= */ true,
- DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
- DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
- DEFAULT_IS_MOVING_TO_BACK);
+ DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS);
assertThat(relayoutParams.mCornerRadiusId).isEqualTo(Resources.ID_NULL);
}
@@ -748,9 +742,7 @@
DEFAULT_HAS_GLOBAL_FOCUS,
mExclusionRegion,
DEFAULT_SHOULD_IGNORE_CORNER_RADIUS,
- /* shouldExcludeCaptionFromAppBounds */ true,
- DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
- DEFAULT_IS_MOVING_TO_BACK);
+ /* shouldExcludeCaptionFromAppBounds */ true);
// Force consuming flags are disabled.
assertThat((relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING) == 0).isTrue();
@@ -785,9 +777,7 @@
DEFAULT_HAS_GLOBAL_FOCUS,
mExclusionRegion,
DEFAULT_SHOULD_IGNORE_CORNER_RADIUS,
- DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
- DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
- DEFAULT_IS_MOVING_TO_BACK);
+ DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS);
assertThat((relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING) != 0).isTrue();
assertThat(
@@ -866,9 +856,7 @@
DEFAULT_HAS_GLOBAL_FOCUS,
mExclusionRegion,
DEFAULT_SHOULD_IGNORE_CORNER_RADIUS,
- DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
- DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
- DEFAULT_IS_MOVING_TO_BACK);
+ DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS);
// Takes status bar inset as padding, ignores caption bar inset.
assertThat(relayoutParams.mCaptionTopPadding).isEqualTo(50);
@@ -896,9 +884,7 @@
DEFAULT_HAS_GLOBAL_FOCUS,
mExclusionRegion,
DEFAULT_SHOULD_IGNORE_CORNER_RADIUS,
- DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
- DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
- DEFAULT_IS_MOVING_TO_BACK);
+ DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS);
assertThat(relayoutParams.mIsInsetSource).isFalse();
}
@@ -925,9 +911,7 @@
DEFAULT_HAS_GLOBAL_FOCUS,
mExclusionRegion,
DEFAULT_SHOULD_IGNORE_CORNER_RADIUS,
- DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
- DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
- DEFAULT_IS_MOVING_TO_BACK);
+ DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS);
// Header is always shown because it's assumed the status bar is always visible.
assertThat(relayoutParams.mIsCaptionVisible).isTrue();
@@ -954,9 +938,7 @@
DEFAULT_HAS_GLOBAL_FOCUS,
mExclusionRegion,
DEFAULT_SHOULD_IGNORE_CORNER_RADIUS,
- DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
- DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
- DEFAULT_IS_MOVING_TO_BACK);
+ DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS);
assertThat(relayoutParams.mIsCaptionVisible).isTrue();
}
@@ -982,9 +964,7 @@
DEFAULT_HAS_GLOBAL_FOCUS,
mExclusionRegion,
DEFAULT_SHOULD_IGNORE_CORNER_RADIUS,
- DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
- DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
- DEFAULT_IS_MOVING_TO_BACK);
+ DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS);
assertThat(relayoutParams.mIsCaptionVisible).isFalse();
}
@@ -1010,9 +990,7 @@
DEFAULT_HAS_GLOBAL_FOCUS,
mExclusionRegion,
DEFAULT_SHOULD_IGNORE_CORNER_RADIUS,
- DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
- DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
- DEFAULT_IS_MOVING_TO_BACK);
+ DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS);
assertThat(relayoutParams.mIsCaptionVisible).isFalse();
}
@@ -1039,9 +1017,7 @@
DEFAULT_HAS_GLOBAL_FOCUS,
mExclusionRegion,
DEFAULT_SHOULD_IGNORE_CORNER_RADIUS,
- DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
- DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
- DEFAULT_IS_MOVING_TO_BACK);
+ DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS);
assertThat(relayoutParams.mIsCaptionVisible).isTrue();
@@ -1060,9 +1036,7 @@
DEFAULT_HAS_GLOBAL_FOCUS,
mExclusionRegion,
DEFAULT_SHOULD_IGNORE_CORNER_RADIUS,
- DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
- DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
- DEFAULT_IS_MOVING_TO_BACK);
+ DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS);
assertThat(relayoutParams.mIsCaptionVisible).isFalse();
}
@@ -1089,9 +1063,7 @@
DEFAULT_HAS_GLOBAL_FOCUS,
mExclusionRegion,
DEFAULT_SHOULD_IGNORE_CORNER_RADIUS,
- DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
- DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
- DEFAULT_IS_MOVING_TO_BACK);
+ DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS);
assertThat(relayoutParams.mIsCaptionVisible).isTrue();
}
@@ -1118,9 +1090,7 @@
DEFAULT_HAS_GLOBAL_FOCUS,
mExclusionRegion,
DEFAULT_SHOULD_IGNORE_CORNER_RADIUS,
- DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
- DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
- DEFAULT_IS_MOVING_TO_BACK);
+ DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS);
assertThat(relayoutParams.mIsCaptionVisible).isFalse();
}
@@ -1151,65 +1121,6 @@
assertThat(relayoutParams.mAsyncViewHost).isFalse();
}
-
- @Test
- @EnableFlags(Flags.FLAG_ENABLE_INPUT_LAYER_TRANSITION_FIX)
- public void updateRelayoutParams_handle_movingToBack_captionNotVisible() {
- final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
- taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- final RelayoutParams relayoutParams = new RelayoutParams();
-
- DesktopModeWindowDecoration.updateRelayoutParams(
- relayoutParams,
- mTestableContext,
- taskInfo,
- mMockSplitScreenController,
- DEFAULT_APPLY_START_TRANSACTION_ON_DRAW,
- DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP,
- DEFAULT_IS_STATUSBAR_VISIBLE,
- DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED,
- DEFAULT_IS_IN_FULL_IMMERSIVE_MODE,
- DEFAULT_IS_DRAGGING,
- new InsetsState(),
- DEFAULT_HAS_GLOBAL_FOCUS,
- mExclusionRegion,
- DEFAULT_SHOULD_IGNORE_CORNER_RADIUS,
- DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
- DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
- /* isMovingToBack= */ true);
-
- assertThat(relayoutParams.mIsCaptionVisible).isFalse();
- }
-
- @Test
- @EnableFlags(Flags.FLAG_ENABLE_INPUT_LAYER_TRANSITION_FIX)
- public void updateRelayoutParams_handle_inRecentsTransition_captionNotVisible() {
- final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
- taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- final RelayoutParams relayoutParams = new RelayoutParams();
-
- DesktopModeWindowDecoration.updateRelayoutParams(
- relayoutParams,
- mTestableContext,
- taskInfo,
- mMockSplitScreenController,
- DEFAULT_APPLY_START_TRANSACTION_ON_DRAW,
- DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP,
- DEFAULT_IS_STATUSBAR_VISIBLE,
- DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED,
- DEFAULT_IS_IN_FULL_IMMERSIVE_MODE,
- DEFAULT_IS_DRAGGING,
- new InsetsState(),
- DEFAULT_HAS_GLOBAL_FOCUS,
- mExclusionRegion,
- DEFAULT_SHOULD_IGNORE_CORNER_RADIUS,
- DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
- /* isRecentsTransitionRunning= */ true,
- DEFAULT_IS_MOVING_TO_BACK);
-
- assertThat(relayoutParams.mIsCaptionVisible).isFalse();
- }
-
@Test
public void relayout_fullscreenTask_appliesTransactionImmediately() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
@@ -1846,9 +1757,7 @@
DEFAULT_HAS_GLOBAL_FOCUS,
mExclusionRegion,
DEFAULT_SHOULD_IGNORE_CORNER_RADIUS,
- DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS,
- DEFAULT_IS_RECENTS_TRANSITION_RUNNING,
- DEFAULT_IS_MOVING_TO_BACK);
+ DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS);
}
private DesktopModeWindowDecoration createWindowDecoration(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeInputListenerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeInputListenerTest.kt
index 3600997..95ae73c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeInputListenerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeInputListenerTest.kt
@@ -40,6 +40,7 @@
import com.google.common.truth.Truth.assertThat
import java.util.function.Consumer
import java.util.function.Supplier
+import kotlin.test.assertNotNull
import org.junit.After
import org.junit.Test
import org.junit.runner.RunWith
@@ -69,9 +70,12 @@
private val sinkInputChannel = mock<InputChannel>()
private val decorationSurface = SurfaceControl.Builder().setName("decoration surface").build()
private val createdSurfaces = ArrayList<SurfaceControl>()
+ private val removedSurfaces = ArrayList<SurfaceControl>()
@After
fun tearDown() {
+ createdSurfaces.clear()
+ removedSurfaces.clear()
decorationSurface.release()
}
@@ -217,6 +221,19 @@
assertThat(createdSurfaces[1].isValid).isFalse()
}
+ @Test
+ fun testClose_releasesDecorationSurfaceWithoutRemoval() {
+ val inputListener = create()
+ testBgExecutor.flushAll()
+ inputListener.close()
+ testMainExecutor.flushAll()
+ testBgExecutor.flushAll()
+
+ val decorationSurface = assertNotNull(createdSurfaces[0])
+ assertThat(decorationSurface.isValid).isFalse()
+ assertThat(removedSurfaces.contains(decorationSurface)).isFalse()
+ }
+
private fun verifyNoInputChannelGrantRequests() {
verify(mockWindowSession, never())
.grantInputChannel(
@@ -258,7 +275,10 @@
{
object : StubTransaction() {
override fun remove(sc: SurfaceControl): SurfaceControl.Transaction {
- return super.remove(sc).also { sc.release() }
+ return super.remove(sc).also {
+ sc.release()
+ removedSurfaces.add(sc)
+ }
}
}
},
diff --git a/libs/androidfw/LocaleDataLookup.cpp b/libs/androidfw/LocaleDataLookup.cpp
index 9aacdcb..ed64582 100644
--- a/libs/androidfw/LocaleDataLookup.cpp
+++ b/libs/androidfw/LocaleDataLookup.cpp
@@ -5774,7 +5774,6 @@
case 0xD2120000u: // squ -> Latn
case 0x73724D45u: // sr-ME -> Latn
case 0x7372524Fu: // sr-RO -> Latn
- case 0x73725255u: // sr-RU -> Latn
case 0x73725452u: // sr-TR -> Latn
case 0x82320000u: // sra -> Latn
case 0x92320000u: // sre -> Latn
@@ -7265,7 +7264,6 @@
return SCRIPT_CODES[73u];
case 0x8ACD0000u: // nwc -> Newa
return SCRIPT_CODES[74u];
- case 0xB40C474Eu: // man-GN -> Nkoo
case 0xBA0D0000u: // nqo -> Nkoo
return SCRIPT_CODES[75u];
case 0xDCF90000u: // zhx -> Nshu
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 3ef9708..46dcc1f 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -164,8 +164,13 @@
android::base::ReadFileToString("/proc/self/cmdline", &temp);
return temp;
}();
- return std::format("bitmap/{}-id_{}-{}x{}-size_{}-{}",
- tag, bitmapId, width, height, size, sCmdline);
+ /* counter is to ensure the uniqueness of the ashmem filename,
+ * e.g. a bitmap with same mId could be sent multiple times, an
+ * ashmem region is created each time
+ */
+ static std::atomic<uint32_t> counter{0};
+ return std::format("bitmap/{}_{}_{}x{}_size-{}_id-{}_{}",
+ tag, counter.fetch_add(1), width, height, size, bitmapId, sCmdline);
}
sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap) {
diff --git a/libs/hwui/jni/GIFMovie.cpp b/libs/hwui/jni/GIFMovie.cpp
index 476b6fd..6c82aa1 100644
--- a/libs/hwui/jni/GIFMovie.cpp
+++ b/libs/hwui/jni/GIFMovie.cpp
@@ -63,7 +63,7 @@
}
fCurrIndex = -1;
fLastDrawIndex = -1;
- fPaintingColor = SK_AlphaTRANSPARENT;
+ fPaintingColor = SkPackARGB32(0, 0, 0, 0);
}
GIFMovie::~GIFMovie()
@@ -127,7 +127,7 @@
for (; width > 0; width--, src++, dst++) {
if (*src != transparent && *src < cmap->ColorCount) {
const GifColorType& col = cmap->Colors[*src];
- *dst = SkColorSetRGB(col.Red, col.Green, col.Blue);
+ *dst = SkPackARGB32(0xFF, col.Red, col.Green, col.Blue);
}
}
}
@@ -395,10 +395,10 @@
lastIndex = fGIF->ImageCount - 1;
}
- SkColor bgColor = SK_ColorTRANSPARENT;
+ SkColor bgColor = SkPackARGB32(0, 0, 0, 0);
if (gif->SColorMap != nullptr && gif->SBackGroundColor < gif->SColorMap->ColorCount) {
const GifColorType& col = gif->SColorMap->Colors[gif->SBackGroundColor];
- bgColor = SkColorSetRGB(col.Red, col.Green, col.Blue);
+ bgColor = SkColorSetARGB(0xFF, col.Red, col.Green, col.Blue);
}
// draw each frames - not intelligent way
@@ -411,7 +411,7 @@
if (!trans && gif->SColorMap != nullptr) {
fPaintingColor = bgColor;
} else {
- fPaintingColor = SK_ColorTRANSPARENT;
+ fPaintingColor = SkColorSetARGB(0, 0, 0, 0);
}
bm->eraseColor(fPaintingColor);
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 0cd9c53..e5a6260 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -44,7 +44,7 @@
namespace renderthread {
// Not all of these are strictly required, but are all enabled if present.
-static std::array<std::string_view, 23> sEnableExtensions{
+static std::array<std::string_view, 25> sEnableExtensions{
VK_KHR_BIND_MEMORY_2_EXTENSION_NAME,
VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
@@ -68,6 +68,8 @@
VK_EXT_GLOBAL_PRIORITY_QUERY_EXTENSION_NAME,
VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME,
VK_EXT_DEVICE_FAULT_EXTENSION_NAME,
+ VK_EXT_FRAME_BOUNDARY_EXTENSION_NAME,
+ VK_ANDROID_FRAME_BOUNDARY_EXTENSION_NAME,
};
static bool shouldEnableExtension(const std::string_view& extension) {
@@ -746,7 +748,14 @@
ALOGE_IF(!context, "Surface is not backed by gpu");
GrSemaphoresSubmitted submitted = context->flush(
surface, SkSurfaces::BackendSurfaceAccess::kPresent, flushInfo);
- context->submit();
+
+ static uint64_t currentFrameID = 0;
+ GrSubmitInfo submitInfo;
+ if (!mFrameBoundaryANDROID) {
+ submitInfo.fMarkBoundary = GrMarkFrameBoundary::kYes;
+ submitInfo.fFrameID = currentFrameID++;
+ }
+ context->submit(submitInfo);
VkDrawResult drawResult{
.submissionTime = systemTime(),
};
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index a593ec6..744211e 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -30,14 +30,10 @@
// VK_ANDROID_frame_boundary is a bespoke extension defined by AGI
// (https://github.com/google/agi) to enable profiling of apps rendering via
// HWUI. This extension is not defined in Khronos, hence the need to declare it
-// manually here. There's a superseding extension (VK_EXT_frame_boundary) being
-// discussed in Khronos, but in the meantime we use the bespoke
-// VK_ANDROID_frame_boundary. This is a device extension that is implemented by
+// manually here. There's an extension (VK_EXT_frame_boundary) which we will use
+// instead if available. This is a device extension that is implemented by
// AGI's Vulkan capture layer, such that it is only supported by devices when
// AGI is doing a capture of the app.
-//
-// TODO(b/182165045): use the Khronos blessed VK_EXT_frame_boudary once it has
-// landed in the spec.
typedef void(VKAPI_PTR* PFN_vkFrameBoundaryANDROID)(VkDevice device, VkSemaphore semaphore,
VkImage image);
#define VK_ANDROID_FRAME_BOUNDARY_EXTENSION_NAME "VK_ANDROID_frame_boundary"
diff --git a/location/api/system-current.txt b/location/api/system-current.txt
index eb19ba8..4798474 100644
--- a/location/api/system-current.txt
+++ b/location/api/system-current.txt
@@ -96,8 +96,8 @@
public static final class BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime implements android.os.Parcelable {
method public int describeContents();
+ method @IntRange(from=0, to=31) public int getAode();
method @IntRange(from=0) public int getBeidouWeekNumber();
- method @IntRange(from=0, to=31) public int getIode();
method @IntRange(from=0, to=604792) public int getToeSeconds();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.location.BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime> CREATOR;
@@ -106,8 +106,8 @@
public static final class BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime.Builder {
ctor public BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime.Builder();
method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime build();
+ method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime.Builder setAode(int);
method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime.Builder setBeidouWeekNumber(@IntRange(from=0) int);
- method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime.Builder setIode(int);
method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime.Builder setToeSeconds(@IntRange(from=0, to=604792) int);
}
@@ -177,7 +177,7 @@
method public int describeContents();
method @Nullable public android.location.GnssAlmanac getAlmanac();
method @Nullable public android.location.AuxiliaryInformation getAuxiliaryInformation();
- method @Nullable public android.location.KlobucharIonosphericModel getIonosphericModel();
+ method @Nullable public android.location.GalileoIonosphericModel getIonosphericModel();
method @Nullable public android.location.LeapSecondsModel getLeapSecondsModel();
method @NonNull public java.util.List<android.location.RealTimeIntegrityModel> getRealTimeIntegrityModels();
method @NonNull public java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections> getSatelliteCorrections();
@@ -193,7 +193,7 @@
method @NonNull public android.location.GalileoAssistance build();
method @NonNull public android.location.GalileoAssistance.Builder setAlmanac(@Nullable android.location.GnssAlmanac);
method @NonNull public android.location.GalileoAssistance.Builder setAuxiliaryInformation(@Nullable android.location.AuxiliaryInformation);
- method @NonNull public android.location.GalileoAssistance.Builder setIonosphericModel(@Nullable android.location.KlobucharIonosphericModel);
+ method @NonNull public android.location.GalileoAssistance.Builder setIonosphericModel(@Nullable android.location.GalileoIonosphericModel);
method @NonNull public android.location.GalileoAssistance.Builder setLeapSecondsModel(@Nullable android.location.LeapSecondsModel);
method @NonNull public android.location.GalileoAssistance.Builder setRealTimeIntegrityModels(@NonNull java.util.List<android.location.RealTimeIntegrityModel>);
method @NonNull public android.location.GalileoAssistance.Builder setSatelliteCorrections(@NonNull java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections>);
diff --git a/location/java/android/location/BeidouSatelliteEphemeris.java b/location/java/android/location/BeidouSatelliteEphemeris.java
index 3382c20..dc5e8b8 100644
--- a/location/java/android/location/BeidouSatelliteEphemeris.java
+++ b/location/java/android/location/BeidouSatelliteEphemeris.java
@@ -527,7 +527,7 @@
*
* <p>This is defined in BDS-SIS-ICD-B1I-3.0 section 5.2.4.11 Table 5-8.
*/
- private final int mIode;
+ private final int mAode;
/** Beidou week number without rollover */
private final int mBeidouWeekNumber;
@@ -540,18 +540,18 @@
private final int mToeSeconds;
private BeidouSatelliteEphemerisTime(Builder builder) {
- Preconditions.checkArgumentInRange(builder.mIode, 0, 31, "Iode");
+ Preconditions.checkArgumentInRange(builder.mAode, 0, 31, "Aode");
Preconditions.checkArgument(builder.mBeidouWeekNumber >= 0);
Preconditions.checkArgumentInRange(builder.mToeSeconds, 0, 604792, "ToeSeconds");
- mIode = builder.mIode;
+ mAode = builder.mAode;
mBeidouWeekNumber = builder.mBeidouWeekNumber;
mToeSeconds = builder.mToeSeconds;
}
/** Returns the AODE Age of Data, Ephemeris. */
@IntRange(from = 0, to = 31)
- public int getIode() {
- return mIode;
+ public int getAode() {
+ return mAode;
}
/** Returns the Beidou week number without rollover . */
@@ -573,7 +573,7 @@
public BeidouSatelliteEphemerisTime createFromParcel(Parcel in) {
final BeidouSatelliteEphemerisTime.Builder beidouSatelliteEphemerisTime =
new Builder()
- .setIode(in.readInt())
+ .setAode(in.readInt())
.setBeidouWeekNumber(in.readInt())
.setToeSeconds(in.readInt());
return beidouSatelliteEphemerisTime.build();
@@ -592,7 +592,7 @@
@Override
public void writeToParcel(@NonNull Parcel parcel, int flags) {
- parcel.writeInt(mIode);
+ parcel.writeInt(mAode);
parcel.writeInt(mBeidouWeekNumber);
parcel.writeInt(mToeSeconds);
}
@@ -600,7 +600,7 @@
@Override
public String toString() {
StringBuilder builder = new StringBuilder("BeidouSatelliteEphemerisTime[");
- builder.append("iode = ").append(mIode);
+ builder.append("aode = ").append(mAode);
builder.append(", beidouWeekNumber = ").append(mBeidouWeekNumber);
builder.append(", toeSeconds = ").append(mToeSeconds);
builder.append("]");
@@ -609,14 +609,14 @@
/** Builder for {@link BeidouSatelliteEphemerisTime} */
public static final class Builder {
- private int mIode;
+ private int mAode;
private int mBeidouWeekNumber;
private int mToeSeconds;
/** Sets the AODE Age of Data, Ephemeris. */
@NonNull
- public Builder setIode(int iode) {
- mIode = iode;
+ public Builder setAode(int iode) {
+ mAode = iode;
return this;
}
diff --git a/location/java/android/location/GalileoAssistance.java b/location/java/android/location/GalileoAssistance.java
index 8a09e66..7f81ccd 100644
--- a/location/java/android/location/GalileoAssistance.java
+++ b/location/java/android/location/GalileoAssistance.java
@@ -41,8 +41,8 @@
/** The Galileo almanac. */
@Nullable private final GnssAlmanac mAlmanac;
- /** The Klobuchar ionospheric model. */
- @Nullable private final KlobucharIonosphericModel mIonosphericModel;
+ /** The Galileo ionospheric model. */
+ @Nullable private final GalileoIonosphericModel mIonosphericModel;
/** The UTC model. */
@Nullable private final UtcModel mUtcModel;
@@ -102,9 +102,9 @@
return mAlmanac;
}
- /** Returns the Klobuchar ionospheric model. */
+ /** Returns the Galileo ionospheric model. */
@Nullable
- public KlobucharIonosphericModel getIonosphericModel() {
+ public GalileoIonosphericModel getIonosphericModel() {
return mIonosphericModel;
}
@@ -192,7 +192,7 @@
return new GalileoAssistance.Builder()
.setAlmanac(in.readTypedObject(GnssAlmanac.CREATOR))
.setIonosphericModel(
- in.readTypedObject(KlobucharIonosphericModel.CREATOR))
+ in.readTypedObject(GalileoIonosphericModel.CREATOR))
.setUtcModel(in.readTypedObject(UtcModel.CREATOR))
.setLeapSecondsModel(in.readTypedObject(LeapSecondsModel.CREATOR))
.setAuxiliaryInformation(
@@ -216,7 +216,7 @@
/** Builder for {@link GalileoAssistance}. */
public static final class Builder {
private GnssAlmanac mAlmanac;
- private KlobucharIonosphericModel mIonosphericModel;
+ private GalileoIonosphericModel mIonosphericModel;
private UtcModel mUtcModel;
private LeapSecondsModel mLeapSecondsModel;
private AuxiliaryInformation mAuxiliaryInformation;
@@ -232,9 +232,9 @@
return this;
}
- /** Sets the Klobuchar ionospheric model. */
+ /** Sets the Galileo ionospheric model. */
@NonNull
- public Builder setIonosphericModel(@Nullable KlobucharIonosphericModel ionosphericModel) {
+ public Builder setIonosphericModel(@Nullable GalileoIonosphericModel ionosphericModel) {
mIonosphericModel = ionosphericModel;
return this;
}
diff --git a/location/java/android/location/flags/location.aconfig b/location/java/android/location/flags/location.aconfig
index f26e72f..9cc58ae 100644
--- a/location/java/android/location/flags/location.aconfig
+++ b/location/java/android/location/flags/location.aconfig
@@ -205,3 +205,17 @@
bug: "209078566"
}
+flag {
+ name: "service_watcher_unstable_fallback"
+ namespace: "location"
+ description: "Flag for service watcher to fallback on an unstable service"
+ bug: "402997842"
+ is_fixed_read_only: true
+}
+
+flag {
+ name: "missing_attribution_tags_in_overlay"
+ namespace: "location"
+ description: "Adds missing attribution tags in the Fused and Gnss overlay"
+ bug: "403337028"
+}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index c505bce..b97b943 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -447,10 +447,8 @@
boolean isAudioServerRunning();
- @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
void registerAudioVolumeCallback(IAudioVolumeChangeDispatcher avc);
- @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
oneway void unregisterAudioVolumeCallback(IAudioVolumeChangeDispatcher avc);
int setUidDeviceAffinity(in IAudioPolicyCallback pcb, in int uid, in int[] deviceTypes,
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index c9ec31b..7221f1d 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -259,3 +259,10 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "enable_output_switcher_personal_audio_sharing"
+ namespace: "cross_device_experiences"
+ description: "Enables personal audio sharing in the output switcher."
+ bug: "385672684"
+}
\ No newline at end of file
diff --git a/media/tests/AudioPolicyTest/AndroidManifest.xml b/media/tests/AudioPolicyTest/AndroidManifest.xml
index 466da7e..5c911b1 100644
--- a/media/tests/AudioPolicyTest/AndroidManifest.xml
+++ b/media/tests/AudioPolicyTest/AndroidManifest.xml
@@ -19,7 +19,6 @@
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
- <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
<uses-permission android:name="android.permission.CHANGE_ACCESSIBILITY_VOLUME" />
diff --git a/media/tests/projection/Android.bp b/media/tests/projection/Android.bp
index 48621e4..0b02d3c 100644
--- a/media/tests/projection/Android.bp
+++ b/media/tests/projection/Android.bp
@@ -3,7 +3,7 @@
//########################################################################
package {
- default_team: "trendy_team_lse_desktop_os_experience",
+ default_team: "trendy_team_media_projection",
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java
index 964268e..518757d 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java
@@ -359,11 +359,7 @@
if (CompanionDeviceDiscoveryService.getScanResult().getValue().isEmpty()) {
// If the scan times out, do NOT close the activity automatically and let the
// user manually cancel the flow.
- synchronized (LOCK) {
- if (sDiscoveryStarted) {
- stopDiscovery();
- }
- }
+ stopDiscovery();
mTimeoutMessage.setText(getString(R.string.message_discovery_hard_timeout));
mTimeoutMessage.setVisibility(View.VISIBLE);
}
@@ -455,8 +451,14 @@
}
private void stopDiscovery() {
- if (mRequest != null && !mRequest.isSelfManaged()) {
- CompanionDeviceDiscoveryService.stop(this);
+ if (mRequest == null || mRequest.isSelfManaged()) {
+ return;
+ }
+
+ synchronized (LOCK) {
+ if (sDiscoveryStarted) {
+ CompanionDeviceDiscoveryService.stop(this);
+ }
}
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index 50a01b3..7b47945 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -136,7 +136,12 @@
intent.setAction(ACTION_START_DISCOVERY);
intent.putExtra(EXTRA_ASSOCIATION_REQUEST, associationRequest);
- context.startService(intent);
+ try {
+ context.startService(intent);
+ } catch (IllegalStateException e) {
+ Slog.e(TAG, "Failed to start discovery.", e);
+ return false;
+ }
return true;
}
@@ -144,7 +149,12 @@
static void stop(@NonNull Context context) {
final Intent intent = new Intent(context, CompanionDeviceDiscoveryService.class);
intent.setAction(ACTION_STOP_DISCOVERY);
- context.startService(intent);
+
+ try {
+ context.startService(intent);
+ } catch (IllegalStateException e) {
+ Slog.e(TAG, "Failed to stop discovery.", e);
+ }
}
static LiveData<List<DeviceFilterPair<?>>> getScanResult() {
diff --git a/packages/FusedLocation/AndroidManifest.xml b/packages/FusedLocation/AndroidManifest.xml
index 158c33a..56fe389 100644
--- a/packages/FusedLocation/AndroidManifest.xml
+++ b/packages/FusedLocation/AndroidManifest.xml
@@ -30,6 +30,9 @@
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
+ <attribution android:tag="FusedOverlayService" android:label="@string/fused_overlay_service"/>
+ <attribution android:tag="GnssOverlayService" android:label="@string/gnss_overlay_service"/>
+
<application
android:label="@string/app_label"
android:process="system"
diff --git a/packages/FusedLocation/res/values/strings.xml b/packages/FusedLocation/res/values/strings.xml
index 5b78e39..25e1fe7 100644
--- a/packages/FusedLocation/res/values/strings.xml
+++ b/packages/FusedLocation/res/values/strings.xml
@@ -2,4 +2,8 @@
<resources>
<!-- Name of the application. [CHAR LIMIT=35] -->
<string name="app_label">Fused Location</string>
+ <!-- Attribution for Fused Overlay Service. [CHAR LIMIT=NONE]-->
+ <string name="fused_overlay_service">Fused Overlay Service</string>
+ <!-- Attribution for GNSS Overlay Service. [CHAR LIMIT=NONE]-->
+ <string name="gnss_overlay_service">GNSS Overlay Service</string>
</resources>
diff --git a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
index a0e008c..78b2f7e 100644
--- a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
+++ b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
@@ -53,6 +53,7 @@
public class FusedLocationProvider extends LocationProviderBase {
private static final String TAG = "FusedLocationProvider";
+ private static final String ATTRIBUTION_TAG = "FusedOverlayService";
private static final ProviderProperties PROPERTIES = new ProviderProperties.Builder()
.setHasAltitudeSupport(true)
@@ -89,8 +90,12 @@
public FusedLocationProvider(Context context) {
super(context, TAG, PROPERTIES);
- mContext = context;
- mLocationManager = Objects.requireNonNull(context.getSystemService(LocationManager.class));
+ if (Flags.missingAttributionTagsInOverlay()) {
+ mContext = context.createAttributionContext(ATTRIBUTION_TAG);
+ } else {
+ mContext = context;
+ }
+ mLocationManager = Objects.requireNonNull(mContext.getSystemService(LocationManager.class));
mGpsListener = new ChildLocationListener(GPS_PROVIDER);
mNetworkListener = new ChildLocationListener(NETWORK_PROVIDER);
diff --git a/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationProvider.java b/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationProvider.java
index c6576e3..86bcd99 100644
--- a/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationProvider.java
+++ b/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationProvider.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import android.content.Context;
+import android.location.flags.Flags;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
@@ -41,6 +42,7 @@
public class GnssOverlayLocationProvider extends LocationProviderBase {
private static final String TAG = "GnssOverlay";
+ private static final String ATTRIBUTION_TAG = "GnssOverlayService";
private static final ProviderProperties PROPERTIES = new ProviderProperties.Builder()
.setHasAltitudeSupport(true)
@@ -87,7 +89,13 @@
public GnssOverlayLocationProvider(Context context) {
super(context, TAG, PROPERTIES);
- mLocationManager = context.getSystemService(LocationManager.class);
+
+ if (Flags.missingAttributionTagsInOverlay()) {
+ Context contextWithAttribution = context.createAttributionContext(ATTRIBUTION_TAG);
+ mLocationManager = contextWithAttribution.getSystemService(LocationManager.class);
+ } else {
+ mLocationManager = context.getSystemService(LocationManager.class);
+ }
}
void start() {
diff --git a/packages/InputDevices/res/raw/keyboard_layout_hungarian.kcm b/packages/InputDevices/res/raw/keyboard_layout_hungarian.kcm
index 6c947c7..455fb83 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_hungarian.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_hungarian.kcm
@@ -37,8 +37,8 @@
key 1 {
label: '1'
base: '1'
- shift: '!'
- ralt: '\u0303'
+ shift: '\''
+ ralt: '\u007e'
}
key 2 {
@@ -80,7 +80,7 @@
label: '7'
base: '7'
shift: '='
- ralt: '\u0300'
+ ralt: '`'
}
key 8 {
@@ -374,6 +374,7 @@
base: 'm'
shift, capslock: 'M'
shift+capslock: 'm'
+ ralt: '<'
}
key COMMA {
@@ -387,6 +388,7 @@
label: '.'
base: '.'
shift: ':'
+ ralt: '>'
}
key MINUS {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
index bcc737a..d05aaaa 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
@@ -52,8 +52,11 @@
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Arrays;
import java.util.Objects;
+import java.util.stream.Stream;
/**
* This is a utility class for defining some utility methods and constants
@@ -69,7 +72,8 @@
//intent attribute strings related to uninstall
public static final String INTENT_ATTR_PACKAGE_NAME=PREFIX+"PackageName";
private static final String DOWNLOADS_AUTHORITY = "downloads";
- private static final String SPLIT_BASE_APK_END_WITH = "base.apk";
+ private static final String SPLIT_BASE_APK_SUFFIX = "base.apk";
+ private static final String SPLIT_APK_SUFFIX = ".apk";
/**
* Utility method to get package information for a given {@link File}
@@ -77,11 +81,20 @@
@Nullable
public static PackageInfo getPackageInfo(Context context, File sourceFile, int flags) {
String filePath = sourceFile.getAbsolutePath();
- if (filePath.endsWith(SPLIT_BASE_APK_END_WITH)) {
+ if (filePath.endsWith(SPLIT_BASE_APK_SUFFIX)) {
File dir = sourceFile.getParentFile();
- if (dir.listFiles().length > 1) {
- // split apks, use file directory to get archive info
- filePath = dir.getPath();
+ try (Stream<Path> list = Files.list(dir.toPath())) {
+ long count = list
+ .filter((name) -> name.endsWith(SPLIT_APK_SUFFIX))
+ .limit(2)
+ .count();
+ if (count > 1) {
+ // split apks, use file directory to get archive info
+ filePath = dir.getPath();
+ }
+ } catch (Exception ignored) {
+ // No access to the parent directory, proceed to read app snippet
+ // from the base apk only
}
}
try {
@@ -240,9 +253,10 @@
appInfo.publicSourceDir = archiveFilePath;
if (appInfo.splitNames != null && appInfo.splitSourceDirs == null) {
- final File[] files = sourceFile.getParentFile().listFiles();
+ final File[] files = sourceFile.getParentFile().listFiles(
+ (dir, name) -> name.endsWith(SPLIT_APK_SUFFIX));
final String[] splits = Arrays.stream(appInfo.splitNames)
- .map(i -> findFilePath(files, i + ".apk"))
+ .map(i -> findFilePath(files, i + SPLIT_APK_SUFFIX))
.filter(Objects::nonNull)
.toArray(String[]::new);
@@ -283,7 +297,9 @@
}
private static String findFilePath(File[] files, String postfix) {
- for (File file : files) {
+ final int length = files != null ? files.length : 0;
+ for (int i = 0; i < length; i++) {
+ File file = files[i];
final String path = file.getAbsolutePath();
if (path.endsWith(postfix)) {
return path;
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt
index e8477ef..b84b903 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt
@@ -41,6 +41,8 @@
import com.android.packageinstaller.v2.model.PackageUtil.getAppSnippet
import java.io.ByteArrayOutputStream
import java.io.File
+import java.nio.file.Files
+import java.nio.file.Path
import kotlinx.parcelize.Parceler
import kotlinx.parcelize.Parcelize
@@ -48,6 +50,7 @@
private val LOG_TAG = InstallRepository::class.java.simpleName
private const val DOWNLOADS_AUTHORITY = "downloads"
private const val SPLIT_BASE_APK_SUFFIX = "base.apk"
+ private const val SPLIT_APK_SUFFIX = ".apk"
const val localLogv = false
const val ARGS_ABORT_REASON: String = "abort_reason"
@@ -440,9 +443,20 @@
var filePath = sourceFile.absolutePath
if (filePath.endsWith(SPLIT_BASE_APK_SUFFIX)) {
val dir = sourceFile.parentFile
- if ((dir?.listFiles()?.size ?: 0) > 1) {
- // split apks, use file directory to get archive info
- filePath = dir.path
+ try {
+ Files.list(dir.toPath()).use { list ->
+ val count: Long = list
+ .filter { name: Path -> name.endsWith(SPLIT_APK_SUFFIX) }
+ .limit(2)
+ .count()
+ if (count > 1) {
+ // split apks, use file directory to get archive info
+ filePath = dir.path
+ }
+ }
+ } catch (ignored: Exception) {
+ // No access to the parent directory, proceed to read app snippet
+ // from the base apk only
}
}
return try {
diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant55.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant55.xml
new file mode 100644
index 0000000..53ffa23
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant55.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral2_500" android:lStar="55"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_selected.xml
index 543b237..e1dde1a 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_selected.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_selected.xml
@@ -26,10 +26,7 @@
<solid
android:color="@color/settingslib_materialColorSurfaceContainer" />
<corners
- android:topLeftRadius="4dp"
- android:bottomLeftRadius="@dimen/settingslib_preference_corner_radius"
- android:topRightRadius="4dp"
- android:bottomRightRadius="@dimen/settingslib_preference_corner_radius" />
+ android:radius="@dimen/settingslib_expressive_radius_extralarge1" />
<padding
android:bottom="16dp"/>
</shape>
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_selected.xml
index 6d2cd1a..bf1b914 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_selected.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_selected.xml
@@ -25,7 +25,7 @@
<solid
android:color="@color/settingslib_materialColorSurfaceContainer" />
<corners
- android:radius="4dp" />
+ android:radius="@dimen/settingslib_expressive_radius_extralarge1" />
</shape>
</item>
</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_selected.xml
index bcdbf1d..e1dde1a 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_selected.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_selected.xml
@@ -26,7 +26,7 @@
<solid
android:color="@color/settingslib_materialColorSurfaceContainer" />
<corners
- android:radius="@dimen/settingslib_preference_corner_radius" />
+ android:radius="@dimen/settingslib_expressive_radius_extralarge1" />
<padding
android:bottom="16dp"/>
</shape>
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_selected.xml
index d4b658c..bf1b914 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_selected.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_selected.xml
@@ -25,10 +25,7 @@
<solid
android:color="@color/settingslib_materialColorSurfaceContainer" />
<corners
- android:topLeftRadius="@dimen/settingslib_preference_corner_radius"
- android:bottomLeftRadius="4dp"
- android:topRightRadius="@dimen/settingslib_preference_corner_radius"
- android:bottomRightRadius="4dp" />
+ android:radius="@dimen/settingslib_expressive_radius_extralarge1" />
</shape>
</item>
</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v36/settingslib_expressive_preference_category.xml b/packages/SettingsLib/SettingsTheme/res/layout-v36/settingslib_expressive_preference_category.xml
new file mode 100644
index 0000000..44b8e7c
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v36/settingslib_expressive_preference_category.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingRight="?android:attr/listPreferredItemPaddingRight"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:background="?android:attr/selectableItemBackground"
+ android:baselineAligned="false"
+ android:layout_marginTop="@dimen/settingslib_expressive_space_small1"
+ android:gravity="center_vertical"
+ android:filterTouchesWhenObscured="false">
+
+ <TextView
+ android:id="@android:id/title"
+ android:paddingStart="@dimen/settingslib_expressive_space_extrasmall4"
+ android:paddingTop="@dimen/settingslib_expressive_space_extrasmall4"
+ android:paddingBottom="@dimen/settingslib_expressive_space_extrasmall4"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
+ style="@style/PreferenceCategoryTitleTextStyle"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v36/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v36/styles.xml
new file mode 100644
index 0000000..ca99d44
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-night-v36/styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<resources>
+ <style name="Seekbar.SettingsLib" parent="@android:style/Widget.Material.SeekBar">
+ <item name="android:thumbTint">@android:color/system_accent1_100</item>
+ <item name="android:progressTint">@android:color/system_accent1_100</item>
+ <item name="android:progressBackgroundTint">@android:color/system_neutral2_500</item>
+ <item name="android:progressBackgroundTintMode">src_over</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v36/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values-v36/dimens.xml
index 193ae61..d783956 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v36/dimens.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v36/dimens.xml
@@ -17,5 +17,4 @@
<resources>
<dimen name="settingslib_preference_corner_radius">20dp</dimen>
- <dimen name="settingslib_preference_corner_radius_selected">28dp</dimen>
</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v36/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v36/styles.xml
new file mode 100644
index 0000000..a31983a
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-v36/styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<resources>
+ <style name="Seekbar.SettingsLib" parent="@android:style/Widget.Material.SeekBar">
+ <item name="android:thumbTint">@android:color/system_accent1_800</item>
+ <item name="android:progressTint">@android:color/system_accent1_800</item>
+ <item name="android:progressBackgroundTint">@color/settingslib_neutral_variant55</item>
+ <item name="android:progressBackgroundTintMode">src_over</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v36/styles_preference_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values-v36/styles_preference_expressive.xml
index cec8e45..ec6fe88 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v36/styles_preference_expressive.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v36/styles_preference_expressive.xml
@@ -40,6 +40,7 @@
</style>
<style name="SettingsLibPreference.Category.Expressive">
+ <item name="layout">@layout/settingslib_expressive_preference_category</item>
</style>
<style name="SettingsLibPreference.CheckBoxPreference.Expressive">
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v36/themes.xml b/packages/SettingsLib/SettingsTheme/res/values-v36/themes.xml
index 1c45ff6..54bd069 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v36/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v36/themes.xml
@@ -22,6 +22,7 @@
<item name="android:textColorPrimary">@color/settingslib_materialColorOnSurface</item>
<item name="android:textColorSecondary">@color/settingslib_text_color_secondary</item>
<item name="android:textColorTertiary">@color/settingslib_materialColorOutline</item>
+ <item name="android:seekBarStyle">@style/Seekbar.SettingsLib</item>
<!-- Set up edge-to-edge configuration for top app bar -->
<item name="android:clipToPadding">false</item>
<item name="android:clipChildren">false</item>
diff --git a/packages/SettingsLib/ValuePreference/Android.bp b/packages/SettingsLib/ValuePreference/Android.bp
new file mode 100644
index 0000000..1cdcd22
--- /dev/null
+++ b/packages/SettingsLib/ValuePreference/Android.bp
@@ -0,0 +1,31 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_library {
+ name: "SettingsLibValuePreference",
+ use_resource_processor: true,
+ defaults: [
+ "SettingsLintDefaults",
+ ],
+
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+
+ static_libs: [
+ "androidx.annotation_annotation",
+ "androidx.preference_preference",
+ "SettingsLibSettingsTheme",
+ ],
+
+ sdk_version: "system_current",
+ min_sdk_version: "23",
+ apex_available: [
+ "//apex_available:platform",
+ ],
+}
diff --git a/packages/SettingsLib/ValuePreference/AndroidManifest.xml b/packages/SettingsLib/ValuePreference/AndroidManifest.xml
new file mode 100644
index 0000000..217282b
--- /dev/null
+++ b/packages/SettingsLib/ValuePreference/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.settingslib.widget.preference.value">
+
+ <uses-sdk android:minSdkVersion="21"/>
+
+</manifest>
diff --git a/packages/SettingsLib/ValuePreference/res/layout/settingslib_expressive_value_preference.xml b/packages/SettingsLib/ValuePreference/res/layout/settingslib_expressive_value_preference.xml
new file mode 100644
index 0000000..4fd3ab10
--- /dev/null
+++ b/packages/SettingsLib/ValuePreference/res/layout/settingslib_expressive_value_preference.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="72dp"
+ android:gravity="center_vertical"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:background="?android:attr/selectableItemBackground"
+ android:clipToPadding="false"
+ android:baselineAligned="false"
+ android:filterTouchesWhenObscured="false">
+
+ <include layout="@layout/settingslib_expressive_preference_icon_frame"/>
+
+ <include layout="@layout/settingslib_expressive_value_preference_text_frame"/>
+
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout
+ android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="end|center_vertical"
+ android:paddingStart="@dimen/settingslib_expressive_space_small1"
+ android:paddingEnd="0dp"
+ android:orientation="vertical"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/ValuePreference/res/layout/settingslib_expressive_value_preference_text_frame.xml b/packages/SettingsLib/ValuePreference/res/layout/settingslib_expressive_value_preference_text_frame.xml
new file mode 100644
index 0000000..a385ee5
--- /dev/null
+++ b/packages/SettingsLib/ValuePreference/res/layout/settingslib_expressive_value_preference_text_frame.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/settingslib_expressive_space_none"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingVertical="@dimen/settingslib_expressive_space_small1"
+ android:paddingStart="@dimen/settingslib_expressive_space_none"
+ android:paddingEnd="@dimen/settingslib_expressive_space_small1"
+ android:filterTouchesWhenObscured="false">
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
+ android:maxLines="2"
+ android:textAppearance="@style/TextAppearance.SettingsLib.ValuePreferenceTitle"
+ android:ellipsize="marquee"/>
+
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/title"
+ android:layout_alignStart="@android:id/title"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
+ android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="10"/>
+</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/ValuePreference/res/values/styles.xml b/packages/SettingsLib/ValuePreference/res/values/styles.xml
new file mode 100644
index 0000000..2848194
--- /dev/null
+++ b/packages/SettingsLib/ValuePreference/res/values/styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:tools="http://schemas.android.com/tools">
+ <style name="TextAppearance.SettingsLib.ValuePreferenceTitle"
+ parent="@style/TextAppearance.SettingsLib.DisplaySmall">
+ <item name="android:textColor">@color/settingslib_text_color_primary</item>
+ </style>
+</resources>
diff --git a/packages/SettingsLib/ValuePreference/src/com/android/settingslib/widget/ValuePreference.kt b/packages/SettingsLib/ValuePreference/src/com/android/settingslib/widget/ValuePreference.kt
new file mode 100644
index 0000000..475638c
--- /dev/null
+++ b/packages/SettingsLib/ValuePreference/src/com/android/settingslib/widget/ValuePreference.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget
+
+import android.content.Context
+import android.util.AttributeSet
+import androidx.preference.Preference
+import androidx.preference.PreferenceViewHolder
+import com.android.settingslib.widget.preference.value.R
+
+/** The BulletPreference shows a text which describe a feature. */
+class ValuePreference
+@JvmOverloads
+constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+ defStyleRes: Int = 0
+) : Preference(context, attrs, defStyleAttr, defStyleRes) {
+
+ init {
+ layoutResource = R.layout.settingslib_expressive_value_preference
+ }
+
+ override fun onBindViewHolder(holder: PreferenceViewHolder) {
+ super.onBindViewHolder(holder)
+ holder.isDividerAllowedAbove = false
+ holder.isDividerAllowedBelow = false
+ }
+}
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index f1859f2..54074ec 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Ingeboude luidspreker"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV-oudio"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kan nie koppel nie. Skakel toestel af en weer aan"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Kan nie koppel nie"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedrade oudiotoestel"</string>
<string name="help_label" msgid="3528360748637781274">"Hulp en terugvoer"</string>
<string name="storage_category" msgid="2287342585424631813">"Berging"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 77009d74..1fab31b 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"አብሮ የተሰራ ድምፅ ማውጫ"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"የTV ኦዲዮ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"መገናኘት ላይ ችግር። መሳሪያውን ያጥፉት እና እንደገና ያብሩት"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"ማገናኘት አልተቻለም"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ባለገመድ የኦዲዮ መሣሪያ"</string>
<string name="help_label" msgid="3528360748637781274">"እገዛ እና ግብረመልስ"</string>
<string name="storage_category" msgid="2287342585424631813">"ማከማቻ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index a522e07..6cb8154 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"مكبِّر الصوت المُدمَج"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"صوت التلفزيون"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"حدثت مشكلة أثناء الاتصال. يُرجى إيقاف الجهاز ثم إعادة تشغيله."</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"يتعذّر الاتصال"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"جهاز سماعي سلكي"</string>
<string name="help_label" msgid="3528360748637781274">"المساعدة والملاحظات"</string>
<string name="storage_category" msgid="2287342585424631813">"مساحة التخزين"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 0ed118b..b39593e 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -77,7 +77,7 @@
<string name="osu_sign_up_failed" msgid="5605453599586001793">"ছাইন আপ সম্পূৰ্ণ কৰিব পৰা নগ’ল। আকৌ চেষ্টা কৰিবলৈ টিপক।"</string>
<string name="osu_sign_up_complete" msgid="7640183358878916847">"ছাইন আপ সম্পূৰ্ণ হৈছে সংযোগ কৰি থকা হৈছে…"</string>
<string name="speed_label_slow" msgid="6069917670665664161">"লেহেমীয়া"</string>
- <string name="speed_label_okay" msgid="1253594383880810424">"ঠিক"</string>
+ <string name="speed_label_okay" msgid="1253594383880810424">"ঠিক আছে"</string>
<string name="speed_label_fast" msgid="2677719134596044051">"দ্ৰুত"</string>
<string name="speed_label_very_fast" msgid="8215718029533182439">"অতি দ্ৰুত"</string>
<string name="wifi_passpoint_expired" msgid="6540867261754427561">"ম্যাদ উকলিছে"</string>
@@ -578,7 +578,7 @@
<string name="next" msgid="2699398661093607009">"পৰৱৰ্তী"</string>
<string name="back" msgid="5554327870352703710">"উভতি যাওক"</string>
<string name="save" msgid="3745809743277153149">"ছেভ কৰক"</string>
- <string name="okay" msgid="949938843324579502">"ঠিক"</string>
+ <string name="okay" msgid="949938843324579502">"ঠিক আছে"</string>
<string name="done" msgid="381184316122520313">"হ’ল"</string>
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"এলাৰ্ম আৰু ৰিমাইণ্ডাৰ"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"এলাৰ্ম আৰু ৰিমাইণ্ডাৰ ছেট কৰাৰ অনুমতি দিয়ক"</string>
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"বিল্ট-ইন স্পীকাৰ"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"টিভিৰ অডিঅ’"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"সংযোগ হোৱাত সমস্যা হৈছে। ডিভাইচটো অফ কৰি পুনৰ অন কৰক"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"সংযোগ কৰিব নোৱাৰি"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"তাঁৰযুক্ত অডিঅ’ ডিভাইচ"</string>
<string name="help_label" msgid="3528360748637781274">"সহায় আৰু মতামত"</string>
<string name="storage_category" msgid="2287342585424631813">"ষ্ট’ৰেজ"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 6ba40f7..de74a46 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Daxili dinamik"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV audiosu"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Qoşulmaqla bağlı problem. Cihazı deaktiv edin, sonra yenidən aktiv edin"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Qoşulmaq mümkün deyil"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio cihaz"</string>
<string name="help_label" msgid="3528360748637781274">"Yardım və rəy"</string>
<string name="storage_category" msgid="2287342585424631813">"Yaddaş"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 0ebeb55..3db1617 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Ugrađeni zvučnik"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Zvuk TV-a"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem pri povezivanju. Isključite uređaj, pa ga ponovo uključite"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Povezivanje nije uspelo"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
<string name="storage_category" msgid="2287342585424631813">"Memorijski prostor"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 8e1fd28..74dd666 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Убудаваны дынамік"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Аўдыя тэлевізара"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Праблема з падключэннем. Выключыце і зноў уключыце прыладу"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Не ўдаецца падключыцца"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Правадная аўдыяпрылада"</string>
<string name="help_label" msgid="3528360748637781274">"Даведка і водгукі"</string>
<string name="storage_category" msgid="2287342585424631813">"Сховішча"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index bf10d1d..b0ff126 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Вграден високоговорител"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Аудио на телевизора"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"При свързването възникна проблем. Изключете устройството и го включете отново"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Няма връзка"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Аудиоустройство с кабел"</string>
<string name="help_label" msgid="3528360748637781274">"Помощ и отзиви"</string>
<string name="storage_category" msgid="2287342585424631813">"Хранилище"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 5f37d44..9afef62 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"বিল্ট-ইন স্পিকার"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"টিভি অডিও"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"কানেক্ট করতে সমস্যা হচ্ছে। ডিভাইস বন্ধ করে আবার চালু করুন"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"কানেক্ট করা যাচ্ছে না"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ওয়্যার অডিও ডিভাইস"</string>
<string name="help_label" msgid="3528360748637781274">"সহায়তা ও মতামত"</string>
<string name="storage_category" msgid="2287342585424631813">"স্টোরেজ"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 8cc8199..22de5005 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Ugrađeni zvučnik"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Zvuk TV-a"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Došlo je do problema prilikom povezivanja. Isključite, pa ponovo uključite uređaj"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Nije se moguće povezati"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
<string name="storage_category" msgid="2287342585424631813">"Pohrana"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index ee683e5..da50f091 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Altaveu integrat"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Àudio de la televisió"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Hi ha hagut un problema amb la connexió. Apaga el dispositiu i torna\'l a encendre."</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"No es pot establir la connexió"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositiu d\'àudio amb cable"</string>
<string name="help_label" msgid="3528360748637781274">"Ajuda i suggeriments"</string>
<string name="storage_category" msgid="2287342585424631813">"Emmagatzematge"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 58cdc19..9d61a5a 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Vestavěný reproduktor"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Zvuk televize"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problém s připojením. Vypněte zařízení a znovu jej zapněte"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Nelze se připojit"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kabelové audiozařízení"</string>
<string name="help_label" msgid="3528360748637781274">"Nápověda a zpětná vazba"</string>
<string name="storage_category" msgid="2287342585424631813">"Úložiště"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 257f673..91b6420 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Indbygget højttaler"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV-lyd"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Der kunne ikke oprettes forbindelse. Sluk og tænd enheden"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Der kan ikke oprettes forbindelse"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhed med ledning"</string>
<string name="help_label" msgid="3528360748637781274">"Hjælp og feedback"</string>
<string name="storage_category" msgid="2287342585424631813">"Lager"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 8bfaa0e..0c7ea02 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Integrierter Lautsprecher"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV‑Audio"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Verbindung kann nicht hergestellt werden. Schalte das Gerät aus und wieder ein."</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Verbindung nicht möglich"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Netzbetriebenes Audiogerät"</string>
<string name="help_label" msgid="3528360748637781274">"Hilfe und Feedback"</string>
<string name="storage_category" msgid="2287342585424631813">"Speicher"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 83fb6ff..06620f3 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -257,14 +257,14 @@
<string name="vpn_settings_not_available" msgid="2894137119965668920">"Οι ρυθμίσεις VPN δεν είναι διαθέσιμες γι\' αυτόν το χρήστη"</string>
<string name="tethering_settings_not_available" msgid="266821736434699780">"Οι ρυθμίσεις σύνδεσης μέσω κινητής συσκευής δεν είναι διαθέσιμες γι\' αυτόν το χρήστη"</string>
<string name="apn_settings_not_available" msgid="1147111671403342300">"Οι ρυθμίσεις ονόματος σημείου πρόσβασης δεν είναι διαθέσιμες γι\' αυτόν το χρήστη"</string>
- <string name="enable_adb" msgid="8072776357237289039">"Εντοπισμός σφαλμάτων USB"</string>
+ <string name="enable_adb" msgid="8072776357237289039">"Αποσφαλμάτωση USB"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"Λειτουργία εντοπισμού σφαλμάτων όταν το USB είναι συνδεδεμένο"</string>
- <string name="clear_adb_keys" msgid="3010148733140369917">"Ανάκληση εξ/σεων εντ/σμού σφ/των USB"</string>
- <string name="enable_adb_wireless" msgid="6973226350963971018">"Ασύρματος εντοπισμός σφαλμάτων"</string>
+ <string name="clear_adb_keys" msgid="3010148733140369917">"Ανάκληση εξ/σεων αποσφαλμάτ. USB"</string>
+ <string name="enable_adb_wireless" msgid="6973226350963971018">"Ασύρματη αποσφαλμάτωση"</string>
<string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Λειτουργία εντοπισμού σφαλμάτων όταν το Wi‑Fi είναι συνδεδεμένο"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"Σφάλμα"</string>
- <string name="adb_wireless_settings" msgid="2295017847215680229">"Ασύρματος εντοπισμός σφαλμάτων"</string>
- <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Για να δείτε και να χρησιμοποιήσετε τις διαθέσιμες συσκευές, ενεργοποιήστε τον ασύρματο εντοπισμό σφαλμάτων"</string>
+ <string name="adb_wireless_settings" msgid="2295017847215680229">"Ασύρματη αποσφαλμάτωση"</string>
+ <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Για να δείτε και να χρησιμοποιήσετε τις διαθέσιμες συσκευές, ενεργοποιήστε την ασύρματη αποσφαλμάτωση"</string>
<string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Σύζευξη συσκευής με κωδικό QR"</string>
<string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Σύζευξη νέων συσκευών με τη χρήση σαρωτή κωδικών QR"</string>
<string name="adb_pair_method_code_title" msgid="1122590300445142904">"Σύζευξη συσκευής με κωδικό σύζευξης"</string>
@@ -287,7 +287,7 @@
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Σάρωση κωδικού QR"</string>
<string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Σύζευξη συσκευής μέσω Wi‑Fi με τη σάρωση ενός κωδικού QR"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Συνδεθείτε σε ένα δίκτυο Wi-Fi"</string>
- <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, εντοπισμός σφαλμάτων, προγραμματιστής"</string>
+ <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, αποσφαλμάτωση, προγραμματιστής"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"Συντόμευση αναφοράς σφαλμάτων"</string>
<string name="bugreport_in_power_summary" msgid="1885529649381831775">"Εμφάνιση κουμπιού στο μενού ενεργοποίησης για τη λήψη αναφοράς σφαλμάτων"</string>
<string name="keep_screen_on" msgid="1187161672348797558">"Παραμονή σε λειτουργία"</string>
@@ -353,11 +353,11 @@
<string name="debug_view_attributes" msgid="3539609843984208216">"Ενεργοποίηση του ελέγχου χαρακτηριστικών προβολής"</string>
<string name="mobile_data_always_on_summary" msgid="1112156365594371019">"Τα δεδομένα κινητής τηλεφωνίας να διατηρούνται πάντα ενεργά, ακόμα και όταν είναι ενεργό το Wi-Fi (για γρήγορη εναλλαγή δικτύου)."</string>
<string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Χρήση της σύνδεσης επιτάχυνσης υλικού εάν υπάρχει"</string>
- <string name="adb_warning_title" msgid="7708653449506485728">"Να επιτρέπεται ο εντοπισμός σφαλμάτων USB;"</string>
- <string name="adb_warning_message" msgid="8145270656419669221">"Ο εντοπισμός σφαλμάτων USB προορίζεται μόνο για σκοπούς προγραμματισμού. Χρησιμοποιήστε τον για αντιγραφή δεδομένων μεταξύ του υπολογιστή και της συσκευής σας, για την εγκατάσταση εφαρμογών στη συσκευή σας χωρίς προειδοποίηση και για την ανάγνωση δεδομένων καταγραφής."</string>
- <string name="adbwifi_warning_title" msgid="727104571653031865">"Να επιτρέπεται ο ασύρματος εντοπισμός σφαλμάτων;"</string>
- <string name="adbwifi_warning_message" msgid="8005936574322702388">"Ο ασύρματος εντοπισμός σφαλμάτων προορίζεται μόνο για σκοπούς προγραμματισμού. Χρησιμοποιήστε τον για αντιγραφή δεδομένων μεταξύ του υπολογιστή και της συσκευής σας, για την εγκατάσταση εφαρμογών στη συσκευή σας χωρίς ειδοποίηση και για την ανάγνωση δεδομένων καταγραφής."</string>
- <string name="adb_keys_warning_message" msgid="2968555274488101220">"Ανάκληση πρόσβασης στον εντοπισμό σφαλμάτων USB από όλους τους υπολογιστές για τους οποίους είχατε εξουσιοδότηση στο παρελθόν;"</string>
+ <string name="adb_warning_title" msgid="7708653449506485728">"Να επιτρέπεται η αποσφαλμάτωση USB;"</string>
+ <string name="adb_warning_message" msgid="8145270656419669221">"Η αποσφαλμάτωση USB προορίζεται μόνο για σκοπούς προγραμματισμού. Χρησιμοποιήστε τον για αντιγραφή δεδομένων μεταξύ του υπολογιστή και της συσκευής σας, για την εγκατάσταση εφαρμογών στη συσκευή σας χωρίς προειδοποίηση και για την ανάγνωση δεδομένων καταγραφής."</string>
+ <string name="adbwifi_warning_title" msgid="727104571653031865">"Να επιτρέπεται η ασύρματη αποσφαλμάτωση;"</string>
+ <string name="adbwifi_warning_message" msgid="8005936574322702388">"Η ασύρματη αποσφαλμάτωση προορίζεται μόνο για σκοπούς προγραμματισμού. Χρησιμοποιήστε τον για αντιγραφή δεδομένων μεταξύ του υπολογιστή και της συσκευής σας, για την εγκατάσταση εφαρμογών στη συσκευή σας χωρίς ειδοποίηση και για την ανάγνωση δεδομένων καταγραφής."</string>
+ <string name="adb_keys_warning_message" msgid="2968555274488101220">"Ανάκληση πρόσβασης στην αποσφαλμάτωση USB από όλους τους υπολογιστές για τους οποίους είχατε εξουσιοδότηση στο παρελθόν;"</string>
<string name="dev_settings_warning_title" msgid="8251234890169074553">"Να επιτρέπεται η χρήση των ρυθμίσεων ανάπτυξης;"</string>
<string name="dev_settings_warning_message" msgid="37741686486073668">"Αυτές οι ρυθμίσεις προορίζονται για χρήση κατά την ανάπτυξη. Μπορούν να προκαλέσουν προβλήματα στη λειτουργία της συσκευής και των εφαρμογών σας."</string>
<string name="verify_apps_over_usb_title" msgid="6031809675604442636">"Επαλήθευση εφαρμογών μέσω USB"</string>
@@ -373,14 +373,14 @@
<string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Εάν απενεργοποιηθεί, τα δεδομένα τερματικού Linux θα διαγραφούν"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Έλεγχος HDCP"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Ρύθμιση συμπεριφοράς ελέγχου HDCP"</string>
- <string name="debug_debugging_category" msgid="535341063709248842">"Εντοπισμός σφαλμάτων"</string>
+ <string name="debug_debugging_category" msgid="535341063709248842">"Εντοπ. σφαλμ."</string>
<string name="debug_app" msgid="8903350241392391766">"Επιλέξτε εφαρμογή εντοπισμού σφαλμάτων"</string>
<string name="debug_app_not_set" msgid="1934083001283807188">"Δεν έχει οριστεί εφαρμογή εντοπισμού σφαλμάτων"</string>
- <string name="debug_app_set" msgid="6599535090477753651">"Εφαρμογή εντοπισμού σφαλμάτων: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="debug_app_set" msgid="6599535090477753651">"Εφαρμογή αποσφαλμάτωσης: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="select_application" msgid="2543228890535466325">"Επιλέξτε εφαρμογή"</string>
<string name="no_application" msgid="9038334538870247690">"Καμία"</string>
<string name="wait_for_debugger" msgid="7461199843335409809">"Περιμένετε το εργαλείο εντοπισμού σφαλμάτων"</string>
- <string name="wait_for_debugger_summary" msgid="6846330006113363286">"Αναμονή εφαρμογής για να συνδεθεί ο εντοπισμός σφαλμάτων"</string>
+ <string name="wait_for_debugger_summary" msgid="6846330006113363286">"Αναμονή εφαρμογής για να συνδεθεί η αποσφαλμάτωση"</string>
<string name="debug_input_category" msgid="7349460906970849771">"Εισαγωγή"</string>
<string name="debug_drawing_category" msgid="5066171112313666619">"Σχέδιο"</string>
<string name="debug_hw_drawing_category" msgid="5830815169336975162">"Απόδοση με επιτάχυνση από υλικό εξοπλισμό"</string>
@@ -419,7 +419,7 @@
<string name="window_blurs" msgid="6831008984828425106">"Θάμπωμα σε επίπεδο παραθ."</string>
<string name="force_msaa" msgid="4081288296137775550">"Αναγκαστικά 4x MSAA"</string>
<string name="force_msaa_summary" msgid="9070437493586769500">"Ενεργοποίηση 4x MSAA σε εφαρμογές OpenGL ES 2.0"</string>
- <string name="show_non_rect_clip" msgid="7499758654867881817">"Εντοπισμός σφαλμάτων σε λειτουργίες μη ορθογώνιας περιοχής"</string>
+ <string name="show_non_rect_clip" msgid="7499758654867881817">"Αποσφαλμάτωση σε λειτουργίες μη ορθογώνιας περιοχής"</string>
<string name="track_frame_time" msgid="522674651937771106">"Απόδοση HWUI προφίλ"</string>
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Ενεργ. επιπ. εντ. σφ. GPU"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Φόρτωση επιπ. εντοπ. σφ. GPU για εφαρμ. αντιμ. σφ."</string>
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Ενσωματωμένο ηχείο"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Ήχος τηλεόρασης"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Πρόβλημα κατά τη σύνδεση. Απενεργοποιήστε τη συσκευή και ενεργοποιήστε την ξανά"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Δεν είναι δυνατή η σύνδεση"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ενσύρματη συσκευή ήχου"</string>
<string name="help_label" msgid="3528360748637781274">"Βοήθεια και σχόλια"</string>
<string name="storage_category" msgid="2287342585424631813">"Αποθηκευτικός χώρος"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index e2e3851..109558e 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Built-in speaker"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV audio"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Can\'t connect"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
<string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
<string name="storage_category" msgid="2287342585424631813">"Storage"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index e2e3851..109558e 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Built-in speaker"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV audio"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Can\'t connect"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
<string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
<string name="storage_category" msgid="2287342585424631813">"Storage"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index e2e3851..109558e 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Built-in speaker"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV audio"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Can\'t connect"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
<string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
<string name="storage_category" msgid="2287342585424631813">"Storage"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 17909f9..216ae57 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Bocina integrada"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Audio de la TV"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Error al establecer la conexión. Apaga el dispositivo y vuelve a encenderlo."</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"No se puede establecer la conexión"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
<string name="help_label" msgid="3528360748637781274">"Ayuda y comentarios"</string>
<string name="storage_category" msgid="2287342585424631813">"Almacenamiento"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 536f099..6bbff4b7 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Altavoz integrado"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Audio de la televisión"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"No se ha podido conectar; reinicia el dispositivo"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"No se puede conectar"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
<string name="help_label" msgid="3528360748637781274">"Ayuda y comentarios"</string>
<string name="storage_category" msgid="2287342585424631813">"Almacenamiento"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 86ccf28..19df69d 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Sisseehitatud kõlar"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Teleri heli"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem ühendamisel. Lülitage seade välja ja uuesti sisse"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Ei saa ühendada"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Juhtmega heliseade"</string>
<string name="help_label" msgid="3528360748637781274">"Abi ja tagasiside"</string>
<string name="storage_category" msgid="2287342585424631813">"Salvestusruum"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 4de40f5..788febb 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -539,8 +539,7 @@
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Ezarpen mugatuak kontrolatzen du"</string>
<string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Ez dago erabilgarri deiak egin bitartean"</string>
<string name="disabled" msgid="8017887509554714950">"Desgaituta"</string>
- <!-- no translation found for enabled (3997122818554810678) -->
- <skip />
+ <string name="enabled" msgid="3997122818554810678">"Gaituta"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Baimenduta"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Baimendu gabe"</string>
<string name="install_other_apps" msgid="3232595082023199454">"Instalatu aplikazio ezezagunak"</string>
@@ -628,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Bozgorailu integratua"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Telebistako audioa"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Arazo bat izan da konektatzean. Itzali gailua eta pitz ezazu berriro."</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Ezin da konektatu"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio-gailu kableduna"</string>
<string name="help_label" msgid="3528360748637781274">"Laguntza eta iritziak"</string>
<string name="storage_category" msgid="2287342585424631813">"Biltegiratzea"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index f3fa38b..75cf19c 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"بلندگوی داخلی"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"صدای تلویزیون"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"مشکل در اتصال. دستگاه را خاموش و دوباره روشن کنید"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"اتصال برقرار نشد"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"دستگاه صوتی سیمی"</string>
<string name="help_label" msgid="3528360748637781274">"راهنما و بازخورد"</string>
<string name="storage_category" msgid="2287342585424631813">"فضای ذخیرهسازی"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index e212f09..7854c67 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Sisäänrakennettu kaiutin"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV:n audio"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Yhteysvirhe. Sammuta laite ja käynnistä se uudelleen."</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Ei yhteyttä"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Langallinen äänilaite"</string>
<string name="help_label" msgid="3528360748637781274">"Ohjeet ja palaute"</string>
<string name="storage_category" msgid="2287342585424631813">"Tallennustila"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 7c3c844..3f267e0 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Haut-parleur intégré"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Sortie audio du téléviseur"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteignez et rallumez l\'appareil"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Connexion impossible"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio à câble"</string>
<string name="help_label" msgid="3528360748637781274">"Aide et commentaires"</string>
<string name="storage_category" msgid="2287342585424631813">"Stockage"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 1053e15..33c1883 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Haut-parleur intégré"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Audio TV"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteignez l\'appareil, puis rallumez-le"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Impossible de se connecter"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio filaire"</string>
<string name="help_label" msgid="3528360748637781274">"Aide et commentaires"</string>
<string name="storage_category" msgid="2287342585424631813">"Stockage"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 618dd62..8044fd8 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Altofalante integrado"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Saída de audio da televisión"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Produciuse un problema coa conexión. Apaga e acende o dispositivo."</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Non se puido establecer a conexión"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
<string name="help_label" msgid="3528360748637781274">"Axuda e comentarios"</string>
<string name="storage_category" msgid="2287342585424631813">"Almacenamento"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 9f8fc10..c8491e0 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"બિલ્ટ-ઇન સ્પીકર"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"ટીવીનો ઑડિયો"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"કનેક્ટ કરવામાં સમસ્યા આવી રહી છે. ડિવાઇસને બંધ કરીને ફરી ચાલુ કરો"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"કનેક્ટ કરી શકતા નથી"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"વાયરવાળો ઑડિયો ડિવાઇસ"</string>
<string name="help_label" msgid="3528360748637781274">"સહાય અને પ્રતિસાદ"</string>
<string name="storage_category" msgid="2287342585424631813">"સ્ટોરેજ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index cb6e3c9..407075a 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"डिवाइस में पहले से मौजूद स्पीकर"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"टीवी ऑडियो"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करने में समस्या हो रही है. डिवाइस को बंद करके चालू करें"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"कनेक्ट नहीं किया जा सकता"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर वाला ऑडियो डिवाइस"</string>
<string name="help_label" msgid="3528360748637781274">"सहायता और सुझाव"</string>
<string name="storage_category" msgid="2287342585424631813">"डिवाइस का स्टोरेज"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 10863cf..380fbe8 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Ugrađeni zvučnik"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV zvuk"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem s povezivanjem. Isključite i ponovo uključite uređaj"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Povezivanje nije uspjelo"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audiouređaj"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
<string name="storage_category" msgid="2287342585424631813">"Pohrana"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 104e4bc..9d08e05 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Beépített hangszóró"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Tévés hangkimenet"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sikertelen csatlakozás. Kapcsolja ki az eszközt, majd kapcsolja be újra."</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Sikertelen csatlakozás"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vezetékes audioeszköz"</string>
<string name="help_label" msgid="3528360748637781274">"Súgó és visszajelzés"</string>
<string name="storage_category" msgid="2287342585424631813">"Tárhely"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index a5a15f9..425cb07 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Ներկառուցված բարձրախոս"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Հեռուստացույցի աուդիո"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Կապի խնդիր կա: Սարքն անջատեք և նորից միացրեք:"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Չի հաջողվում միանալ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Լարով աուդիո սարք"</string>
<string name="help_label" msgid="3528360748637781274">"Օգնություն և հետադարձ կապ"</string>
<string name="storage_category" msgid="2287342585424631813">"Տարածք"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index c8d7481..99b3bdc 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Speaker bawaan"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Audio TV"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ada masalah saat menghubungkan. Nonaktifkan perangkat & aktifkan kembali"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Tidak dapat terhubung"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Perangkat audio berkabel"</string>
<string name="help_label" msgid="3528360748637781274">"Bantuan & masukan"</string>
<string name="storage_category" msgid="2287342585424631813">"Penyimpanan"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index f85c20b..b337f35 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Innbyggður hátalari"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Sjónvarpshljóð"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Vandamál í tengingu. Slökktu og kveiktu á tækinu"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Ekki tókst að tengjast"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Snúrutengt hljómtæki"</string>
<string name="help_label" msgid="3528360748637781274">"Hjálp og ábendingar"</string>
<string name="storage_category" msgid="2287342585424631813">"Geymsla"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 1b31ae0..8347e6a 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Altoparlante integrato"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Audio della TV"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema di connessione. Spegni e riaccendi il dispositivo"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Impossibile connettersi"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo audio cablato"</string>
<string name="help_label" msgid="3528360748637781274">"Guida e feedback"</string>
<string name="storage_category" msgid="2287342585424631813">"Archiviazione"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 78c16de..7485026 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"内蔵スピーカー"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV オーディオ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"接続エラーです。デバイスを OFF にしてから ON に戻してください"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"接続できません"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線オーディオ デバイス"</string>
<string name="help_label" msgid="3528360748637781274">"ヘルプとフィードバック"</string>
<string name="storage_category" msgid="2287342585424631813">"ストレージ"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index a7599be..fe7e65c 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"ჩაშენებული დინამიკი"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV Audio"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"დაკავშირებისას წარმოიქმნა პრობლემა. გამორთეთ და კვლავ ჩართეთ მოწყობილობა"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"დაკავშირება შეუძლებელია"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"სადენიანი აუდიო მოწყობილობა"</string>
<string name="help_label" msgid="3528360748637781274">"დახმარება და გამოხმაურება"</string>
<string name="storage_category" msgid="2287342585424631813">"საცავი"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index b8a8355..6053ff7 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"ឧបករណ៍សំឡេងមកជាមួយ"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"សំឡេងទូរទស្សន៍"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"មានបញ្ហាក្នុងការភ្ជាប់។ បិទ រួចបើកឧបករណ៍វិញ"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"មិនអាចភ្ជាប់បានទេ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ឧបករណ៍សំឡេងប្រើខ្សែ"</string>
<string name="help_label" msgid="3528360748637781274">"ជំនួយ និងមតិកែលម្អ"</string>
<string name="storage_category" msgid="2287342585424631813">"ទំហំផ្ទុក"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 4a8a413..61b235e 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"ಅಂತರ್ ನಿರ್ಮಿತ ಧ್ವನಿ ವರ್ಧಕ"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV ಆಡಿಯೊ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ಕನೆಕ್ಟ್ ಮಾಡುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ ಸಾಧನವನ್ನು ಆಫ್ ಮಾಡಿ ಹಾಗೂ ನಂತರ ಪುನಃ ಆನ್ ಮಾಡಿ"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ವೈರ್ ಹೊಂದಿರುವ ಆಡಿಯೋ ಸಾಧನ"</string>
<string name="help_label" msgid="3528360748637781274">"ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"</string>
<string name="storage_category" msgid="2287342585424631813">"ಸಂಗ್ರಹಣೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index ee99beb..d0a583bd 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"내장 스피커"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV 오디오"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"연결 중에 문제가 발생했습니다. 기기를 껐다가 다시 켜 보세요."</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"연결할 수 없습니다."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"유선 오디오 기기"</string>
<string name="help_label" msgid="3528360748637781274">"고객센터"</string>
<string name="storage_category" msgid="2287342585424631813">"저장용량"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 5a8a66f..c68fb70 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Алдын ала орнотулган динамик"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Сыналгы аудиосу"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Туташууда маселе келип чыкты. Түзмөктү өчүрүп, кайра күйгүзүп көрүңүз"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Туташпай жатат"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Зымдуу аудио түзмөк"</string>
<string name="help_label" msgid="3528360748637781274">"Жардам/Пикир билдирүү"</string>
<string name="storage_category" msgid="2287342585424631813">"Сактагыч"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index c60c04d..c4e25f8 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"ລຳໂພງທີ່ມີໃນຕົວ"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"ສຽງນີ້"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ເກີດບັນຫາໃນການເຊື່ອມຕໍ່. ປິດອຸປະກອນແລ້ວເປີດກັບຄືນມາໃໝ່"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"ບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ອຸປະກອນສຽງແບບມີສາຍ"</string>
<string name="help_label" msgid="3528360748637781274">"ຊ່ວຍເຫຼືອ ແລະ ຕິຊົມ"</string>
<string name="storage_category" msgid="2287342585424631813">"ບ່ອນເກັບຂໍ້ມູນ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 6467e89..0379d5c 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Įtaisytas garsiakalbis"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV garso įrašas"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Prisijungiant kilo problema. Išjunkite įrenginį ir vėl jį įjunkite"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Nepavyksta prisijungti"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Laidinis garso įrenginys"</string>
<string name="help_label" msgid="3528360748637781274">"Pagalba ir atsiliepimai"</string>
<string name="storage_category" msgid="2287342585424631813">"Saugykla"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 71d9b76..a181249 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Вграден звучник"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Аудио на телевизор"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем со поврзување. Исклучете го уредот и повторно вклучете го"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Не може да се поврзе"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичен аудиоуред"</string>
<string name="help_label" msgid="3528360748637781274">"Помош и повратни информации"</string>
<string name="storage_category" msgid="2287342585424631813">"Простор"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index d9c9629..b1d1d4f 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"ബിൽട്ട്-ഇൻ സ്പീക്കർ"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"ടിവി ഓഡിയോ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"കണക്റ്റ് ചെയ്യുന്നതിൽ പ്രശ്നമുണ്ടായി. ഉപകരണം ഓഫാക്കി വീണ്ടും ഓണാക്കുക"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"കണക്റ്റ് ചെയ്യാനാകുന്നില്ല"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"വയർ മുഖേന ബന്ധിപ്പിച്ച ഓഡിയോ ഉപകരണം"</string>
<string name="help_label" msgid="3528360748637781274">"സഹായവും ഫീഡ്ബാക്കും"</string>
<string name="storage_category" msgid="2287342585424631813">"സ്റ്റോറേജ്"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 829b1d7..9b128bd 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Бүрэлдэхүүн чанга яригч"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"ТВ-ийн аудио"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Холбогдоход асуудал гарлаа. Төхөөрөмжийг унтраагаад дахин асаана уу"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Холбогдох боломжгүй байна"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Утастай аудио төхөөрөмж"</string>
<string name="help_label" msgid="3528360748637781274">"Тусламж, санал хүсэлт"</string>
<string name="storage_category" msgid="2287342585424631813">"Хадгалах сан"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 8207174..7c8c6aa 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"बिल्ट-इन स्पीकर"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"टीव्ही ऑडिओ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करण्यात समस्या आली. डिव्हाइस बंद करा आणि नंतर सुरू करा"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"कनेक्ट करू शकत नाही"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर असलेले ऑडिओ डिव्हाइस"</string>
<string name="help_label" msgid="3528360748637781274">"मदत आणि फीडबॅक"</string>
<string name="storage_category" msgid="2287342585424631813">"स्टोरेज"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index ea3d78e..52d1d5a 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Pembesar suara terbina dalam"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Audio TV"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Masalah penyambungan. Matikan & hidupkan kembali peranti"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Tidak dapat disambungkan"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Peranti audio berwayar"</string>
<string name="help_label" msgid="3528360748637781274">"Bantuan & maklum balas"</string>
<string name="storage_category" msgid="2287342585424631813">"Storan"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index c484a74..e3d1005 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"အသင့်ပါ စပီကာ"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV အသံ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ချိတ်ဆက်ရာတွင် ပြဿနာရှိပါသည်။ စက်ကိုပိတ်ပြီး ပြန်ဖွင့်ပါ"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"ချိတ်ဆက်၍မရပါ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ကြိုးတပ် အသံစက်ပစ္စည်း"</string>
<string name="help_label" msgid="3528360748637781274">"အကူအညီနှင့် အကြံပြုချက်"</string>
<string name="storage_category" msgid="2287342585424631813">"သိုလှောင်ခန်း"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 3c06c68..9b2fbd8 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Innebygd høyttaler"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV-lyd"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Tilkoblingsproblemer. Slå enheten av og på igjen"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Kan ikke koble til"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhet med kabel"</string>
<string name="help_label" msgid="3528360748637781274">"Hjelp og tilbakemelding"</string>
<string name="storage_category" msgid="2287342585424631813">"Lagring"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index fe743e8..005f0cd 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"अन्तर्निर्मित स्पिकर"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"टिभीको अडियो"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"जोड्ने क्रममा समस्या भयो। यन्त्रलाई निष्क्रिय पारेर फेरि अन गर्नुहोस्"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"कनेक्ट गर्न सकिएन"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"तारयुक्त अडियो यन्त्र"</string>
<string name="help_label" msgid="3528360748637781274">"मद्दत र प्रतिक्रिया"</string>
<string name="storage_category" msgid="2287342585424631813">"भण्डारण"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index f49829f..ffde98a 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Ingebouwde speaker"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Tv-audio"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem bij verbinding maken. Zet het apparaat uit en weer aan."</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Kan geen verbinding maken"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedraad audioapparaat"</string>
<string name="help_label" msgid="3528360748637781274">"Hulp en feedback"</string>
<string name="storage_category" msgid="2287342585424631813">"Opslag"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index ed202fa..0ba9cb6 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"ବିଲ୍ଟ-ଇନ ସ୍ପିକର"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"ଟିଭି ଅଡିଓ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ସଂଯୋଗ କରିବାରେ ସମସ୍ୟା ହେଉଛି। ଡିଭାଇସ୍ ବନ୍ଦ କରି ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"କନେକ୍ଟ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ତାରଯୁକ୍ତ ଅଡିଓ ଡିଭାଇସ୍"</string>
<string name="help_label" msgid="3528360748637781274">"ସାହାଯ୍ୟ ଓ ମତାମତ"</string>
<string name="storage_category" msgid="2287342585424631813">"ଷ୍ଟୋରେଜ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index ee0f761..08106e4 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"ਬਿਲਟ-ਇਨ ਸਪੀਕਰ"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"ਟੀਵੀ ਆਡੀਓ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ਕਨੈਕਟ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ ਆਈ। ਡੀਵਾਈਸ ਨੂੰ ਬੰਦ ਕਰਕੇ ਵਾਪਸ ਚਾਲੂ ਕਰੋ"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ਤਾਰ ਵਾਲਾ ਆਡੀਓ ਡੀਵਾਈਸ"</string>
<string name="help_label" msgid="3528360748637781274">"ਮਦਦ ਅਤੇ ਵਿਚਾਰ"</string>
<string name="storage_category" msgid="2287342585424631813">"ਸਟੋਰੇਜ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index fec5bf1..d8d2b0b 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Wbudowany głośnik"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Audio z telewizora"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem z połączeniem. Wyłącz i ponownie włącz urządzenie"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Nie można się połączyć"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Przewodowe urządzenie audio"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoc i opinie"</string>
<string name="storage_category" msgid="2287342585424631813">"Pamięć wewnętrzna"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 3486037..194af5b 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Altifalante integrado"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Áudio da TV"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema ao ligar. Desligue e volte a ligar o dispositivo."</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Não é possível estabelecer ligação"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fios"</string>
<string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string>
<string name="storage_category" msgid="2287342585424631813">"Armazenamento"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 8965a0c..7d07d54 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Difuzor încorporat"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Audio TV"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problemă la conectare. Oprește și repornește dispozitivul."</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Nu se poate conecta"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispozitiv audio cu fir"</string>
<string name="help_label" msgid="3528360748637781274">"Ajutor și feedback"</string>
<string name="storage_category" msgid="2287342585424631813">"Stocare"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 2da6708..55ff696f 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Встроенный динамик"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Аудиовыход телевизора"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ошибка подключения. Выключите и снова включите устройство."</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Ошибка подключения"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Проводное аудиоустройство"</string>
<string name="help_label" msgid="3528360748637781274">"Справка/отзыв"</string>
<string name="storage_category" msgid="2287342585424631813">"Хранилище"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 1c57acd..4546f4b 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"එකට තැනූ ශබ්දවාහිනීය"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"රූපවාහිනී ශ්රව්ය"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"සම්බන්ධ කිරීමේ ගැටලුවකි උපාංගය ක්රියාවිරහිත කර & ආපසු ක්රියාත්මක කරන්න"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"සම්බන්ධ විය නොහැක"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"රැහැන්ගත කළ ඕඩියෝ උපාංගය"</string>
<string name="help_label" msgid="3528360748637781274">"උදවු & ප්රතිපෝෂණ"</string>
<string name="storage_category" msgid="2287342585424631813">"ගබඩාව"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 5534ed0..7578d06 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -627,11 +627,10 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Vstavaný reproduktor"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Zvuk televízora"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Pri pripájaní sa vyskytol problém. Zariadenie vypnite a znova zapnite."</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Nedá sa pripojiť"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio zariadenie s káblom"</string>
<string name="help_label" msgid="3528360748637781274">"Pomocník a spätná väzba"</string>
- <string name="storage_category" msgid="2287342585424631813">"Priestor"</string>
+ <string name="storage_category" msgid="2287342585424631813">"Ukladací priestor"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Zdieľané údaje"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Zobrazenie a úprava zdieľaných údajov"</string>
<string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Pre tohto používateľa nie sú k dispozícii žiadne zdieľané údaje."</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index be7b115..4b268cb 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Vgrajen zvočnik"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Zvok televizorja"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Težava pri povezovanju. Napravo izklopite in znova vklopite."</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Povezave ni mogoče vzpostaviti"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žična zvočna naprava"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoč in povratne informacije"</string>
<string name="storage_category" msgid="2287342585424631813">"Shramba"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 06da1722..a296f87 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Altoparlanti i integruar"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Audioja e televizorit"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem me lidhjen. Fike dhe ndize përsëri pajisjen"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Nuk mund të lidhet"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Pajisja audio me tel"</string>
<string name="help_label" msgid="3528360748637781274">"Ndihma dhe komentet"</string>
<string name="storage_category" msgid="2287342585424631813">"Hapësira ruajtëse"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 63d1502..defea3a 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Уграђени звучник"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Звук ТВ-а"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем при повезивању. Искључите уређај, па га поново укључите"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Повезивање није успело"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичани аудио уређај"</string>
<string name="help_label" msgid="3528360748637781274">"Помоћ и повратне информације"</string>
<string name="storage_category" msgid="2287342585424631813">"Меморијски простор"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 131cca7..d03b99b 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Inbyggd högtalare"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Tv-ljud"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Det gick inte att ansluta. Stäng av enheten och slå på den igen"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Det går inte att ansluta"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ljudenhet med kabelanslutning"</string>
<string name="help_label" msgid="3528360748637781274">"Hjälp och feedback"</string>
<string name="storage_category" msgid="2287342585424631813">"Lagring"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 1cb95a7..0755ce8 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Spika iliyojumuishwa"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Sauti ya Televisheni"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kuna tatizo la kuunganisha kwenye Intaneti. Zima kisha uwashe kifaa"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Imeshindwa kuunganisha"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kifaa cha sauti kinachotumia waya"</string>
<string name="help_label" msgid="3528360748637781274">"Usaidizi na maoni"</string>
<string name="storage_category" msgid="2287342585424631813">"Hifadhi"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index cc8a36f..a67f35e 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"உள்ளமைந்த ஸ்பீக்கர்"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"டிவி ஆடியோ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"இணைப்பதில் சிக்கல். சாதனத்தை ஆஃப் செய்து மீண்டும் ஆன் செய்யவும்"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"இணைக்க முடியவில்லை"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"வயருடன்கூடிய ஆடியோ சாதனம்"</string>
<string name="help_label" msgid="3528360748637781274">"உதவியும் கருத்தும்"</string>
<string name="storage_category" msgid="2287342585424631813">"சேமிப்பகம்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index ccb5aa8..ffca18d 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"బిల్ట్-ఇన్ స్పీకర్"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"టీవీ ఆడియో"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"కనెక్ట్ చేయడంలో సమస్య ఉంది. పరికరాన్ని ఆఫ్ చేసి, ఆపై తిరిగి ఆన్ చేయండి"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"కనెక్ట్ చేయడం సాధ్యపడలేదు"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"వైర్ గల ఆడియో పరికరం"</string>
<string name="help_label" msgid="3528360748637781274">"సహాయం & ఫీడ్బ్యాక్"</string>
<string name="storage_category" msgid="2287342585424631813">"స్టోరేజ్"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 08d2017..fce95ac 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"ลำโพงในตัว"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"เสียงจากทีวี"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"เกิดปัญหาในการเชื่อมต่อ ปิดอุปกรณ์แล้วเปิดใหม่อีกครั้ง"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"เชื่อมต่อไม่ได้"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"อุปกรณ์เสียงแบบมีสาย"</string>
<string name="help_label" msgid="3528360748637781274">"ความช่วยเหลือและความคิดเห็น"</string>
<string name="storage_category" msgid="2287342585424631813">"พื้นที่เก็บข้อมูล"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 14069b9..011c8d7 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Built-in na speaker"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Audio ng TV"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Nagkaproblema sa pagkonekta. I-off at pagkatapos ay i-on ang device"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Hindi makakonekta"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired na audio device"</string>
<string name="help_label" msgid="3528360748637781274">"Tulong at feedback"</string>
<string name="storage_category" msgid="2287342585424631813">"Storage"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 7021003..4285230 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Dahili hoparlör"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV Sesi"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Bağlanırken sorun oluştu. Cihazı kapatıp tekrar açın"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Bağlanılamıyor"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kablolu ses cihazı"</string>
<string name="help_label" msgid="3528360748637781274">"Yardım ve geri bildirim"</string>
<string name="storage_category" msgid="2287342585424631813">"Depolama"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index a0ff95a..48aa063 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"پہلے سے شامل اسپیکر"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV آڈیو"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"منسلک کرنے میں مسئلہ پیش آ گیا۔ آلہ کو آف اور بیک آن کریں"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"منسلک نہیں ہو سکتا"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"وائرڈ آڈیو آلہ"</string>
<string name="help_label" msgid="3528360748637781274">"مدد اور تاثرات"</string>
<string name="storage_category" msgid="2287342585424631813">"اسٹوریج"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 0a65885..8969c0d 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Ichki karnay"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"TV Audio"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ulanishda muammo yuz berdi. Qurilmani oʻchiring va yoqing"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Ulanmadi"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio qurilma"</string>
<string name="help_label" msgid="3528360748637781274">"Yordam/fikr-mulohaza"</string>
<string name="storage_category" msgid="2287342585424631813">"Xotira"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 5e1e3da..e456617 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Loa tích hợp"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Âm thanh TV"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sự cố kết nối. Hãy tắt thiết bị rồi bật lại"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Không kết nối được"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Thiết bị âm thanh có dây"</string>
<string name="help_label" msgid="3528360748637781274">"Trợ giúp và phản hồi"</string>
<string name="storage_category" msgid="2287342585424631813">"Bộ nhớ"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 6bf27b3..6fe9e2a 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"内置扬声器"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"电视音频"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"连接时遇到问题。请关闭并重新开启设备"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"无法连接"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有线音频设备"</string>
<string name="help_label" msgid="3528360748637781274">"帮助和反馈"</string>
<string name="storage_category" msgid="2287342585424631813">"存储空间"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 9f96b5b..23ee3c9 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"內置喇叭"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"電視音訊"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連接,請關閉裝置然後重新開機"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"無法連線"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音響裝置"</string>
<string name="help_label" msgid="3528360748637781274">"說明與意見反映"</string>
<string name="storage_category" msgid="2287342585424631813">"儲存空間"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index e5f29e9..32151eea 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"內建喇叭"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"電視音訊"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連線,請關閉裝置後再重新開啟"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"無法連線"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音訊裝置"</string>
<string name="help_label" msgid="3528360748637781274">"說明與意見回饋"</string>
<string name="storage_category" msgid="2287342585424631813">"儲存空間"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index c587678..e4f3c57 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -627,8 +627,7 @@
<string name="tv_media_transfer_internal_speakers" msgid="4662765121700213785">"Isipikha esakhelwe ngaphakathi"</string>
<string name="tv_media_transfer_hdmi_title" msgid="6715658310934507444">"Umsindo we-TV"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Inkinga yokuxhumeka. Vala idivayisi futhi uphinde uyivule"</string>
- <!-- no translation found for bluetooth_key_missing_subtext (1003639333895028298) -->
- <skip />
+ <string name="bluetooth_key_missing_subtext" msgid="1003639333895028298">"Ayikwazi ukuxhuma"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Idivayisi yomsindo enentambo"</string>
<string name="help_label" msgid="3528360748637781274">"Usizo nempendulo"</string>
<string name="storage_category" msgid="2287342585424631813">"Isitoreji"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 1297aa3..6a7e048 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -288,7 +288,7 @@
<string name="bluetooth_profile_hid">Input device</string>
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the PAN profile (accessing Internet through remote device). [CHAR LIMIT=40] -->
<string name="bluetooth_profile_pan">Internet access</string>
- <!-- Bluetooth settings. The user-visible string that is used whenever referring to the PBAP profile. [CHAR LIMIT=40] -->
+ <!-- Bluetooth settings. The user-visible string that is used whenever referring to the PBAP profile. [CHAR LIMIT=80] -->
<string name="bluetooth_profile_pbap">Allow access to contacts and call history</string>
<!-- Bluetooth settings. The user-visible summary string that is used whenever referring to the PBAP profile (sharing contacts). [CHAR LIMIT=60] -->
<string name="bluetooth_profile_pbap_summary">Info will be used for call announcements and more</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index edec2e4..78b307e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -25,6 +25,7 @@
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
@@ -58,6 +59,7 @@
import com.android.settingslib.utils.ThreadUtils;
import com.android.settingslib.widget.AdaptiveOutlineDrawable;
+import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
@@ -75,6 +77,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
@@ -396,6 +399,9 @@
}
}
Log.d(TAG, "Disconnect " + this);
+ if (Flags.enableLeAudioSharing()) {
+ removeBroadcastSource(ImmutableSet.of(mDevice));
+ }
mDevice.disconnect();
}
// Disconnect PBAP server in case its connected
@@ -608,6 +614,16 @@
final BluetoothDevice dev = mDevice;
if (dev != null) {
mUnpairing = true;
+ if (Flags.enableLeAudioSharing()) {
+ Set<BluetoothDevice> devicesToRemoveSource = new HashSet<>();
+ devicesToRemoveSource.add(dev);
+ if (getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+ for (CachedBluetoothDevice member : getMemberDevice()) {
+ devicesToRemoveSource.add(member.getDevice());
+ }
+ }
+ removeBroadcastSource(devicesToRemoveSource);
+ }
final boolean successful = dev.removeBond();
if (successful) {
releaseLruCache();
@@ -622,6 +638,25 @@
}
}
+ @WorkerThread
+ private void removeBroadcastSource(Set<BluetoothDevice> devices) {
+ if (mProfileManager == null || devices.isEmpty()) return;
+ LocalBluetoothLeBroadcast broadcast = mProfileManager.getLeAudioBroadcastProfile();
+ LocalBluetoothLeBroadcastAssistant assistant =
+ mProfileManager.getLeAudioBroadcastAssistantProfile();
+ if (broadcast != null && assistant != null && broadcast.isEnabled(null)) {
+ for (BluetoothDevice device : devices) {
+ for (BluetoothLeBroadcastReceiveState state : assistant.getAllSources(device)) {
+ if (BluetoothUtils.D) {
+ Log.d(TAG, "Remove broadcast source " + state.getBroadcastId()
+ + " from device " + device.getAnonymizedAddress());
+ }
+ assistant.removeSource(device, state.getSourceId());
+ }
+ }
+ }
+ }
+
public int getProfileConnectionState(LocalBluetoothProfile profile) {
return profile != null
? profile.getConnectionStatus(mDevice)
@@ -1778,9 +1813,55 @@
@Nullable
private BatteryLevelsInfo getBatteryOfLeAudioDeviceComponents() {
- // TODO(b/397847825): Implement the logic to get battery of LE audio device components.
- return null;
+ LeAudioProfile leAudio = mProfileManager.getLeAudioProfile();
+ if (leAudio == null) {
+ return null;
+ }
+ int leftBattery = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+ int rightBattery = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+ int overallBattery = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+
+ Set<BluetoothDevice> allDevices =
+ Stream.concat(
+ mMemberDevices.stream().map(CachedBluetoothDevice::getDevice),
+ Stream.of(mDevice))
+ .collect(Collectors.toSet());
+ for (BluetoothDevice device : allDevices) {
+ int battery = device.getBatteryLevel();
+ if (battery <= BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
+ continue;
+ }
+ int deviceId = leAudio.getAudioLocation(device);
+ boolean isLeft = (deviceId & LeAudioProfile.LEFT_DEVICE_ID) != 0;
+ boolean isRight = (deviceId & LeAudioProfile.RIGHT_DEVICE_ID) != 0;
+ boolean isLeftRight = isLeft && isRight;
+ // We should expect only one device assign to one side, but if it happens,
+ // we don't care which one.
+ if (isLeftRight) {
+ overallBattery = battery;
+ } else if (isLeft) {
+ leftBattery = battery;
+ } else if (isRight) {
+ rightBattery = battery;
+ }
+ }
+ overallBattery = getMinBatteryLevels(
+ Arrays.stream(new int[]{leftBattery, rightBattery, overallBattery}));
+
+ Log.d(TAG, "Acquired battery info from Bluetooth service for le audio device "
+ + mDevice.getAnonymizedAddress()
+ + " left battery: " + leftBattery
+ + " right battery: " + rightBattery
+ + " overall battery: " + overallBattery);
+ return overallBattery > BluetoothDevice.BATTERY_LEVEL_UNKNOWN
+ ? new BatteryLevelsInfo(
+ leftBattery,
+ rightBattery,
+ BluetoothDevice.BATTERY_LEVEL_UNKNOWN,
+ overallBattery)
+ : null;
}
+
private CharSequence getTvBatterySummary(int mainBattery, int leftBattery, int rightBattery,
int lowBatteryColorRes) {
// Since there doesn't seem to be a way to use format strings to add the
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
index 155c7e6..2ec25a1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
@@ -37,12 +37,35 @@
import androidx.annotation.RequiresApi;
import com.android.settingslib.R;
+import com.android.settingslib.flags.Flags;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
public class LeAudioProfile implements LocalBluetoothProfile {
+ public static final int LEFT_DEVICE_ID = BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT
+ | BluetoothLeAudio.AUDIO_LOCATION_BACK_LEFT
+ | BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT_OF_CENTER
+ | BluetoothLeAudio.AUDIO_LOCATION_SIDE_LEFT
+ | BluetoothLeAudio.AUDIO_LOCATION_TOP_FRONT_LEFT
+ | BluetoothLeAudio.AUDIO_LOCATION_TOP_BACK_LEFT
+ | BluetoothLeAudio.AUDIO_LOCATION_TOP_SIDE_LEFT
+ | BluetoothLeAudio.AUDIO_LOCATION_BOTTOM_FRONT_LEFT
+ | BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT_WIDE
+ | BluetoothLeAudio.AUDIO_LOCATION_LEFT_SURROUND;
+ public static final int RIGHT_DEVICE_ID = BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT
+ | BluetoothLeAudio.AUDIO_LOCATION_BACK_RIGHT
+ | BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT_OF_CENTER
+ | BluetoothLeAudio.AUDIO_LOCATION_SIDE_RIGHT
+ | BluetoothLeAudio.AUDIO_LOCATION_TOP_FRONT_RIGHT
+ | BluetoothLeAudio.AUDIO_LOCATION_TOP_BACK_RIGHT
+ | BluetoothLeAudio.AUDIO_LOCATION_TOP_SIDE_RIGHT
+ | BluetoothLeAudio.AUDIO_LOCATION_BOTTOM_FRONT_RIGHT
+ | BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT_WIDE
+ | BluetoothLeAudio.AUDIO_LOCATION_RIGHT_SURROUND;
+
private static final String TAG = "LeAudioProfile";
private static boolean DEBUG = true;
@@ -59,6 +82,10 @@
// Order of this profile in device profiles list
private static final int ORDINAL = 1;
+ // Cached callbacks being registered before service is connected.
+ private ConcurrentHashMap<BluetoothLeAudio.Callback, Executor>
+ mCachedCallbackExecutorMap = new ConcurrentHashMap<>();
+
// These callbacks run on the main thread.
private final class LeAudioServiceListener implements BluetoothProfile.ServiceListener {
@@ -88,7 +115,19 @@
// Check current list of CachedDevices to see if any are hearing aid devices.
mDeviceManager.updateHearingAidsDevices();
mProfileManager.callServiceConnectedListeners();
- mIsProfileReady = true;
+ if (!mIsProfileReady) {
+ mIsProfileReady = true;
+ if (Flags.adoptPrimaryGroupManagementApiV2()) {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "onServiceConnected, register mCachedCallbackExecutorMap = "
+ + mCachedCallbackExecutorMap);
+ }
+ mCachedCallbackExecutorMap.forEach(
+ (callback, executor) -> registerCallback(executor, callback));
+ }
+ }
}
public void onServiceDisconnected(int profile) {
@@ -96,7 +135,12 @@
Log.d(TAG, "Bluetooth service disconnected");
}
mProfileManager.callServiceDisconnectedListeners();
- mIsProfileReady = false;
+ if (mIsProfileReady) {
+ mIsProfileReady = false;
+ if (Flags.adoptPrimaryGroupManagementApiV2()) {
+ mCachedCallbackExecutorMap.clear();
+ }
+ }
}
}
@@ -367,6 +411,9 @@
@NonNull BluetoothLeAudio.Callback callback) {
if (mService == null) {
Log.w(TAG, "Proxy not attached to service. Cannot register callback.");
+ if (Flags.adoptPrimaryGroupManagementApiV2()) {
+ mCachedCallbackExecutorMap.putIfAbsent(callback, executor);
+ }
return;
}
mService.registerCallback(executor, callback);
@@ -384,6 +431,9 @@
* callback is registered
*/
public void unregisterCallback(@NonNull BluetoothLeAudio.Callback callback) {
+ if (Flags.adoptPrimaryGroupManagementApiV2()) {
+ mCachedCallbackExecutorMap.remove(callback);
+ }
if (mService == null) {
Log.w(TAG, "Proxy not attached to service. Cannot unregister callback.");
return;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
index 2ed437c..4d38f1d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
@@ -487,7 +487,7 @@
context,
lifecycleOwner.lifecycleScope,
ssid,
- WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW,
+ WindowManager.LayoutParams.TYPE_APPLICATION,
{ intent -> context.startActivity(intent) },
onAllowed
)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index b4384b7..146b667 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -2357,6 +2357,78 @@
Integer.parseInt(TWS_BATTERY_LEFT));
}
+ @Test
+ public void getBatteryLevelsInfo_leAudioDeviceWithBattery_returnBatteryLevelsInfo() {
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn(
+ "false".getBytes());
+ when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
+ updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_CONNECTED);
+ mCachedDevice.addMemberDevice(mSubCachedDevice);
+ when(mLeAudioProfile.getAudioLocation(mSubDevice)).thenReturn(
+ BluetoothLeAudio.AUDIO_LOCATION_BACK_LEFT);
+ when(mSubDevice.getBatteryLevel()).thenReturn(Integer.parseInt(TWS_BATTERY_LEFT));
+ when(mLeAudioProfile.getAudioLocation(mDevice)).thenReturn(
+ BluetoothLeAudio.AUDIO_LOCATION_SIDE_RIGHT);
+ when(mDevice.getBatteryLevel()).thenReturn(Integer.parseInt(TWS_BATTERY_RIGHT));
+
+ BatteryLevelsInfo batteryLevelsInfo = mCachedDevice.getBatteryLevelsInfo();
+
+ assertThat(batteryLevelsInfo.getLeftBatteryLevel()).isEqualTo(
+ Integer.parseInt(TWS_BATTERY_LEFT));
+ assertThat(batteryLevelsInfo.getRightBatteryLevel()).isEqualTo(
+ Integer.parseInt(TWS_BATTERY_RIGHT));
+ assertThat(batteryLevelsInfo.getCaseBatteryLevel()).isEqualTo(
+ BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
+ assertThat(batteryLevelsInfo.getOverallBatteryLevel()).isEqualTo(
+ Integer.parseInt(TWS_BATTERY_LEFT));
+ }
+
+ @Test
+ public void disconnect_removeBroadcastSource() {
+ when(mCachedDevice.getGroupId()).thenReturn(1);
+ when(mSubCachedDevice.getGroupId()).thenReturn(1);
+ mCachedDevice.addMemberDevice(mSubCachedDevice);
+ LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class);
+ LocalBluetoothLeBroadcastAssistant assistant = mock(
+ LocalBluetoothLeBroadcastAssistant.class);
+ when(mProfileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast);
+ when(mProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant);
+ when(broadcast.isEnabled(null)).thenReturn(true);
+ BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+ when(state.getSourceId()).thenReturn(1);
+ when(assistant.getAllSources(mDevice)).thenReturn(ImmutableList.of(state));
+ when(assistant.getAllSources(mSubDevice)).thenReturn(ImmutableList.of(state));
+
+ mCachedDevice.disconnect();
+ verify(assistant).removeSource(mDevice, /* sourceId= */1);
+ verify(assistant).removeSource(mSubDevice, /* sourceId= */1);
+ verify(mDevice).disconnect();
+ verify(mSubDevice).disconnect();
+ }
+
+ @Test
+ public void unpair_removeBroadcastSource() {
+ when(mCachedDevice.getGroupId()).thenReturn(1);
+ when(mSubCachedDevice.getGroupId()).thenReturn(1);
+ mCachedDevice.addMemberDevice(mSubCachedDevice);
+ when(mCachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class);
+ LocalBluetoothLeBroadcastAssistant assistant = mock(
+ LocalBluetoothLeBroadcastAssistant.class);
+ when(mProfileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast);
+ when(mProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant);
+ when(broadcast.isEnabled(null)).thenReturn(true);
+ BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+ when(state.getSourceId()).thenReturn(1);
+ when(assistant.getAllSources(mDevice)).thenReturn(ImmutableList.of(state));
+ when(assistant.getAllSources(mSubDevice)).thenReturn(ImmutableList.of(state));
+
+ mCachedDevice.unpair();
+ verify(assistant).removeSource(mDevice, /* sourceId= */1);
+ verify(assistant).removeSource(mSubDevice, /* sourceId= */1);
+ verify(mDevice).removeBond();
+ }
+
private void updateProfileStatus(LocalBluetoothProfile profile, int status) {
doReturn(status).when(profile).getConnectionStatus(mDevice);
mCachedDevice.onProfileStateChanged(profile, status);
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index d0f8462..463e94b 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -464,6 +464,7 @@
VALIDATORS.put(Secure.MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED,
new InclusiveIntegerRangeValidator(0, 1));
VALIDATORS.put(Secure.ADVANCED_PROTECTION_MODE, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.AAPM_USB_DATA_PROTECTION, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.DISABLE_ADAPTIVE_AUTH_LIMIT_LOCK, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.FACE_APP_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.FACE_KEYGUARD_ENABLED, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 7179cbd..e9b6c73 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -642,6 +642,7 @@
private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS =
newHashSet(
+ Settings.Secure.AAPM_USB_DATA_PROTECTION,
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, // Deprecated since O.
Settings.Secure.ALLOW_PRIMARY_GAIA_ACCOUNT_REMOVAL_FOR_TESTS,
diff --git a/packages/Shell/res/values-en-rCA-watch/strings.xml b/packages/Shell/res/values-en-rCA-watch/strings.xml
new file mode 100644
index 0000000..23f83c4
--- /dev/null
+++ b/packages/Shell/res/values-en-rCA-watch/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bugreport_in_progress_title" msgid="5351751440620800623">"Bug report <xliff:g id="ID">#%1$d</xliff:g> is <xliff:g id="PERCENTAGE">%2$s</xliff:g> complete"</string>
+</resources>
diff --git a/packages/StatementService/Android.bp b/packages/StatementService/Android.bp
index 39b0302..3fc9aab 100644
--- a/packages/StatementService/Android.bp
+++ b/packages/StatementService/Android.bp
@@ -32,7 +32,11 @@
},
target_sdk_version: "29",
platform_apis: true,
+ system_ext_specific: true,
privileged: true,
+ required: [
+ "privapp_whitelist_com.android.statementservice",
+ ],
certificate: "platform",
static_libs: [
"StatementServiceParser",
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 7f45443..2b17ae4 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -220,6 +220,7 @@
"tests/src/**/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt",
"tests/src/**/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt",
"tests/src/**/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosAdapterTest.kt",
"tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt",
"tests/src/**/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt",
"tests/src/**/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt",
@@ -356,7 +357,9 @@
"tests/src/**/systemui/qs/tiles/AlarmTileTest.kt",
"tests/src/**/systemui/qs/tiles/BluetoothTileTest.kt",
"tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosAdapterTest.kt",
"tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt",
+ "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionKairosAdapterTelephonySmokeTests.kt",
"tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt",
"tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt",
"tests/src/**/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt",
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
index db2fbd9..60625f4 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
@@ -143,7 +143,7 @@
final Display display = mDisplayManager.getDisplay(DEFAULT_DISPLAY);
final Context uiContext = mService.createWindowContext(
display, TYPE_ACCESSIBILITY_OVERLAY, /* options= */null);
- final WindowManager windowManager = WindowManagerUtils.getWindowManager(uiContext);
+ final WindowManager windowManager = uiContext.getSystemService(WindowManager.class);
mLayout = new A11yMenuFrameLayout(uiContext);
updateLayoutPosition(uiContext);
inflateLayoutAndSetOnTouchListener(mLayout, uiContext);
diff --git a/packages/SystemUI/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig
index c6bc1c7..3cb3025 100644
--- a/packages/SystemUI/aconfig/accessibility.aconfig
+++ b/packages/SystemUI/aconfig/accessibility.aconfig
@@ -155,13 +155,3 @@
purpose: PURPOSE_BUGFIX
}
}
-
-flag {
- name: "hearing_devices_input_routing_ui_improvement"
- namespace: "accessibility"
- description: "UI improvement for hearing device input routing feature"
- bug: "397314200"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a696b65..a93291f 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -559,6 +559,13 @@
}
flag {
+ name: "debug_live_updates_promote_all"
+ namespace: "systemui"
+ description: "Promote all notifications to Live Updates (RONs). (For testing/debugging only, do not promote/release!)"
+ bug: "404838239"
+}
+
+flag {
name: "compose_bouncer"
namespace: "systemui"
description: "Use the new compose bouncer in SystemUI"
@@ -1994,6 +2001,13 @@
}
flag {
+ name: "notification_animated_actions_treatment"
+ namespace: "systemui"
+ description: "Special UI treatment for animated actions and replys"
+ bug: "383567383"
+}
+
+flag {
name: "show_audio_sharing_slider_in_volume_panel"
namespace: "cross_device_experiences"
description: "Show two sliders in volume panel when audio sharing."
@@ -2179,3 +2193,18 @@
description: "Allow users to add shortcuts to open apps that are not present in the apps category in shortcut helper by default"
bug: "394290928"
}
+
+flag {
+ name: "use_aad_prox_sensor"
+ namespace: "systemui"
+ description: "Use AAD proximity sensor if flag is enabled and sensor is present"
+ bug: "402534470"
+}
+
+flag {
+ name: "enable_underlay"
+ namespace: "ailabs"
+ description: "Enable the underlay additional layer"
+ bug: "403422950"
+}
+
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
index fdb07bd..576ff61 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
@@ -83,7 +83,7 @@
ViewTransitionRegistry.instance
} else {
null
- }
+ },
) : ActivityTransitionAnimator.Controller {
override val isLaunching: Boolean = true
@@ -313,9 +313,17 @@
// visibility that is saved by `setShouldBlockVisibilityChanges()` for a later restoration.
(ghostedView as? LaunchableView)?.setShouldBlockVisibilityChanges(true)
- // Create a ghost of the view that will be moving and fading out. This allows to fade out
- // the content before fading out the background.
- ghostView = GhostView.addGhost(ghostedView, transitionContainer)
+ try {
+ // Create a ghost of the view that will be moving and fading out. This allows to fade
+ // out the content before fading out the background.
+ ghostView = GhostView.addGhost(ghostedView, transitionContainer)
+ } catch (e: Exception) {
+ // It is not 100% clear what conditions cause this exception to happen in practice, and
+ // we could never reproduce it, but it does show up extremely rarely. We already handle
+ // the scenario where ghostView is null, so we just avoid crashing and log the error.
+ // See b/315858472 for an investigation of the issue.
+ Log.e(TAG, "Failed to create ghostView", e)
+ }
// [GhostView.addGhost], the result of which is our [ghostView], creates a [GhostView], and
// adds it first to a [FrameLayout] container. It then adds _that_ container to an
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java
index 060f0c9..9e08317 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java
@@ -199,7 +199,9 @@
info.releaseAllSurfaces();
// Make sure that the transition leashes created are not leaked.
for (SurfaceControl leash : leashMap.values()) {
- finishTransaction.reparent(leash, null);
+ if (leash.isValid()) {
+ finishTransaction.reparent(leash, null);
+ }
}
// Don't release here since launcher might still be using them. Instead
// let launcher release them (eg. via RemoteAnimationTargets)
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/OffsetOverscrollEffect.kt b/packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/OffsetOverscrollEffect.kt
index 07a571b..c411d27 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/OffsetOverscrollEffect.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/OffsetOverscrollEffect.kt
@@ -36,6 +36,7 @@
import kotlin.math.roundToInt
import kotlinx.coroutines.CoroutineScope
+/** Returns a [remember]ed [OffsetOverscrollEffect]. */
@Composable
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
fun rememberOffsetOverscrollEffect(
@@ -63,7 +64,10 @@
private val animationSpec: AnimationSpec<Float>,
) : OverscrollFactory {
override fun createOverscrollEffect(): OverscrollEffect {
- return OffsetOverscrollEffect(animationScope, animationSpec)
+ return OffsetOverscrollEffect(
+ animationScope = animationScope,
+ animationSpec = animationSpec,
+ )
}
}
@@ -80,11 +84,11 @@
return layout(placeable.width, placeable.height) {
val offsetPx = computeOffset(density = this@measure, overscrollDistance)
if (offsetPx != 0) {
- placeable.placeRelativeWithLayer(
+ placeable.placeWithLayer(
with(requireConverter()) { offsetPx.toIntOffset() }
)
} else {
- placeable.placeRelative(0, 0)
+ placeable.place(0, 0)
}
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
index 5fac686..3e1252b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
@@ -48,6 +48,7 @@
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
import com.android.systemui.statusbar.VibratorHelper
+import com.google.android.msdl.domain.MSDLPlayer
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -66,6 +67,7 @@
private val deviceEntryBackgroundViewModel: Lazy<DeviceEntryBackgroundViewModel>,
private val falsingManager: Lazy<FalsingManager>,
private val vibratorHelper: Lazy<VibratorHelper>,
+ private val msdlPlayer: Lazy<MSDLPlayer>,
@LongPressTouchLog private val logBuffer: LogBuffer,
) {
@Composable
@@ -90,6 +92,7 @@
deviceEntryBackgroundViewModel.get(),
falsingManager.get(),
vibratorHelper.get(),
+ msdlPlayer.get(),
overrideColor,
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
index 8f0fb20..cb03119 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
@@ -39,6 +39,7 @@
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.onPlaced
@@ -266,7 +267,10 @@
BrightnessSliderContainer(
viewModel = viewModel.brightnessSliderViewModel,
containerColors =
- ContainerColors.singleColor(OverlayShade.Colors.PanelBackground),
+ ContainerColors(
+ idleColor = Color.Transparent,
+ mirrorColor = OverlayShade.Colors.PanelBackground,
+ ),
modifier = Modifier.fillMaxWidth(),
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/session/shared/SessionStorage.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/session/shared/SessionStorage.kt
index dc58919..d1cbeca 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/session/shared/SessionStorage.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/session/shared/SessionStorage.kt
@@ -16,6 +16,7 @@
package com.android.systemui.scene.session.shared
+import androidx.compose.runtime.RememberObserver
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
@@ -39,6 +40,9 @@
/** Clears the data store; any downstream usage within `@Composable`s will be recomposed. */
fun clear() {
+ for (storageEntry in _storage.values) {
+ (storageEntry.stored as? RememberObserver)?.onForgotten()
+ }
_storage = hashMapOf()
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
index 068218a..89c54bc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
@@ -37,7 +37,6 @@
import androidx.compose.foundation.layout.waterfall
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.overscroll
-import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
@@ -46,6 +45,7 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.platform.LocalResources
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@@ -55,7 +55,10 @@
import com.android.compose.windowsizeclass.LocalWindowSizeClass
import com.android.mechanics.behavior.VerticalExpandContainerSpec
import com.android.mechanics.behavior.verticalExpandContainerBackground
+import com.android.systemui.Flags
import com.android.systemui.res.R
+import com.android.systemui.shade.ui.ShadeColors.notificationScrim
+import com.android.systemui.shade.ui.ShadeColors.shadePanel
import com.android.systemui.shade.ui.composable.OverlayShade.rememberShadeExpansionMotion
/** Renders a lightweight shade UI container, as an overlay. */
@@ -189,9 +192,15 @@
}
object Colors {
- val ScrimBackground = Color(0f, 0f, 0f, alpha = 0.2f)
+ val ScrimBackground: Color
+ @Composable
+ @ReadOnlyComposable
+ get() = Color(LocalResources.current.notificationScrim(Flags.notificationShadeBlur()))
+
val PanelBackground: Color
- @Composable @ReadOnlyComposable get() = MaterialTheme.colorScheme.surfaceContainer
+ @Composable
+ @ReadOnlyComposable
+ get() = Color(LocalResources.current.shadePanel(Flags.notificationShadeBlur()))
}
object Dimensions {
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
index 5f71b19..8846668 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
@@ -111,10 +111,6 @@
override fun onZenDataChanged(data: ZenData) {}
- override fun onFontAxesChanged(axes: ClockAxisStyle) {
- view.updateAxes(axes)
- }
-
override var isReactiveTouchInteractionEnabled
get() = view.isReactiveTouchInteractionEnabled
set(value) {
@@ -152,6 +148,13 @@
override fun onFidgetTap(x: Float, y: Float) {
view.animateFidget(x, y)
}
+
+ private var hasFontAxes = false
+
+ override fun onFontAxesChanged(style: ClockAxisStyle) {
+ view.updateAxes(style, isAnimated = hasFontAxes)
+ hasFontAxes = true
+ }
}
override val faceEvents =
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index 3cfa78d..450cece 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -231,8 +231,6 @@
override fun onAlarmDataChanged(data: AlarmData) {}
override fun onZenDataChanged(data: ZenData) {}
-
- override fun onFontAxesChanged(axes: ClockAxisStyle) {}
}
open inner class DefaultClockAnimations(
@@ -285,6 +283,8 @@
override fun onPositionUpdated(distance: Float, fraction: Float) {}
override fun onFidgetTap(x: Float, y: Float) {}
+
+ override fun onFontAxesChanged(style: ClockAxisStyle) {}
}
inner class LargeClockAnimations(
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
index 8744357..84f45fc 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
@@ -99,12 +99,6 @@
smallClock.events.onZenDataChanged(data)
largeClock.events.onZenDataChanged(data)
}
-
- override fun onFontAxesChanged(axes: ClockAxisStyle) {
- val fontAxes = ClockAxisStyle(getDefaultAxes(clockCtx.settings).merge(axes))
- smallClock.events.onFontAxesChanged(fontAxes)
- largeClock.events.onFontAxesChanged(fontAxes)
- }
}
override fun initialize(
@@ -113,10 +107,10 @@
foldFraction: Float,
clockListener: ClockEventListener?,
) {
- events.onFontAxesChanged(clockCtx.settings.axes)
smallClock.run {
layerController.onViewBoundsChanged = { clockListener?.onBoundsChanged(it) }
events.onThemeChanged(theme.copy(isDarkTheme = isDarkTheme))
+ animations.onFontAxesChanged(clockCtx.settings.axes)
animations.doze(dozeFraction)
animations.fold(foldFraction)
events.onTimeTick()
@@ -125,6 +119,7 @@
largeClock.run {
layerController.onViewBoundsChanged = { clockListener?.onBoundsChanged(it) }
events.onThemeChanged(theme.copy(isDarkTheme = isDarkTheme))
+ animations.onFontAxesChanged(clockCtx.settings.axes)
animations.doze(dozeFraction)
animations.fold(foldFraction)
events.onTimeTick()
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt
index 171a68f..ec7803d0c 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt
@@ -31,10 +31,12 @@
import com.android.systemui.plugins.clocks.ClockFaceController
import com.android.systemui.plugins.clocks.ClockFaceEvents
import com.android.systemui.plugins.clocks.ClockFaceLayout
+import com.android.systemui.plugins.clocks.ClockFontAxis.Companion.merge
import com.android.systemui.plugins.clocks.DefaultClockFaceLayout
import com.android.systemui.plugins.clocks.ThemeConfig
import com.android.systemui.plugins.clocks.WeatherData
import com.android.systemui.plugins.clocks.ZenData
+import com.android.systemui.shared.clocks.FlexClockController.Companion.getDefaultAxes
import com.android.systemui.shared.clocks.FontUtils.get
import com.android.systemui.shared.clocks.FontUtils.set
import com.android.systemui.shared.clocks.ViewUtils.computeLayoutDiff
@@ -131,15 +133,6 @@
layerController.faceEvents.onThemeChanged(theme)
}
- override fun onFontAxesChanged(settings: ClockAxisStyle) {
- var axes = ClockAxisStyle(settings)
- if (!isLargeClock && axes[GSFAxes.WIDTH] > SMALL_CLOCK_MAX_WDTH) {
- axes[GSFAxes.WIDTH] = SMALL_CLOCK_MAX_WDTH
- }
-
- layerController.events.onFontAxesChanged(axes)
- }
-
/**
* targetRegion passed to all customized clock applies counter translationY of Keyguard and
* keyguard_large_clock_top_margin from default clock
@@ -232,6 +225,15 @@
override fun onFidgetTap(x: Float, y: Float) {
layerController.animations.onFidgetTap(x, y)
}
+
+ override fun onFontAxesChanged(style: ClockAxisStyle) {
+ var axes = ClockAxisStyle(getDefaultAxes(clockCtx.settings).merge(style))
+ if (!isLargeClock && axes[GSFAxes.WIDTH] > SMALL_CLOCK_MAX_WDTH) {
+ axes[GSFAxes.WIDTH] = SMALL_CLOCK_MAX_WDTH
+ }
+
+ layerController.animations.onFontAxesChanged(axes)
+ }
}
companion object {
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
index 7be9a93..eef910c 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
@@ -171,10 +171,6 @@
override fun onAlarmDataChanged(data: AlarmData) {}
override fun onZenDataChanged(data: ZenData) {}
-
- override fun onFontAxesChanged(axes: ClockAxisStyle) {
- view.updateAxes(axes)
- }
}
override val animations =
@@ -195,6 +191,13 @@
view.dozeFraction = fraction
}
+ private var hasFontAxes = false
+
+ override fun onFontAxesChanged(style: ClockAxisStyle) {
+ view.updateAxes(style, isAnimated = hasFontAxes)
+ hasFontAxes = true
+ }
+
override fun fold(fraction: Float) {
applyLayout()
refreshTime()
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
index 4531aed..4a5532b 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
@@ -272,8 +272,8 @@
invalidate()
}
- fun updateAxes(axes: ClockAxisStyle) {
- childViews.forEach { view -> view.updateAxes(axes) }
+ fun updateAxes(axes: ClockAxisStyle, isAnimated: Boolean) {
+ childViews.forEach { view -> view.updateAxes(axes, isAnimated) }
requestLayout()
}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
index 377a24c..05c9818 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
@@ -200,11 +200,11 @@
invalidate()
}
- fun updateAxes(lsAxes: ClockAxisStyle) {
+ fun updateAxes(lsAxes: ClockAxisStyle, isAnimated: Boolean) {
lsFontVariation = lsAxes.toFVar()
aodFontVariation = lsAxes.copyWith(fixedAodAxes).toFVar()
fidgetFontVariation = buildFidgetVariation(lsAxes).toFVar()
- logger.updateAxes(lsFontVariation, aodFontVariation)
+ logger.updateAxes(lsFontVariation, aodFontVariation, isAnimated)
lockScreenPaint.typeface = typefaceCache.getTypefaceForVariant(lsFontVariation)
typeface = lockScreenPaint.typeface
@@ -212,7 +212,15 @@
textBounds = lockScreenPaint.getTextBounds(text)
targetTextBounds = textBounds
- textAnimator.setTextStyle(TextAnimator.Style(fVar = lsFontVariation))
+ textAnimator.setTextStyle(
+ TextAnimator.Style(fVar = lsFontVariation),
+ TextAnimator.Animation(
+ animate = isAnimated && isAnimationEnabled,
+ duration = AXIS_CHANGE_ANIMATION_DURATION,
+ interpolator = aodDozingInterpolator,
+ ),
+ )
+
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
recomputeMaxSingleDigitSizes()
requestLayout()
@@ -651,6 +659,7 @@
.compose()
val CHARGE_ANIMATION_DURATION = 500L
+ val AXIS_CHANGE_ANIMATION_DURATION = 400L
val FIDGET_ANIMATION_DURATION = 250L
val FIDGET_INTERPOLATOR = PathInterpolator(0.26873f, 0f, 0.45042f, 1f)
val FIDGET_DISTS =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/MagnificationSettingsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/MagnificationSettingsControllerTest.java
index 02ec5aa..d0f8e78 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/MagnificationSettingsControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/MagnificationSettingsControllerTest.java
@@ -23,7 +23,6 @@
import android.content.pm.ActivityInfo;
import android.testing.TestableLooper;
-import android.view.WindowManager;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -57,15 +56,13 @@
private SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
@Mock
private SecureSettings mSecureSettings;
- @Mock
- private WindowManager mWindowManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mMagnificationSettingsController = new MagnificationSettingsController(
mContext, mSfVsyncFrameProvider,
- mMagnificationSettingControllerCallback, mSecureSettings, mWindowManager,
+ mMagnificationSettingControllerCallback, mSecureSettings,
mWindowMagnificationSettings);
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 675c9de..56c0182 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.biometrics;
+import static com.android.systemui.SysuiTestCaseExtKt.testKosmos;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -69,7 +71,9 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.keyguard.UserActivityNotifierKosmosKt;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.kosmos.Kosmos;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -115,7 +119,7 @@
@RunWith(AndroidJUnit4.class)
@RunWithLooper(setAsMainLooper = true)
public class UdfpsControllerTest extends SysuiTestCase {
-
+ private final Kosmos mKosmos = testKosmos(this);
private static final long TEST_REQUEST_ID = 70;
@Rule
@@ -325,7 +329,8 @@
mDefaultUdfpsTouchOverlayViewModel,
mUdfpsOverlayInteractor,
mPowerInteractor,
- mock(CoroutineScope.class)
+ mock(CoroutineScope.class),
+ UserActivityNotifierKosmosKt.getUserActivityNotifier(mKosmos)
);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractorTest.kt
index 95334b5..856a62e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractorTest.kt
@@ -25,9 +25,10 @@
import com.android.systemui.communal.data.model.FEATURE_AUTO_OPEN
import com.android.systemui.communal.data.model.FEATURE_MANUAL_OPEN
import com.android.systemui.communal.data.model.SuppressionReason
+import com.android.systemui.communal.posturing.data.model.PositionState
import com.android.systemui.communal.posturing.data.repository.fake
import com.android.systemui.communal.posturing.data.repository.posturingRepository
-import com.android.systemui.communal.posturing.shared.model.PosturedState
+import com.android.systemui.communal.posturing.domain.interactor.advanceTimeBySlidingWindowAndRun
import com.android.systemui.dock.DockManager
import com.android.systemui.dock.fakeDockManager
import com.android.systemui.kosmos.Kosmos
@@ -127,7 +128,12 @@
)
batteryRepository.fake.setDevicePluggedIn(true)
- posturingRepository.fake.setPosturedState(PosturedState.NotPostured)
+ posturingRepository.fake.emitPositionState(
+ PositionState(
+ stationary = PositionState.StationaryState.Stationary(confidence = 1f),
+ orientation = PositionState.OrientationState.NotPostured(confidence = 1f),
+ )
+ )
assertThat(shouldAutoOpen).isFalse()
assertThat(suppressionReason)
@@ -135,7 +141,13 @@
SuppressionReason.ReasonWhenToAutoShow(FEATURE_AUTO_OPEN or FEATURE_MANUAL_OPEN)
)
- posturingRepository.fake.setPosturedState(PosturedState.Postured(1f))
+ posturingRepository.fake.emitPositionState(
+ PositionState(
+ stationary = PositionState.StationaryState.Stationary(confidence = 1f),
+ orientation = PositionState.OrientationState.Postured(confidence = 1f),
+ )
+ )
+ advanceTimeBySlidingWindowAndRun()
assertThat(shouldAutoOpen).isTrue()
assertThat(suppressionReason).isNull()
}
@@ -153,7 +165,7 @@
)
batteryRepository.fake.setDevicePluggedIn(true)
- posturingRepository.fake.setPosturedState(PosturedState.Postured(1f))
+ posturingRepository.fake.emitPositionState(PositionState())
fakeDockManager.setIsDocked(true)
assertThat(shouldAutoOpen).isFalse()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractorTest.kt
index 0df8834..b4708d97 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractorTest.kt
@@ -16,22 +16,39 @@
package com.android.systemui.communal.posturing.domain.interactor
+import android.hardware.Sensor
+import android.hardware.TriggerEventListener
+import android.platform.test.annotations.EnableFlags
+import android.service.dreams.Flags.FLAG_ALLOW_DREAM_WHEN_POSTURED
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.posturing.data.model.PositionState
import com.android.systemui.communal.posturing.data.repository.fake
import com.android.systemui.communal.posturing.data.repository.posturingRepository
import com.android.systemui.communal.posturing.shared.model.PosturedState
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.advanceTimeBy
import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runCurrent
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.testKosmos
+import com.android.systemui.util.sensors.asyncSensorManager
import com.google.common.truth.Truth.assertThat
+import kotlin.time.Duration.Companion.hours
+import kotlin.time.Duration.Companion.milliseconds
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.stub
@SmallTest
@RunWith(AndroidJUnit4::class)
+@EnableFlags(FLAG_ALLOW_DREAM_WHEN_POSTURED)
class PosturingInteractorTest : SysuiTestCase() {
private val kosmos = testKosmos().useUnconfinedTestDispatcher()
@@ -44,23 +61,220 @@
val postured by collectLastValue(underTest.postured)
assertThat(postured).isFalse()
- posturingRepository.fake.setPosturedState(PosturedState.Postured(1f))
+ posturingRepository.fake.emitPositionState(
+ PositionState(
+ stationary = PositionState.StationaryState.Stationary(confidence = 1f),
+ orientation = PositionState.OrientationState.Postured(confidence = 1f),
+ )
+ )
+
+ advanceTimeBySlidingWindowAndRun()
assertThat(postured).isTrue()
}
@Test
+ fun testLowConfidenceOrientation() =
+ kosmos.runTest {
+ val postured by collectLastValue(underTest.postured)
+ assertThat(postured).isFalse()
+
+ posturingRepository.fake.emitPositionState(
+ PositionState(
+ stationary = PositionState.StationaryState.Stationary(confidence = 1f),
+ orientation = PositionState.OrientationState.Postured(confidence = 0.2f),
+ )
+ )
+
+ advanceTimeBySlidingWindowAndRun()
+ assertThat(postured).isFalse()
+ }
+
+ @Test
+ fun testLowConfidenceStationary() =
+ kosmos.runTest {
+ val postured by collectLastValue(underTest.postured)
+ assertThat(postured).isFalse()
+
+ posturingRepository.fake.emitPositionState(
+ PositionState(
+ stationary = PositionState.StationaryState.Stationary(confidence = 1f),
+ orientation = PositionState.OrientationState.Postured(confidence = 0.2f),
+ )
+ )
+
+ advanceTimeBySlidingWindowAndRun()
+ assertThat(postured).isFalse()
+ }
+
+ @Test
+ fun testSlidingWindow() =
+ kosmos.runTest {
+ val postured by collectLastValue(underTest.postured)
+ assertThat(postured).isFalse()
+
+ posturingRepository.fake.emitPositionState(
+ PositionState(
+ stationary = PositionState.StationaryState.Stationary(confidence = 1f),
+ orientation = PositionState.OrientationState.Postured(confidence = 0.2f),
+ )
+ )
+
+ advanceTimeBy(PosturingInteractor.SLIDING_WINDOW_DURATION / 2)
+ runCurrent()
+ assertThat(postured).isFalse()
+
+ posturingRepository.fake.emitPositionState(
+ PositionState(
+ stationary = PositionState.StationaryState.Stationary(confidence = 1f),
+ orientation = PositionState.OrientationState.Postured(confidence = 1f),
+ )
+ )
+ assertThat(postured).isFalse()
+ advanceTimeBy(PosturingInteractor.SLIDING_WINDOW_DURATION / 2)
+ runCurrent()
+
+ // The 0.2 confidence will have fallen out of the sliding window, and we should now flip
+ // to true.
+ assertThat(postured).isTrue()
+
+ advanceTimeBy(9999.hours)
+ // We should remain postured if no other updates are received.
+ assertThat(postured).isTrue()
+ }
+
+ @Test
+ fun testLiftGesture_afterSlidingWindow() =
+ kosmos.runTest {
+ val triggerSensor = stubSensorManager()
+ val sensor = asyncSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE)!!
+
+ val postured by collectLastValue(underTest.postured)
+ assertThat(postured).isFalse()
+
+ posturingRepository.fake.emitPositionState(
+ PositionState(
+ stationary = PositionState.StationaryState.Stationary(confidence = 1f),
+ orientation = PositionState.OrientationState.Postured(confidence = 1f),
+ )
+ )
+
+ advanceTimeBySlidingWindowAndRun()
+ assertThat(postured).isTrue()
+
+ // If we detect a lift gesture, we should transition back to not postured.
+ triggerSensor(sensor)
+ assertThat(postured).isFalse()
+
+ advanceTimeBy(9999.hours)
+ assertThat(postured).isFalse()
+ }
+
+ @Test
+ fun testLiftGesture_overridesSlidingWindow() =
+ kosmos.runTest {
+ val triggerSensor = stubSensorManager()
+ val sensor = asyncSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE)!!
+
+ val postured by collectLastValue(underTest.postured)
+ assertThat(postured).isFalse()
+
+ // Add multiple stationary + postured events to the sliding window.
+ repeat(100) {
+ advanceTimeBy(1.milliseconds)
+ posturingRepository.fake.emitPositionState(
+ PositionState(
+ stationary = PositionState.StationaryState.Stationary(confidence = 1f),
+ orientation = PositionState.OrientationState.Postured(confidence = 1f),
+ )
+ )
+ }
+
+ assertThat(postured).isTrue()
+
+ // If we detect a lift gesture, we should transition back to not postured immediately.
+ triggerSensor(sensor)
+ assertThat(postured).isFalse()
+ }
+
+ @Test
+ fun testSignificantMotion_afterSlidingWindow() =
+ kosmos.runTest {
+ val triggerSensor = stubSensorManager()
+ val sensor = asyncSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION)!!
+
+ val postured by collectLastValue(underTest.postured)
+ assertThat(postured).isFalse()
+
+ posturingRepository.fake.emitPositionState(
+ PositionState(
+ stationary = PositionState.StationaryState.Stationary(confidence = 1f),
+ orientation = PositionState.OrientationState.Postured(confidence = 1f),
+ )
+ )
+
+ advanceTimeBySlidingWindowAndRun()
+ assertThat(postured).isTrue()
+
+ // If we detect motion, we should transition back to not postured.
+ triggerSensor(sensor)
+ assertThat(postured).isFalse()
+
+ advanceTimeBy(9999.hours)
+ assertThat(postured).isFalse()
+ }
+
+ @Test
fun testOverriddenByDebugValue() =
kosmos.runTest {
val postured by collectLastValue(underTest.postured)
assertThat(postured).isFalse()
underTest.setValueForDebug(PosturedState.NotPostured)
- posturingRepository.fake.setPosturedState(PosturedState.Postured(1f))
+ posturingRepository.fake.emitPositionState(
+ PositionState(
+ stationary = PositionState.StationaryState.Stationary(confidence = 1f),
+ orientation = PositionState.OrientationState.Postured(confidence = 1f),
+ )
+ )
// Repository value is overridden by debug value
assertThat(postured).isFalse()
underTest.setValueForDebug(PosturedState.Unknown)
+
+ advanceTimeBySlidingWindowAndRun()
assertThat(postured).isTrue()
}
+
+ private fun Kosmos.stubSensorManager(): (sensor: Sensor) -> Unit {
+ val callbacks = mutableMapOf<Sensor, List<TriggerEventListener>>()
+ val pickupSensor = mock<Sensor>()
+ val motionSensor = mock<Sensor>()
+
+ asyncSensorManager.stub {
+ on { getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE) } doReturn pickupSensor
+ on { getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION) } doReturn motionSensor
+ on { requestTriggerSensor(any(), any()) } doAnswer
+ {
+ val callback = it.arguments[0] as TriggerEventListener
+ val sensor = it.arguments[1] as Sensor
+ callbacks[sensor] = callbacks.getOrElse(sensor) { emptyList() } + callback
+ true
+ }
+ on { cancelTriggerSensor(any(), any()) } doAnswer
+ {
+ val callback = it.arguments[0] as TriggerEventListener
+ val sensor = it.arguments[1] as Sensor
+ callbacks[sensor] = callbacks.getOrElse(sensor) { emptyList() } - callback
+ true
+ }
+ }
+
+ return { sensor: Sensor ->
+ val list = callbacks.getOrElse(sensor) { emptyList() }
+ // Simulate a trigger sensor which unregisters callbacks after triggering.
+ callbacks[sensor] = emptyList()
+ list.forEach { it.onTrigger(mock()) }
+ }
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/cursorposition/data/repository/MultiDisplayCursorPositionRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/cursorposition/data/repository/MultiDisplayCursorPositionRepositoryTest.kt
new file mode 100644
index 0000000..5609e8b
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/cursorposition/data/repository/MultiDisplayCursorPositionRepositoryTest.kt
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.cursorposition.data.repository
+
+import android.os.Handler
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import android.view.Display.DEFAULT_DISPLAY
+import android.view.Display.TYPE_EXTERNAL
+import android.view.Display.TYPE_INTERNAL
+import android.view.InputDevice.SOURCE_MOUSE
+import android.view.InputDevice.SOURCE_TOUCHPAD
+import android.view.MotionEvent
+import androidx.test.filters.SmallTest
+import com.android.app.displaylib.PerDisplayInstanceRepositoryImpl
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.cursorposition.data.model.CursorPosition
+import com.android.systemui.cursorposition.data.repository.SingleDisplayCursorPositionRepositoryImpl.Companion.defaultInputEventListenerBuilder
+import com.android.systemui.cursorposition.domain.data.repository.TestCursorPositionRepositoryInstanceProvider
+import com.android.systemui.display.data.repository.display
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.display.data.repository.fakeDisplayInstanceLifecycleManager
+import com.android.systemui.display.data.repository.perDisplayDumpHelper
+import com.android.systemui.kosmos.backgroundScope
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.shared.system.InputChannelCompat
+import com.android.systemui.shared.system.InputMonitorCompat
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.launch
+import org.junit.Before
+import org.junit.Rule
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.any
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+
+@SmallTest
+@RunWith(ParameterizedAndroidJunit4::class)
+@RunWithLooper
+@kotlinx.coroutines.ExperimentalCoroutinesApi
+class MultiDisplayCursorPositionRepositoryTest(private val cursorEventSource: Int) :
+ SysuiTestCase() {
+
+ @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
+ private lateinit var underTest: MultiDisplayCursorPositionRepository
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+ private val displayRepository = kosmos.displayRepository
+ private val displayLifecycleManager = kosmos.fakeDisplayInstanceLifecycleManager
+
+ private lateinit var listener: InputChannelCompat.InputEventListener
+ private var emittedCursorPosition: CursorPosition? = null
+
+ @Mock private lateinit var inputMonitor: InputMonitorCompat
+ @Mock private lateinit var inputReceiver: InputChannelCompat.InputEventReceiver
+
+ private val x = 100f
+ private val y = 200f
+
+ private lateinit var testableLooper: TestableLooper
+
+ @Before
+ fun setup() {
+ testableLooper = TestableLooper.get(this)
+ val testHandler = Handler(testableLooper.looper)
+ whenever(inputMonitor.getInputReceiver(any(), any(), any())).thenReturn(inputReceiver)
+ displayLifecycleManager.displayIds.value = setOf(DEFAULT_DISPLAY, DISPLAY_2)
+
+ val cursorPerDisplayRepository =
+ PerDisplayInstanceRepositoryImpl(
+ debugName = "testCursorPositionPerDisplayInstanceRepository",
+ instanceProvider =
+ TestCursorPositionRepositoryInstanceProvider(
+ testHandler,
+ { channel ->
+ listener = defaultInputEventListenerBuilder.build(channel)
+ listener
+ },
+ ) { _: String, _: Int ->
+ inputMonitor
+ },
+ displayLifecycleManager,
+ kosmos.backgroundScope,
+ displayRepository,
+ kosmos.perDisplayDumpHelper,
+ )
+
+ underTest =
+ MultiDisplayCursorPositionRepositoryImpl(
+ displayRepository,
+ backgroundScope = kosmos.backgroundScope,
+ cursorPerDisplayRepository,
+ )
+ }
+
+ @Test
+ fun getCursorPositionFromDefaultDisplay() = setUpAndRunTest {
+ val event = getMotionEvent(x, y, 0)
+ listener.onInputEvent(event)
+
+ assertThat(emittedCursorPosition).isEqualTo(CursorPosition(x, y, 0))
+ }
+
+ @Test
+ fun getCursorPositionFromAdditionDisplay() = setUpAndRunTest {
+ addDisplay(id = DISPLAY_2, type = TYPE_EXTERNAL)
+
+ val event = getMotionEvent(x, y, DISPLAY_2)
+ listener.onInputEvent(event)
+
+ assertThat(emittedCursorPosition).isEqualTo(CursorPosition(x, y, DISPLAY_2))
+ }
+
+ @Test
+ fun noCursorPositionFromRemovedDisplay() = setUpAndRunTest {
+ addDisplay(id = DISPLAY_2, type = TYPE_EXTERNAL)
+ removeDisplay(DISPLAY_2)
+
+ val event = getMotionEvent(x, y, DISPLAY_2)
+ listener.onInputEvent(event)
+
+ assertThat(emittedCursorPosition).isEqualTo(null)
+ }
+
+ @Test
+ fun disposeInputMonitorAndInputReceiver() = setUpAndRunTest {
+ addDisplay(DISPLAY_2, TYPE_EXTERNAL)
+ removeDisplay(DISPLAY_2)
+
+ verify(inputMonitor).dispose()
+ verify(inputReceiver).dispose()
+ }
+
+ private fun setUpAndRunTest(block: suspend () -> Unit) =
+ kosmos.runTest {
+ // Add default display before creating cursor repository
+ displayRepository.addDisplays(display(id = DEFAULT_DISPLAY, type = TYPE_INTERNAL))
+
+ backgroundScope.launch {
+ underTest.cursorPositions.collect { emittedCursorPosition = it }
+ }
+ // Run all tasks received by TestHandler to create input monitors
+ testableLooper.processAllMessages()
+
+ block()
+ }
+
+ private suspend fun addDisplay(id: Int, type: Int) {
+ displayRepository.addDisplays(display(id = id, type = type))
+ testableLooper.processAllMessages()
+ }
+
+ private suspend fun removeDisplay(id: Int) {
+ displayRepository.removeDisplay(id)
+ testableLooper.processAllMessages()
+ }
+
+ private fun getMotionEvent(x: Float, y: Float, displayId: Int): MotionEvent {
+ val event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, x, y, 0)
+ event.source = cursorEventSource
+ event.displayId = displayId
+ return event
+ }
+
+ private companion object {
+ const val DISPLAY_2 = DEFAULT_DISPLAY + 1
+
+ @JvmStatic
+ @Parameters(name = "source = {0}")
+ fun data(): List<Int> {
+ return listOf(SOURCE_MOUSE, SOURCE_TOUCHPAD)
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
index 454c156..89d3060 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
@@ -311,6 +311,20 @@
assertThat(playSuccessHaptic).isNull()
}
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun playSuccessHaptic_onDeviceEntry_fromDeviceEntryIcon() =
+ testScope.runTest {
+ underTest = kosmos.deviceEntryHapticsInteractor
+ val playSuccessHaptic by collectLastValue(underTest.playSuccessHapticOnDeviceEntry)
+
+ kosmos.fakeKeyguardRepository.setKeyguardDismissible(true)
+ runCurrent()
+ kosmos.deviceEntrySourceInteractor.attemptEnterDeviceFromDeviceEntryIcon()
+
+ assertThat(playSuccessHaptic).isNotNull()
+ }
+
// Mock dependencies for DeviceEntrySourceInteractor#deviceEntryFromBiometricSource
private fun configureDeviceEntryFromBiometricSource(
isFpUnlock: Boolean = false,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutCustomizationModeRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutCustomizationModeRepositoryTest.kt
new file mode 100644
index 0000000..e955ca8
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutCustomizationModeRepositoryTest.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.keyboard.shortcut.data.repository
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyboard.shortcut.shortcutHelperCustomizationModeRepository
+import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ShortcutCustomizationModeRepositoryTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+ private val repo = kosmos.shortcutHelperCustomizationModeRepository
+ private val testScope = kosmos.testScope
+ private val helper = kosmos.shortcutHelperTestHelper
+
+ @Test
+ fun customizationMode_disabledByDefault() {
+ testScope.runTest {
+ val customizationMode by collectLastValue(repo.isCustomizationModeEnabled)
+
+ assertThat(customizationMode).isFalse()
+ }
+ }
+
+ @Test
+ fun customizationMode_enabledOnRequest_whenShortcutHelperIsOpen() {
+ testScope.runTest {
+ val customizationMode by collectLastValue(repo.isCustomizationModeEnabled)
+ helper.showFromActivity()
+ repo.toggleCustomizationMode(isCustomizing = true)
+ assertThat(customizationMode).isTrue()
+ }
+ }
+
+ @Test
+ fun customizationMode_disabledOnRequest_whenShortcutHelperIsOpen() {
+ testScope.runTest {
+ val customizationMode by collectLastValue(repo.isCustomizationModeEnabled)
+ helper.showFromActivity()
+ repo.toggleCustomizationMode(isCustomizing = true)
+ repo.toggleCustomizationMode(isCustomizing = false)
+ assertThat(customizationMode).isFalse()
+ }
+ }
+
+ @Test
+ fun customizationMode_disabledWhenShortcutHelperIsDismissed() {
+ testScope.runTest {
+ val customizationMode by collectLastValue(repo.isCustomizationModeEnabled)
+ helper.showFromActivity()
+ repo.toggleCustomizationMode(isCustomizing = true)
+ helper.hideFromActivity()
+ assertThat(customizationMode).isFalse()
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/UserVisibleAppsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/UserVisibleAppsRepositoryTest.kt
new file mode 100644
index 0000000..a2e4297
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/UserVisibleAppsRepositoryTest.kt
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.keyboard.shortcut.data.repository
+
+import android.content.pm.UserInfo
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyboard.shortcut.fakeLauncherApps
+import com.android.systemui.keyboard.shortcut.userVisibleAppsRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.settings.fakeUserTracker
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class UserVisibleAppsRepositoryTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+ private val fakeLauncherApps = kosmos.fakeLauncherApps
+ private val repo = kosmos.userVisibleAppsRepository
+ private val userTracker = kosmos.fakeUserTracker
+ private val testScope = kosmos.testScope
+ private val userVisibleAppsContainsApplication:
+ (pkgName: String, clsName: String) -> Flow<Boolean> =
+ { pkgName, clsName ->
+ repo.userVisibleApps.map { userVisibleApps ->
+ userVisibleApps.any {
+ it.componentName.packageName == pkgName && it.componentName.className == clsName
+ }
+ }
+ }
+
+ @Before
+ fun setup() {
+ switchUser(index = PRIMARY_USER_INDEX)
+ }
+
+ @Test
+ fun userVisibleApps_emitsUpdatedAppsList_onNewAppInstalled() {
+ testScope.runTest {
+ val containsPackageOne by
+ collectLastValue(userVisibleAppsContainsApplication(TEST_PACKAGE_1, TEST_CLASS_1))
+
+ installPackageOneForUserOne()
+
+ assertThat(containsPackageOne).isTrue()
+ }
+ }
+
+ @Test
+ fun userVisibleApps_emitsUpdatedAppsList_onAppUserChanged() {
+ testScope.runTest {
+ val containsPackageOne by
+ collectLastValue(userVisibleAppsContainsApplication(TEST_PACKAGE_1, TEST_CLASS_1))
+ val containsPackageTwo by
+ collectLastValue(userVisibleAppsContainsApplication(TEST_PACKAGE_2, TEST_CLASS_2))
+
+ installPackageOneForUserOne()
+ installPackageTwoForUserTwo()
+
+ assertThat(containsPackageOne).isTrue()
+ assertThat(containsPackageTwo).isFalse()
+
+ switchUser(index = SECONDARY_USER_INDEX)
+
+ assertThat(containsPackageOne).isFalse()
+ assertThat(containsPackageTwo).isTrue()
+ }
+ }
+
+ @Test
+ fun userVisibleApps_emitsUpdatedAppsList_onAppUninstalled() {
+ testScope.runTest {
+ val containsPackageOne by
+ collectLastValue(userVisibleAppsContainsApplication(TEST_PACKAGE_1, TEST_CLASS_1))
+
+ installPackageOneForUserOne()
+ uninstallPackageOneForUserOne()
+
+ assertThat(containsPackageOne).isFalse()
+ }
+ }
+
+ private fun switchUser(index: Int) {
+ userTracker.set(
+ userInfos =
+ listOf(
+ UserInfo(/* id= */ PRIMARY_USER_ID, /* name= */ "Primary User", /* flags= */ 0),
+ UserInfo(
+ /* id= */ SECONDARY_USER_ID,
+ /* name= */ "Secondary User",
+ /* flags= */ 0,
+ ),
+ ),
+ selectedUserIndex = index,
+ )
+ }
+
+ private fun installPackageOneForUserOne() {
+ fakeLauncherApps.installPackageForUser(
+ TEST_PACKAGE_1,
+ TEST_CLASS_1,
+ UserHandle(/* userId= */ PRIMARY_USER_ID),
+ )
+ }
+
+ private fun uninstallPackageOneForUserOne() {
+ fakeLauncherApps.uninstallPackageForUser(
+ TEST_PACKAGE_1,
+ TEST_CLASS_1,
+ UserHandle(/* userId= */ PRIMARY_USER_ID),
+ )
+ }
+
+ private fun installPackageTwoForUserTwo() {
+ fakeLauncherApps.installPackageForUser(
+ TEST_PACKAGE_2,
+ TEST_CLASS_2,
+ UserHandle(/* userId= */ SECONDARY_USER_ID),
+ )
+ }
+
+ companion object {
+ const val TEST_PACKAGE_1 = "test.package.one"
+ const val TEST_PACKAGE_2 = "test.package.two"
+ const val TEST_CLASS_1 = "TestClassOne"
+ const val TEST_CLASS_2 = "TestClassTwo"
+ const val PRIMARY_USER_ID = 10
+ const val PRIMARY_USER_INDEX = 0
+ const val SECONDARY_USER_ID = 11
+ const val SECONDARY_USER_INDEX = 1
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
index 7667448..d4292bf5b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
@@ -56,7 +56,6 @@
import com.android.systemui.keyboard.shortcut.ui.model.IconSource
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCategoryUi
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutsUiState
-import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.model.sysUiState
@@ -66,7 +65,8 @@
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SHORTCUT_HELPER_SHOWING
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -89,7 +89,6 @@
private val kosmos =
testKosmos().useUnconfinedTestDispatcher().also {
- it.testDispatcher = UnconfinedTestDispatcher()
it.shortcutHelperSystemShortcutsSource = fakeSystemSource
it.shortcutHelperMultiTaskingShortcutsSource = fakeMultiTaskingSource
it.shortcutHelperAppCategoriesShortcutsSource = FakeKeyboardShortcutGroupsSource()
@@ -445,6 +444,51 @@
assertThat((uiState as? ShortcutsUiState.Active)?.searchQuery).isEqualTo("")
}
+ @Test
+ fun shortcutsUiState_customizationModeDisabledByDefault() {
+ testScope.runTest {
+ testHelper.showFromActivity()
+ val uiState by collectLastValue(viewModel.shortcutsUiState)
+
+ assertFalse((uiState as ShortcutsUiState.Active).isCustomizationModeEnabled)
+ }
+ }
+
+ @Test
+ fun shortcutsUiState_customizationModeEnabledOnRequest() {
+ testScope.runTest {
+ testHelper.showFromActivity()
+ val uiState by collectLastValue(viewModel.shortcutsUiState)
+ viewModel.toggleCustomizationMode(true)
+
+ assertTrue((uiState as ShortcutsUiState.Active).isCustomizationModeEnabled)
+ }
+ }
+
+ @Test
+ fun shortcutsUiState_customizationModeDisabledOnRequest() {
+ testScope.runTest {
+ testHelper.showFromActivity()
+ val uiState by collectLastValue(viewModel.shortcutsUiState)
+ viewModel.toggleCustomizationMode(true)
+ viewModel.toggleCustomizationMode(false)
+
+ assertFalse((uiState as ShortcutsUiState.Active).isCustomizationModeEnabled)
+ }
+ }
+
+ @Test
+ fun shortcutsUiState_customizationModeDisabledWhenShortcutHelperIsReopened() {
+ testScope.runTest {
+ testHelper.showFromActivity()
+ val uiState by collectLastValue(viewModel.shortcutsUiState)
+ viewModel.toggleCustomizationMode(true)
+ closeAndReopenShortcutHelper()
+
+ assertFalse((uiState as ShortcutsUiState.Active).isCustomizationModeEnabled)
+ }
+ }
+
private fun openHelperAndSearchForFooString() {
testHelper.showFromActivity()
viewModel.onSearchQueryChanged("foo")
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 8a11be0..b1427f2 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
@@ -219,17 +219,13 @@
underTest.addSelectedUserMediaEntry(playingData1)
underTest.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(playingInstanceId1))
underTest.addSelectedUserMediaEntry(playingData2)
- underTest.addMediaDataLoadingState(
- MediaDataLoadingModel.Loaded(playingInstanceId2, false)
- )
+ underTest.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(playingInstanceId2))
assertThat(currentMedia?.size).isEqualTo(2)
assertThat(currentMedia)
.containsExactly(
MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(playingInstanceId1)),
- MediaCommonModel.MediaControl(
- MediaDataLoadingModel.Loaded(playingInstanceId2, false)
- ),
+ MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(playingInstanceId2)),
)
.inOrder()
@@ -238,9 +234,7 @@
assertThat(currentMedia?.size).isEqualTo(2)
assertThat(currentMedia)
.containsExactly(
- MediaCommonModel.MediaControl(
- MediaDataLoadingModel.Loaded(playingInstanceId2, false)
- ),
+ MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(playingInstanceId2)),
MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(playingInstanceId1)),
)
.inOrder()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/util/MediaDiffUtilTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/util/MediaDiffUtilTest.kt
index faa62c2..45128e2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/util/MediaDiffUtilTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/util/MediaDiffUtilTest.kt
@@ -21,7 +21,7 @@
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.systemui.SysuiTestCase
-import com.android.systemui.media.controls.ui.viewmodel.MediaCommonViewModel
+import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel
import com.android.systemui.media.controls.ui.viewmodel.mediaControlViewModel
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -37,8 +37,8 @@
@Test
fun newMediaControlAdded() {
- val mediaControl = createMediaControl(InstanceId.fakeInstanceId(123), true)
- val oldList = listOf<MediaCommonViewModel>()
+ val mediaControl = createMediaControl(InstanceId.fakeInstanceId(123))
+ val oldList = listOf<MediaControlViewModel>()
val newList = listOf(mediaControl)
val mediaLoadedCallback = MediaViewModelCallback(oldList, newList)
val mediaLoadedListUpdateCallback =
@@ -56,18 +56,18 @@
@Test
fun updateMediaControl_contentChanged() {
- val mediaControl = createMediaControl(InstanceId.fakeInstanceId(123), true)
+ val mediaControl = createMediaControl(InstanceId.fakeInstanceId(123))
val oldList = listOf(mediaControl)
- val newList = listOf(mediaControl.copy(immediatelyUpdateUi = false))
+ val newList = listOf(mediaControl.copy())
val mediaLoadedCallback = MediaViewModelCallback(oldList, newList)
val mediaLoadedListUpdateCallback =
MediaViewModelListUpdateCallback(
oldList,
newList,
- { commonViewModel, _ -> fail("Unexpected to add $commonViewModel") },
- { commonViewModel, _ -> assertThat(commonViewModel).isNotEqualTo(mediaControl) },
+ { controlViewModel, _ -> fail("Unexpected to add $controlViewModel") },
+ { controlViewModel, _ -> assertThat(controlViewModel).isNotEqualTo(mediaControl) },
{ fail("Unexpected to remove $it") },
- { commonViewModel, _, _ -> fail("Unexpected to move $commonViewModel ") },
+ { controlViewModel, _, _ -> fail("Unexpected to move $controlViewModel ") },
)
DiffUtil.calculateDiff(mediaLoadedCallback).dispatchUpdatesTo(mediaLoadedListUpdateCallback)
@@ -75,8 +75,8 @@
@Test
fun mediaControlMoved() {
- val mediaControl1 = createMediaControl(InstanceId.fakeInstanceId(123), true)
- val mediaControl2 = createMediaControl(InstanceId.fakeInstanceId(456), false)
+ val mediaControl1 = createMediaControl(InstanceId.fakeInstanceId(123))
+ val mediaControl2 = createMediaControl(InstanceId.fakeInstanceId(456))
val oldList = listOf(mediaControl1, mediaControl2)
val newList = listOf(mediaControl2, mediaControl1)
val mediaLoadedCallback = MediaViewModelCallback(oldList, newList)
@@ -84,10 +84,10 @@
MediaViewModelListUpdateCallback(
oldList,
newList,
- { commonViewModel, _ -> fail("Unexpected to add $commonViewModel") },
- { commonViewModel, _ -> fail("Unexpected to update $commonViewModel") },
+ { controlViewModel, _ -> fail("Unexpected to add $controlViewModel") },
+ { controlViewModel, _ -> fail("Unexpected to update $controlViewModel") },
{ fail("Unexpected to remove $it") },
- { commonViewModel, _, _ -> assertThat(commonViewModel).isEqualTo(mediaControl1) },
+ { controlViewModel, _, _ -> assertThat(controlViewModel).isEqualTo(mediaControl1) },
)
DiffUtil.calculateDiff(mediaLoadedCallback).dispatchUpdatesTo(mediaLoadedListUpdateCallback)
@@ -95,34 +95,24 @@
@Test
fun mediaControlRemoved() {
- val mediaControl = createMediaControl(InstanceId.fakeInstanceId(123), true)
+ val mediaControl = createMediaControl(InstanceId.fakeInstanceId(123))
val oldList = listOf(mediaControl)
- val newList = listOf<MediaCommonViewModel>()
+ val newList = listOf<MediaControlViewModel>()
val mediaLoadedCallback = MediaViewModelCallback(oldList, newList)
val mediaLoadedListUpdateCallback =
MediaViewModelListUpdateCallback(
oldList,
newList,
- { commonViewModel, _ -> fail("Unexpected to add $commonViewModel") },
- { commonViewModel, _ -> fail("Unexpected to update $commonViewModel") },
- { commonViewModel -> assertThat(commonViewModel).isEqualTo(mediaControl) },
- { commonViewModel, _, _ -> fail("Unexpected to move $commonViewModel ") },
+ { controlViewModel, _ -> fail("Unexpected to add $controlViewModel") },
+ { controlViewModel, _ -> fail("Unexpected to update $controlViewModel") },
+ { controlViewModel -> assertThat(controlViewModel).isEqualTo(mediaControl) },
+ { controlViewModel, _, _ -> fail("Unexpected to move $controlViewModel ") },
)
DiffUtil.calculateDiff(mediaLoadedCallback).dispatchUpdatesTo(mediaLoadedListUpdateCallback)
}
- private fun createMediaControl(
- instanceId: InstanceId,
- immediatelyUpdateUi: Boolean,
- ): MediaCommonViewModel.MediaControl {
- return MediaCommonViewModel.MediaControl(
- instanceId = instanceId,
- immediatelyUpdateUi = immediatelyUpdateUi,
- controlViewModel = kosmos.mediaControlViewModel,
- onAdded = {},
- onRemoved = {},
- onUpdated = {},
- )
+ private fun createMediaControl(instanceId: InstanceId): MediaControlViewModel {
+ return kosmos.mediaControlViewModel.copy(instanceId = instanceId)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt
index e56b114..fab5a3c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt
@@ -86,23 +86,23 @@
loadMediaControl(KEY_2, instanceId2, isPlaying = true)
loadMediaControl(KEY, instanceId1, isPlaying = false)
- var mediaControl2 = sortedMedia?.get(0) as MediaCommonViewModel.MediaControl
- var mediaControl1 = sortedMedia?.get(1) as MediaCommonViewModel.MediaControl
+ var mediaControl2 = sortedMedia?.get(0) as MediaControlViewModel
+ var mediaControl1 = sortedMedia?.get(1) as MediaControlViewModel
assertThat(mediaControl2.instanceId).isEqualTo(instanceId2)
assertThat(mediaControl1.instanceId).isEqualTo(instanceId1)
loadMediaControl(KEY, instanceId1, isPlaying = true)
loadMediaControl(KEY_2, instanceId2, isPlaying = false)
- mediaControl2 = sortedMedia?.get(0) as MediaCommonViewModel.MediaControl
- mediaControl1 = sortedMedia?.get(1) as MediaCommonViewModel.MediaControl
+ mediaControl2 = sortedMedia?.get(0) as MediaControlViewModel
+ mediaControl1 = sortedMedia?.get(1) as MediaControlViewModel
assertThat(mediaControl2.instanceId).isEqualTo(instanceId2)
assertThat(mediaControl1.instanceId).isEqualTo(instanceId1)
underTest.onReorderingAllowed()
- mediaControl1 = sortedMedia?.get(0) as MediaCommonViewModel.MediaControl
- mediaControl2 = sortedMedia?.get(1) as MediaCommonViewModel.MediaControl
+ mediaControl1 = sortedMedia?.get(0) as MediaControlViewModel
+ mediaControl2 = sortedMedia?.get(1) as MediaControlViewModel
assertThat(mediaControl1.instanceId).isEqualTo(instanceId1)
assertThat(mediaControl2.instanceId).isEqualTo(instanceId2)
}
@@ -115,7 +115,7 @@
loadMediaControl(KEY, instanceId)
- val mediaControl = sortedMedia?.get(0) as MediaCommonViewModel.MediaControl
+ val mediaControl = sortedMedia?.get(0) as MediaControlViewModel
assertThat(mediaControl.instanceId).isEqualTo(instanceId)
// when media control is added to carousel
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModelTest.kt
index 7490674..7fb66ce 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModelTest.kt
@@ -76,7 +76,7 @@
underTest.activateIn(this)
val action =
- (actions?.get(Swipe.Down(fromSource = SceneContainerArea.EndHalf))
+ (actions?.get(Swipe.Down(fromSource = SceneContainerArea.TopEdgeEndHalf))
as? ReplaceByOverlay)
assertThat(action?.overlay).isEqualTo(Overlays.QuickSettingsShade)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt
index 80ce43d..ffcd95b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt
@@ -157,7 +157,7 @@
}
@Test
- fun showMedia_noActiveMedia_false() =
+ fun showMedia_InactiveMedia_false() =
testScope.runTest {
kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = false))
runCurrent()
@@ -166,6 +166,16 @@
}
@Test
+ fun showMedia_noMedia_false() =
+ testScope.runTest {
+ kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = true))
+ kosmos.mediaFilterRepository.clearSelectedUserMedia()
+ runCurrent()
+
+ assertThat(underTest.showMedia).isFalse()
+ }
+
+ @Test
fun showMedia_qsDisabled_false() =
testScope.runTest {
kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = true))
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelTest.kt
index 701e55d..d117015 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelTest.kt
@@ -95,11 +95,21 @@
}
@Test
- fun showMedia_noActiveMedia_false() =
+ fun showMedia_InactiveMedia_true() =
testScope.runTest {
kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = false))
runCurrent()
+ assertThat(underTest.showMedia).isTrue()
+ }
+
+ @Test
+ fun showMedia_noMedia_false() =
+ testScope.runTest {
+ kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = true))
+ kosmos.mediaFilterRepository.clearSelectedUserMedia()
+ runCurrent()
+
assertThat(underTest.showMedia).isFalse()
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelTest.kt
index 0207a30..882d296 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelTest.kt
@@ -89,7 +89,7 @@
underTest.activateIn(this)
val action =
- (actions?.get(Swipe.Down(fromSource = SceneContainerArea.StartHalf))
+ (actions?.get(Swipe.Down(fromSource = SceneContainerArea.TopEdgeStartHalf))
as? ReplaceByOverlay)
assertThat(action?.overlay).isEqualTo(Overlays.NotificationsShade)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerSwipeDetectorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerSwipeDetectorTest.kt
index a09e5cd..7536bb3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerSwipeDetectorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerSwipeDetectorTest.kt
@@ -32,6 +32,8 @@
import com.android.systemui.scene.ui.viewmodel.SceneContainerArea.Resolved.LeftHalf
import com.android.systemui.scene.ui.viewmodel.SceneContainerArea.Resolved.RightEdge
import com.android.systemui.scene.ui.viewmodel.SceneContainerArea.Resolved.RightHalf
+import com.android.systemui.scene.ui.viewmodel.SceneContainerArea.Resolved.TopEdgeLeftHalf
+import com.android.systemui.scene.ui.viewmodel.SceneContainerArea.Resolved.TopEdgeRightHalf
import com.android.systemui.scene.ui.viewmodel.SceneContainerArea.StartEdge
import com.android.systemui.scene.ui.viewmodel.SceneContainerArea.StartHalf
import com.google.common.truth.Truth.assertThat
@@ -55,9 +57,9 @@
}
@Test
- fun source_swipeVerticallyOnTopLeft_detectsLeftHalf() {
+ fun source_swipeVerticallyOnTopLeft_detectsTopEdgeLeftHalf() {
val detectedEdge = swipeVerticallyFrom(x = 1, y = edgeSize - 1)
- assertThat(detectedEdge).isEqualTo(LeftHalf)
+ assertThat(detectedEdge).isEqualTo(TopEdgeLeftHalf)
}
@Test
@@ -69,7 +71,7 @@
@Test
fun source_swipeVerticallyOnTopRight_detectsRightHalf() {
val detectedEdge = swipeVerticallyFrom(x = screenWidth - 1, y = edgeSize - 1)
- assertThat(detectedEdge).isEqualTo(RightHalf)
+ assertThat(detectedEdge).isEqualTo(TopEdgeRightHalf)
}
@Test
@@ -79,14 +81,26 @@
}
@Test
- fun source_swipeVerticallyToLeftOfSplit_detectsLeftHalf() {
+ fun source_swipeVerticallyOnTopEdge_ToLeftOfSplit_detectsTopEdgeLeftHalf() {
val detectedEdge = swipeVerticallyFrom(x = (screenWidth / 2) - 1, y = edgeSize - 1)
+ assertThat(detectedEdge).isEqualTo(TopEdgeLeftHalf)
+ }
+
+ @Test
+ fun source_swipeVerticallyBelowTopEdge_ToLeftOfSplit_detectsLeftHalf() {
+ val detectedEdge = swipeVerticallyFrom(x = (screenWidth / 2) - 1, y = edgeSize + 1)
assertThat(detectedEdge).isEqualTo(LeftHalf)
}
@Test
- fun source_swipeVerticallyToRightOfSplit_detectsRightHalf() {
+ fun source_swipeVerticallyOnTopEdge_toRightOfSplit_detectsTopEdgeRightHalf() {
val detectedEdge = swipeVerticallyFrom(x = (screenWidth / 2) + 1, y = edgeSize - 1)
+ assertThat(detectedEdge).isEqualTo(TopEdgeRightHalf)
+ }
+
+ @Test
+ fun source_swipeVerticallyBelowTopEdge_toRightOfSplit_detectsRightHalf() {
+ val detectedEdge = swipeVerticallyFrom(x = (screenWidth / 2) + 1, y = edgeSize + 1)
assertThat(detectedEdge).isEqualTo(RightHalf)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 676e1ea..579c242 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -41,16 +41,12 @@
import android.animation.Animator;
import android.annotation.IdRes;
-import android.content.ContentResolver;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Handler;
import android.os.Looper;
-import android.os.PowerManager;
-import android.os.UserManager;
import android.util.DisplayMetrics;
import android.view.Display;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -65,10 +61,8 @@
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.LatencyTracker;
-import com.android.keyguard.KeyguardSliceViewController;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
-import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.classifier.FalsingCollectorFake;
@@ -142,7 +136,6 @@
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
@@ -164,9 +157,7 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
-import com.android.systemui.statusbar.policy.SplitShadeStateController;
import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository;
-import com.android.systemui.statusbar.window.StatusBarWindowStateController;
import com.android.systemui.unfold.SysUIUnfoldComponent;
import com.android.systemui.user.domain.interactor.UserSwitcherInteractor;
import com.android.systemui.util.kotlin.JavaAdapter;
@@ -214,7 +205,6 @@
@Mock protected DozeParameters mDozeParameters;
@Mock protected ScreenOffAnimationController mScreenOffAnimationController;
@Mock protected NotificationPanelView mView;
- @Mock protected LayoutInflater mLayoutInflater;
@Mock protected DynamicPrivacyController mDynamicPrivacyController;
@Mock protected ShadeTouchableRegionManager mShadeTouchableRegionManager;
@Mock protected KeyguardStateController mKeyguardStateController;
@@ -223,7 +213,6 @@
@Mock protected CommandQueue mCommandQueue;
@Mock protected VibratorHelper mVibratorHelper;
@Mock protected LatencyTracker mLatencyTracker;
- @Mock protected PowerManager mPowerManager;
@Mock protected AccessibilityManager mAccessibilityManager;
@Mock protected MetricsLogger mMetricsLogger;
@Mock protected Resources mResources;
@@ -242,14 +231,12 @@
@Mock protected ScrimController mScrimController;
@Mock protected MediaDataManager mMediaDataManager;
@Mock protected AmbientState mAmbientState;
- @Mock protected UserManager mUserManager;
@Mock protected UiEventLogger mUiEventLogger;
@Mock protected KeyguardMediaController mKeyguardMediaController;
@Mock protected NavigationModeController mNavigationModeController;
@Mock protected NavigationBarController mNavigationBarController;
@Mock protected QuickSettingsControllerImpl mQsController;
@Mock protected ShadeHeaderController mShadeHeaderController;
- @Mock protected ContentResolver mContentResolver;
@Mock protected TapAgainViewController mTapAgainViewController;
@Mock protected KeyguardIndicationController mKeyguardIndicationController;
@Mock protected FragmentService mFragmentService;
@@ -261,12 +248,10 @@
@Mock protected DumpManager mDumpManager;
@Mock protected NotificationsQSContainerController mNotificationsQSContainerController;
@Mock protected QsFrameTranslateController mQsFrameTranslateController;
- @Mock protected StatusBarWindowStateController mStatusBarWindowStateController;
@Mock protected KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock protected NotificationShadeWindowController mNotificationShadeWindowController;
@Mock protected SysUiState mSysUiState;
@Mock protected NotificationListContainer mNotificationListContainer;
- @Mock protected NotificationStackSizeCalculator mNotificationStackSizeCalculator;
@Mock protected UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@Mock protected QS mQs;
@Mock protected QSFragmentLegacy mQSFragment;
@@ -281,8 +266,6 @@
@Mock protected AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock protected MotionEvent mDownMotionEvent;
@Mock protected CoroutineDispatcher mMainDispatcher;
- @Mock protected KeyguardSliceViewController mKeyguardSliceViewController;
- private final KeyguardLogger mKeyguardLogger = new KeyguardLogger(logcatLogBuffer());
@Captor
protected ArgumentCaptor<NotificationStackScrollLayout.OnEmptySpaceClickListener>
mEmptySpaceClickListenerCaptor;
@@ -363,9 +346,6 @@
mock(DeviceEntryUdfpsInteractor.class);
when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(MutableStateFlow(false));
- final SplitShadeStateController splitShadeStateController =
- new ResourcesSplitShadeStateController();
-
mShadeInteractor = new ShadeInteractorImpl(
mTestScope.getBackgroundScope(),
mKosmos.getDeviceProvisioningInteractor(),
@@ -380,8 +360,7 @@
mTestScope.getBackgroundScope(),
mFakeKeyguardRepository,
mShadeRepository
- ),
- mKosmos.getShadeModeInteractor());
+ ));
SystemClock systemClock = new FakeSystemClock();
mStatusBarStateController = new StatusBarStateControllerImpl(
mUiEventLogger,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
index db0c07c..348eee8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
@@ -199,8 +199,7 @@
mTestScope.getBackgroundScope(),
mKeyguardRepository,
mShadeRepository
- ),
- mKosmos.getShadeModeInteractor());
+ ));
when(mResources.getDimensionPixelSize(
R.dimen.lockscreen_shade_qs_transition_distance)).thenReturn(DEFAULT_HEIGHT);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index 67af7a5..039a32b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -353,7 +353,6 @@
notificationShadeDepthController.addListener(listener)
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(wallpaperController).setNotificationShadeZoom(anyFloat())
- verify(listener).onWallpaperZoomOutChanged(anyFloat())
verify(blurUtils).applyBlur(any(), anyInt(), eq(false))
}
@@ -369,7 +368,6 @@
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(wallpaperController).setNotificationShadeZoom(eq(0f))
- verify(listener).onWallpaperZoomOutChanged(eq(0f))
}
@Test
@@ -384,7 +382,6 @@
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(wallpaperController).setNotificationShadeZoom(floatThat { it != 0f })
- verify(listener).onWallpaperZoomOutChanged(floatThat { it != 0f })
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
index 5ec9b60..cbef24a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
@@ -24,6 +24,7 @@
import android.platform.test.flag.junit.FlagsParameterization
import android.view.View
import androidx.test.filters.SmallTest
+import com.android.internal.logging.InstanceId
import com.android.systemui.SysuiTestCase
import com.android.systemui.activity.data.repository.activityManagerRepository
import com.android.systemui.activity.data.repository.fake
@@ -44,8 +45,6 @@
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
import com.android.systemui.statusbar.core.StatusBarRootModernization
-import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentBuilder
-import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.statusbar.phone.ongoingcall.DisableChipsModernization
import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization
import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
@@ -99,39 +98,57 @@
}
@Test
- fun chip_inCall_zeroStartTime_isShownAsIconOnly() =
+ fun chip_inCall_hasKeyWithPrefix() =
kosmos.runTest {
val latest by collectLastValue(underTest.chip)
addOngoingCallState(startTimeMs = 0, isAppVisible = false)
- assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
- assertThat((latest as OngoingActivityChipModel.Active).isHidden).isFalse()
- assertThat((latest as OngoingActivityChipModel.Active).isImportantForPrivacy).isFalse()
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active::class.java)
+ assertThat((latest as OngoingActivityChipModel.Active).key)
+ .startsWith(CallChipViewModel.KEY_PREFIX)
}
@Test
- fun chip_inCall_negativeStartTime_isShownAsIconOnly() =
+ fun chip_inCall_zeroStartTime_isShownAsIconOnly_withData() =
kosmos.runTest {
val latest by collectLastValue(underTest.chip)
- addOngoingCallState(startTimeMs = -2, isAppVisible = false)
+ val instanceId = InstanceId.fakeInstanceId(10)
+ addOngoingCallState(startTimeMs = 0, isAppVisible = false, instanceId = instanceId)
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
assertThat((latest as OngoingActivityChipModel.Active).isHidden).isFalse()
assertThat((latest as OngoingActivityChipModel.Active).isImportantForPrivacy).isFalse()
+ assertThat((latest as OngoingActivityChipModel.Active).instanceId).isEqualTo(instanceId)
}
@Test
- fun chip_inCall_positiveStartTime_isShownAsTimer() =
+ fun chip_inCall_negativeStartTime_isShownAsIconOnly_withData() =
kosmos.runTest {
val latest by collectLastValue(underTest.chip)
- addOngoingCallState(startTimeMs = 345, isAppVisible = false)
+ val instanceId = InstanceId.fakeInstanceId(10)
+ addOngoingCallState(startTimeMs = -2, isAppVisible = false, instanceId = instanceId)
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
+ assertThat((latest as OngoingActivityChipModel.Active).isHidden).isFalse()
+ assertThat((latest as OngoingActivityChipModel.Active).isImportantForPrivacy).isFalse()
+ assertThat((latest as OngoingActivityChipModel.Active).instanceId).isEqualTo(instanceId)
+ }
+
+ @Test
+ fun chip_inCall_positiveStartTime_isShownAsTimer_withData() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ val instanceId = InstanceId.fakeInstanceId(10)
+ addOngoingCallState(startTimeMs = 345, isAppVisible = false, instanceId = instanceId)
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java)
assertThat((latest as OngoingActivityChipModel.Active).isHidden).isFalse()
assertThat((latest as OngoingActivityChipModel.Active).isImportantForPrivacy).isFalse()
+ assertThat((latest as OngoingActivityChipModel.Active).instanceId).isEqualTo(instanceId)
}
@Test
@@ -799,17 +816,6 @@
mock<StatusBarIconView>()
}
- private val PROMOTED_CONTENT_WITH_COLOR =
- PromotedNotificationContentBuilder("notif")
- .applyToShared {
- this.colors =
- PromotedNotificationContentModel.Colors(
- backgroundColor = PROMOTED_BACKGROUND_COLOR,
- primaryTextColor = PROMOTED_PRIMARY_TEXT_COLOR,
- )
- }
- .build()
-
private const val NOTIFICATION_KEY = "testKey"
private const val NOTIFICATION_UID = 12345
private const val PROMOTED_BACKGROUND_COLOR = 65
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt
index a60e7c1..e1b4496 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt
@@ -136,6 +136,8 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java)
assertThat((latest as OngoingActivityChipModel.Active).isImportantForPrivacy).isTrue()
+ assertThat((latest as OngoingActivityChipModel.Active).instanceId).isNotNull()
+
val icon =
(((latest as OngoingActivityChipModel.Active).icon)
as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
@@ -159,6 +161,8 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
assertThat((latest as OngoingActivityChipModel.Active).isImportantForPrivacy).isTrue()
+ assertThat((latest as OngoingActivityChipModel.Active).instanceId).isNotNull()
+
val icon =
(((latest as OngoingActivityChipModel.Active).icon)
as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
@@ -180,6 +184,8 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java)
assertThat((latest as OngoingActivityChipModel.Active).isImportantForPrivacy).isTrue()
+ assertThat((latest as OngoingActivityChipModel.Active).instanceId).isNotNull()
+
val icon =
(((latest as OngoingActivityChipModel.Active).icon)
as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
@@ -219,6 +225,8 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
assertThat((latest as OngoingActivityChipModel.Active).isImportantForPrivacy).isTrue()
+ assertThat((latest as OngoingActivityChipModel.Active).instanceId).isNotNull()
+
val icon =
(((latest as OngoingActivityChipModel.Active).icon)
as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
@@ -250,6 +258,8 @@
// Only the projection info will show a timer
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java)
assertThat((latest as OngoingActivityChipModel.Active).isImportantForPrivacy).isTrue()
+ assertThat((latest as OngoingActivityChipModel.Active).instanceId).isNotNull()
+
val icon =
(((latest as OngoingActivityChipModel.Active).icon)
as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
index 9ce43a0..3bed69b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
@@ -20,6 +20,7 @@
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.internal.logging.InstanceId
import com.android.systemui.SysuiTestCase
import com.android.systemui.activity.data.repository.activityManagerRepository
import com.android.systemui.activity.data.repository.fake
@@ -49,12 +50,14 @@
fun notificationChip_startsWithStartingModel() =
kosmos.runTest {
val icon = mock<StatusBarIconView>()
+ val instanceId = InstanceId.fakeInstanceId(4)
val startingNotif =
activeNotificationModel(
key = "notif1",
appName = "Fake Name",
statusBarChipIcon = icon,
promotedContent = PROMOTED_CONTENT,
+ instanceId = instanceId,
)
val underTest = factory.create(startingNotif, creationTime = 1)
@@ -65,12 +68,14 @@
assertThat(latest!!.appName).isEqualTo("Fake Name")
assertThat(latest!!.statusBarChipIconView).isEqualTo(icon)
assertThat(latest!!.promotedContent).isEqualTo(PROMOTED_CONTENT)
+ assertThat(latest!!.instanceId).isEqualTo(instanceId)
}
@Test
fun notificationChip_updatesAfterSet() =
kosmos.runTest {
val originalIconView = mock<StatusBarIconView>()
+ val originalInstanceId = InstanceId.fakeInstanceId(4)
val underTest =
factory.create(
activeNotificationModel(
@@ -78,6 +83,7 @@
appName = "Fake Name",
statusBarChipIcon = originalIconView,
promotedContent = PROMOTED_CONTENT,
+ instanceId = originalInstanceId,
),
creationTime = 1,
)
@@ -85,18 +91,21 @@
val latest by collectLastValue(underTest.notificationChip)
val newIconView = mock<StatusBarIconView>()
+ val newInstanceId = InstanceId.fakeInstanceId(4)
underTest.setNotification(
activeNotificationModel(
key = "notif1",
appName = "New Name",
statusBarChipIcon = newIconView,
promotedContent = PROMOTED_CONTENT,
+ instanceId = newInstanceId,
)
)
assertThat(latest!!.key).isEqualTo("notif1")
assertThat(latest!!.appName).isEqualTo("New Name")
assertThat(latest!!.statusBarChipIconView).isEqualTo(newIconView)
+ assertThat(latest!!.instanceId).isEqualTo(newInstanceId)
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
index 202d5cf..233efbb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
@@ -56,9 +56,9 @@
@Test
@DisableFlags(StatusBarNotifChips.FLAG_NAME)
- fun shownNotificationChips_flagOff_noNotifs() =
+ fun allNotificationChips_flagOff_noNotifs() =
kosmos.runTest {
- val latest by collectLastValue(underTest.shownNotificationChips)
+ val latest by collectLastValue(underTest.allNotificationChips)
setNotifs(
listOf(
@@ -75,9 +75,9 @@
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun shownNotificationChips_noNotifs_empty() =
+ fun allNotificationChips_noNotifs_empty() =
kosmos.runTest {
- val latest by collectLastValue(underTest.shownNotificationChips)
+ val latest by collectLastValue(underTest.allNotificationChips)
setNotifs(emptyList())
@@ -87,9 +87,9 @@
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
@DisableFlags(StatusBarConnectedDisplays.FLAG_NAME)
- fun shownNotificationChips_notifMissingStatusBarChipIconView_cdFlagOff_empty() =
+ fun allNotificationChips_notifMissingStatusBarChipIconView_cdFlagOff_empty() =
kosmos.runTest {
- val latest by collectLastValue(underTest.shownNotificationChips)
+ val latest by collectLastValue(underTest.allNotificationChips)
setNotifs(
listOf(
@@ -106,9 +106,9 @@
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME, StatusBarConnectedDisplays.FLAG_NAME)
- fun shownNotificationChips_notifMissingStatusBarChipIconView_cdFlagOn_notEmpty() =
+ fun allNotificationChips_notifMissingStatusBarChipIconView_cdFlagOn_notEmpty() =
kosmos.runTest {
- val latest by collectLastValue(underTest.shownNotificationChips)
+ val latest by collectLastValue(underTest.allNotificationChips)
setNotifs(
listOf(
@@ -125,9 +125,9 @@
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun shownNotificationChips_onePromotedNotif_statusBarIconViewMatches() =
+ fun allNotificationChips_onePromotedNotif_statusBarIconViewMatches() =
kosmos.runTest {
- val latest by collectLastValue(underTest.shownNotificationChips)
+ val latest by collectLastValue(underTest.allNotificationChips)
val icon = mock<StatusBarIconView>()
setNotifs(
@@ -147,9 +147,9 @@
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun shownNotificationChips_onlyForPromotedNotifs() =
+ fun allNotificationChips_onlyForPromotedNotifs() =
kosmos.runTest {
- val latest by collectLastValue(underTest.shownNotificationChips)
+ val latest by collectLastValue(underTest.allNotificationChips)
val firstIcon = mock<StatusBarIconView>()
val secondIcon = mock<StatusBarIconView>()
@@ -182,11 +182,11 @@
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun shownNotificationChips_onlyForNotVisibleApps() =
+ fun allNotificationChips_appVisibilityInfoCorrect() =
kosmos.runTest {
activityManagerRepository.fake.startingIsAppVisibleValue = false
- val latest by collectLastValue(underTest.shownNotificationChips)
+ val latest by collectLastValue(underTest.allNotificationChips)
val uid = 433
setNotifs(
@@ -195,27 +195,30 @@
key = "notif",
uid = uid,
statusBarChipIcon = mock<StatusBarIconView>(),
- promotedContent = PromotedNotificationContentBuilder("notif1").build(),
+ promotedContent = PromotedNotificationContentBuilder("notif").build(),
)
)
)
activityManagerRepository.fake.setIsAppVisible(uid, isAppVisible = false)
assertThat(latest).hasSize(1)
+ assertThat(latest!![0].isAppVisible).isFalse()
activityManagerRepository.fake.setIsAppVisible(uid, isAppVisible = true)
- assertThat(latest).isEmpty()
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0].isAppVisible).isTrue()
activityManagerRepository.fake.setIsAppVisible(uid, isAppVisible = false)
assertThat(latest).hasSize(1)
+ assertThat(latest!![0].isAppVisible).isFalse()
}
/** Regression test for b/388521980. */
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun shownNotificationChips_callNotifIsAlsoPromoted_callNotifExcluded() =
+ fun allNotificationChips_callNotifIsAlsoPromoted_callNotifExcluded() =
kosmos.runTest {
- val latest by collectLastValue(underTest.shownNotificationChips)
+ val latest by collectLastValue(underTest.allNotificationChips)
setNotifs(
listOf(
@@ -243,9 +246,9 @@
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun shownNotificationChips_notifUpdatesGoThrough() =
+ fun allNotificationChips_notifUpdatesGoThrough() =
kosmos.runTest {
- val latest by collectLastValue(underTest.shownNotificationChips)
+ val latest by collectLastValue(underTest.allNotificationChips)
val firstIcon = mock<StatusBarIconView>()
val secondIcon = mock<StatusBarIconView>()
@@ -293,9 +296,9 @@
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun shownNotificationChips_promotedNotifDisappearsThenReappears() =
+ fun allNotificationChips_promotedNotifDisappearsThenReappears() =
kosmos.runTest {
- val latest by collectLastValue(underTest.shownNotificationChips)
+ val latest by collectLastValue(underTest.allNotificationChips)
setNotifs(
listOf(
@@ -335,9 +338,9 @@
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun shownNotificationChips_sortedByFirstAppearanceTime() =
+ fun allNotificationChips_sortedByFirstAppearanceTime() =
kosmos.runTest {
- val latest by collectLastValue(underTest.shownNotificationChips)
+ val latest by collectLastValue(underTest.allNotificationChips)
val firstIcon = mock<StatusBarIconView>()
val secondIcon = mock<StatusBarIconView>()
@@ -411,9 +414,9 @@
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun shownNotificationChips_lastAppVisibleTimeMaintainedAcrossNotifAddsAndRemoves() =
+ fun allNotificationChips_lastAppVisibleTimeMaintainedAcrossNotifAddsAndRemoves() =
kosmos.runTest {
- val latest by collectLastValue(underTest.shownNotificationChips)
+ val latest by collectLastValue(underTest.allNotificationChips)
val notif1Info = NotifInfo("notif1", mock<StatusBarIconView>(), uid = 100)
val notif2Info = NotifInfo("notif2", mock<StatusBarIconView>(), uid = 200)
@@ -466,9 +469,9 @@
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun shownNotificationChips_sortedByLastAppVisibleTime() =
+ fun allNotificationChips_sortedByLastAppVisibleTime() =
kosmos.runTest {
- val latest by collectLastValue(underTest.shownNotificationChips)
+ val latest by collectLastValue(underTest.allNotificationChips)
val notif1Info = NotifInfo("notif1", mock<StatusBarIconView>(), uid = 100)
val notif2Info = NotifInfo("notif2", mock<StatusBarIconView>(), uid = 200)
@@ -496,15 +499,19 @@
fakeSystemClock.advanceTime(1000)
activityManagerRepository.fake.setIsAppVisible(notif2Info.uid, isAppVisible = true)
- // THEN notif2 is no longer shown
- assertThat(latest!!.map { it.key }).containsExactly("notif1").inOrder()
+ // THEN notif2 is ranked above notif1 because it was more recently visible
+ assertThat(latest!!.map { it.key }).containsExactly("notif2", "notif1").inOrder()
+ assertThat(latest!![0].isAppVisible).isTrue() // notif2
+ assertThat(latest!![1].isAppVisible).isFalse() // notif1
// WHEN notif2's app is no longer visible
fakeSystemClock.advanceTime(1000)
activityManagerRepository.fake.setIsAppVisible(notif2Info.uid, isAppVisible = false)
- // THEN notif2 is ranked above notif1 because it was more recently visible
+ // THEN notif2 is still ranked above notif1
assertThat(latest!!.map { it.key }).containsExactly("notif2", "notif1").inOrder()
+ assertThat(latest!![0].isAppVisible).isFalse() // notif2
+ assertThat(latest!![1].isAppVisible).isFalse() // notif1
// WHEN the app associated with notif1 becomes visible then un-visible
fakeSystemClock.advanceTime(1000)
@@ -518,9 +525,9 @@
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun shownNotificationChips_newNotificationTakesPriorityOverLastAppVisible() =
+ fun allNotificationChips_newNotificationTakesPriorityOverLastAppVisible() =
kosmos.runTest {
- val latest by collectLastValue(underTest.shownNotificationChips)
+ val latest by collectLastValue(underTest.allNotificationChips)
val notif1Info = NotifInfo("notif1", mock<StatusBarIconView>(), uid = 100)
val notif2Info = NotifInfo("notif2", mock<StatusBarIconView>(), uid = 200)
@@ -574,9 +581,9 @@
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun shownNotificationChips_fullSort() =
+ fun allNotificationChips_fullSort() =
kosmos.runTest {
- val latest by collectLastValue(underTest.shownNotificationChips)
+ val latest by collectLastValue(underTest.allNotificationChips)
val notif1Info = NotifInfo("notif1", mock<StatusBarIconView>(), uid = 100)
val notif2Info = NotifInfo("notif2", mock<StatusBarIconView>(), uid = 200)
@@ -689,9 +696,9 @@
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun shownNotificationChips_notifChangesKey() =
+ fun allNotificationChips_notifChangesKey() =
kosmos.runTest {
- val latest by collectLastValue(underTest.shownNotificationChips)
+ val latest by collectLastValue(underTest.allNotificationChips)
val firstIcon = mock<StatusBarIconView>()
val secondIcon = mock<StatusBarIconView>()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
index eecdbbf..1ee4b0f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
@@ -22,8 +22,11 @@
import android.view.View
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.internal.logging.InstanceId
import com.android.systemui.Flags.FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY
import com.android.systemui.SysuiTestCase
+import com.android.systemui.activity.data.repository.activityManagerRepository
+import com.android.systemui.activity.data.repository.fake
import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -286,6 +289,84 @@
}
@Test
+ fun chips_appStartsAsVisible_isHiddenTrue() =
+ kosmos.runTest {
+ activityManagerRepository.fake.startingIsAppVisibleValue = true
+
+ val latest by collectLastValue(underTest.chips)
+
+ val uid = 433
+ setNotifs(
+ listOf(
+ activeNotificationModel(
+ key = "notif",
+ uid = uid,
+ statusBarChipIcon = createStatusBarIconViewOrNull(),
+ promotedContent = PromotedNotificationContentBuilder("notif").build(),
+ )
+ )
+ )
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0].isHidden).isTrue()
+ }
+
+ @Test
+ fun chips_appStartsAsNotVisible_isHiddenFalse() =
+ kosmos.runTest {
+ activityManagerRepository.fake.startingIsAppVisibleValue = false
+
+ val latest by collectLastValue(underTest.chips)
+
+ val uid = 433
+ setNotifs(
+ listOf(
+ activeNotificationModel(
+ key = "notif",
+ uid = uid,
+ statusBarChipIcon = createStatusBarIconViewOrNull(),
+ promotedContent = PromotedNotificationContentBuilder("notif").build(),
+ )
+ )
+ )
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0].isHidden).isFalse()
+ }
+
+ @Test
+ fun chips_isHidden_changesBasedOnAppVisibility() =
+ kosmos.runTest {
+ activityManagerRepository.fake.startingIsAppVisibleValue = false
+
+ val latest by collectLastValue(underTest.chips)
+
+ val uid = 433
+ setNotifs(
+ listOf(
+ activeNotificationModel(
+ key = "notif",
+ uid = uid,
+ statusBarChipIcon = createStatusBarIconViewOrNull(),
+ promotedContent = PromotedNotificationContentBuilder("notif").build(),
+ )
+ )
+ )
+
+ activityManagerRepository.fake.setIsAppVisible(uid, isAppVisible = false)
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0].isHidden).isFalse()
+
+ activityManagerRepository.fake.setIsAppVisible(uid, isAppVisible = true)
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0].isHidden).isTrue()
+
+ activityManagerRepository.fake.setIsAppVisible(uid, isAppVisible = false)
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0].isHidden).isFalse()
+ }
+
+ @Test
@DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
fun chips_hasShortCriticalText_usesTextInsteadOfTime() =
kosmos.runTest {
@@ -316,6 +397,33 @@
@Test
@DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
+ fun chips_shortCriticalText_usesInstanceId() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.chips)
+
+ val promotedContentBuilder =
+ PromotedNotificationContentBuilder("notif").applyToShared {
+ this.shortCriticalText = "Arrived"
+ }
+ val instanceId = InstanceId.fakeInstanceId(30)
+ setNotifs(
+ listOf(
+ activeNotificationModel(
+ key = "notif",
+ statusBarChipIcon = createStatusBarIconViewOrNull(),
+ promotedContent = promotedContentBuilder.build(),
+ instanceId = instanceId,
+ )
+ )
+ )
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0]).isInstanceOf(OngoingActivityChipModel.Active::class.java)
+ assertThat(latest!![0].instanceId).isEqualTo(instanceId)
+ }
+
+ @Test
+ @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
fun chips_noTime_isIconOnly() =
kosmos.runTest {
val latest by collectLastValue(underTest.chips)
@@ -422,6 +530,42 @@
}
@Test
+ fun chips_basicTime_respectsIsAppVisible() =
+ kosmos.runTest {
+ activityManagerRepository.fake.startingIsAppVisibleValue = false
+
+ val latest by collectLastValue(underTest.chips)
+ val currentTime = 3.minutes.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
+
+ val promotedContentBuilder =
+ PromotedNotificationContentBuilder("notif").applyToShared {
+ this.time = When.Time(currentTime + 13.minutes.inWholeMilliseconds)
+ }
+ val uid = 3
+
+ setNotifs(
+ listOf(
+ activeNotificationModel(
+ key = "notif",
+ uid = 3,
+ statusBarChipIcon = createStatusBarIconViewOrNull(),
+ promotedContent = promotedContentBuilder.build(),
+ )
+ )
+ )
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0])
+ .isInstanceOf(OngoingActivityChipModel.Active.ShortTimeDelta::class.java)
+ assertThat(latest!![0].isHidden).isFalse()
+
+ activityManagerRepository.fake.setIsAppVisible(uid = uid, isAppVisible = true)
+
+ assertThat(latest!![0].isHidden).isTrue()
+ }
+
+ @Test
@DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
fun chips_basicTime_timeLessThanOneMinInFuture_isIconOnly() =
kosmos.runTest {
@@ -579,6 +723,48 @@
@Test
@DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
+ fun chips_countUpTime_respectsIsAppVisible() =
+ kosmos.runTest {
+ activityManagerRepository.fake.startingIsAppVisibleValue = true
+
+ val latest by collectLastValue(underTest.chips)
+ val currentTime = 30.minutes.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
+
+ val currentElapsed =
+ currentTime + fakeSystemClock.elapsedRealtime() -
+ fakeSystemClock.currentTimeMillis()
+
+ val whenElapsed = currentElapsed - 1.minutes.inWholeMilliseconds
+
+ val promotedContentBuilder =
+ PromotedNotificationContentBuilder("notif").applyToShared {
+ this.time =
+ When.Chronometer(elapsedRealtimeMillis = whenElapsed, isCountDown = false)
+ }
+ val uid = 6
+ setNotifs(
+ listOf(
+ activeNotificationModel(
+ key = "notif",
+ uid = uid,
+ statusBarChipIcon = createStatusBarIconViewOrNull(),
+ promotedContent = promotedContentBuilder.build(),
+ )
+ )
+ )
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0]).isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java)
+ assertThat(latest!![0].isHidden).isTrue()
+
+ activityManagerRepository.fake.setIsAppVisible(uid, isAppVisible = false)
+
+ assertThat(latest!![0].isHidden).isFalse()
+ }
+
+ @Test
+ @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
fun chips_countDownTime_isTimer() =
kosmos.runTest {
val latest by collectLastValue(underTest.chips)
@@ -616,6 +802,41 @@
@Test
@DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
+ fun chips_countDownTime_usesInstanceId() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.chips)
+
+ val instanceId = InstanceId.fakeInstanceId(20)
+ val currentTime = 30.minutes.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
+
+ val currentElapsed =
+ currentTime + fakeSystemClock.elapsedRealtime() -
+ fakeSystemClock.currentTimeMillis()
+ val whenElapsed = currentElapsed + 10.minutes.inWholeMilliseconds
+ val promotedContentBuilder =
+ PromotedNotificationContentBuilder("notif").applyToShared {
+ this.time =
+ When.Chronometer(elapsedRealtimeMillis = whenElapsed, isCountDown = true)
+ }
+ setNotifs(
+ listOf(
+ activeNotificationModel(
+ key = "notif",
+ statusBarChipIcon = createStatusBarIconViewOrNull(),
+ promotedContent = promotedContentBuilder.build(),
+ instanceId = instanceId,
+ )
+ )
+ )
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0]).isInstanceOf(OngoingActivityChipModel.Active::class.java)
+ assertThat((latest!![0]).instanceId).isEqualTo(instanceId)
+ }
+
+ @Test
+ @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
fun chips_noHeadsUp_showsTime() =
kosmos.runTest {
val latest by collectLastValue(underTest.chips)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
index 9194221..3e67e98 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
@@ -111,6 +111,7 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active.Countdown::class.java)
assertThat((latest as OngoingActivityChipModel.Active).isImportantForPrivacy).isTrue()
+ assertThat((latest as OngoingActivityChipModel.Active).instanceId).isNotNull()
assertThat((latest as OngoingActivityChipModel.Active).icon).isNull()
assertThat((latest as OngoingActivityChipModel.Active).onClickListenerLegacy).isNull()
}
@@ -158,6 +159,7 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java)
assertThat((latest as OngoingActivityChipModel.Active).isImportantForPrivacy).isTrue()
+ assertThat((latest as OngoingActivityChipModel.Active).instanceId).isNotNull()
val icon =
(((latest as OngoingActivityChipModel.Active).icon)
as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
index 99e378c..ad556b7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
@@ -385,6 +385,8 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
assertThat((latest as OngoingActivityChipModel.Active).isImportantForPrivacy).isTrue()
+ assertThat((latest as OngoingActivityChipModel.Active).instanceId).isNotNull()
+
val icon =
(((latest as OngoingActivityChipModel.Active).icon)
as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
@@ -409,6 +411,8 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java)
assertThat((latest as OngoingActivityChipModel.Active).isImportantForPrivacy).isTrue()
+ assertThat((latest as OngoingActivityChipModel.Active).instanceId).isNotNull()
+
val icon =
(((latest as OngoingActivityChipModel.Active).icon)
as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
@@ -427,6 +431,8 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java)
assertThat((latest as OngoingActivityChipModel.Active).isImportantForPrivacy).isTrue()
+ assertThat((latest as OngoingActivityChipModel.Active).instanceId).isNotNull()
+
val icon =
(((latest as OngoingActivityChipModel.Active).icon)
as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt
index 39b19d3..0eddcd5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt
@@ -20,6 +20,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.jank.Cuj
+import com.android.internal.logging.InstanceId
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogCuj
import com.android.systemui.animation.DialogTransitionAnimator
@@ -29,9 +30,11 @@
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickCallback
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickListener
+import com.android.systemui.statusbar.chips.uievents.statusBarChipsUiEventLogger
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.statusbar.phone.ongoingcall.DisableChipsModernization
import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization
+import com.android.systemui.testKosmos
import kotlin.test.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyBoolean
@@ -44,6 +47,7 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
class OngoingActivityChipViewModelTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
private val mockSystemUIDialog = mock<SystemUIDialog>()
private val dialogDelegate = SystemUIDialog.Delegate { mockSystemUIDialog }
private val dialogTransitionAnimator = mock<DialogTransitionAnimator>()
@@ -70,8 +74,10 @@
dialogDelegate,
dialogTransitionAnimator,
cuj,
- logcatLogBuffer("OngoingActivityChipViewModelTest"),
- "tag",
+ instanceId = InstanceId.fakeInstanceId(0),
+ uiEventLogger = kosmos.statusBarChipsUiEventLogger,
+ logger = logcatLogBuffer("OngoingActivityChipViewModelTest"),
+ tag = "tag",
)
clickListener.onClick(chipView)
@@ -88,8 +94,10 @@
dialogDelegate,
dialogTransitionAnimator,
cuj,
- logcatLogBuffer("OngoingActivityChipViewModelTest"),
- "tag",
+ instanceId = InstanceId.fakeInstanceId(0),
+ uiEventLogger = kosmos.statusBarChipsUiEventLogger,
+ logger = logcatLogBuffer("OngoingActivityChipViewModelTest"),
+ tag = "tag",
)
clickCallback.invoke(mockExpandable)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
index e39fa70..4f0dfd3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
@@ -41,6 +41,7 @@
import com.android.systemui.res.R
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
+import com.android.systemui.statusbar.chips.call.ui.viewmodel.CallChipViewModel
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.notification.shared.StatusBarNotifChips
@@ -402,7 +403,8 @@
context: Context,
) {
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active::class.java)
- assertThat((latest as OngoingActivityChipModel.Active).key).isEqualTo(notificationKey)
+ assertThat((latest as OngoingActivityChipModel.Active).key)
+ .isEqualTo("${CallChipViewModel.KEY_PREFIX}$notificationKey")
if (StatusBarConnectedDisplays.isEnabled) {
assertNotificationIcon(latest, notificationKey)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
index 83b3c9c..826f944 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
@@ -42,6 +42,7 @@
import com.android.systemui.res.R
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
+import com.android.systemui.statusbar.chips.call.ui.viewmodel.CallChipViewModel
import com.android.systemui.statusbar.chips.call.ui.viewmodel.CallChipViewModelTest.Companion.createStatusBarIconViewOrNull
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
@@ -269,7 +270,10 @@
addOngoingCallState(callNotificationKey)
assertThat(latest)
- .containsExactly(ScreenRecordChipViewModel.KEY, callNotificationKey)
+ .containsExactly(
+ ScreenRecordChipViewModel.KEY,
+ "${CallChipViewModel.KEY_PREFIX}$callNotificationKey",
+ )
.inOrder()
}
@@ -1103,7 +1107,10 @@
)
assertThat(latest)
- .containsExactly(ScreenRecordChipViewModel.KEY, callNotificationKey)
+ .containsExactly(
+ ScreenRecordChipViewModel.KEY,
+ "${CallChipViewModel.KEY_PREFIX}$callNotificationKey",
+ )
.inOrder()
}
@@ -1132,7 +1139,11 @@
)
assertThat(latest)
- .containsExactly(ScreenRecordChipViewModel.KEY, callNotificationKey, "notif1")
+ .containsExactly(
+ ScreenRecordChipViewModel.KEY,
+ "${CallChipViewModel.KEY_PREFIX}$callNotificationKey",
+ "notif1",
+ )
.inOrder()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
index a58f7f7..ae5cd01 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
@@ -41,6 +41,7 @@
import android.os.Handler;
import android.os.UserHandle;
import android.provider.DeviceConfig;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.testing.TestableLooper;
@@ -101,52 +102,53 @@
switchFlag("false");
// test flag disables logic with default values
assertEquals(STATUS_UNCHANGED, mAssistantFeedbackController.getFeedbackStatus(
- getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED)));
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED).getRanking()));
assertNull(mAssistantFeedbackController.getFeedbackIcon(
- getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED)));
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED).getRanking()));
// test that the flag disables logic with values that otherwise would return a value
assertEquals(STATUS_UNCHANGED, mAssistantFeedbackController.getFeedbackStatus(
- getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_PROMOTED)));
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_PROMOTED).getRanking()));
assertNull(mAssistantFeedbackController.getFeedbackIcon(
- getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_PROMOTED)));
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_PROMOTED).getRanking()));
}
@Test
public void testFeedback_noChange() {
switchFlag("true");
assertEquals(STATUS_UNCHANGED, mAssistantFeedbackController.getFeedbackStatus(
- getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED)));
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED).getRanking()));
assertNull(mAssistantFeedbackController.getFeedbackIcon(
- getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED)));
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_UNCHANGED).getRanking()));
}
@Test
public void testFeedback_changedImportance() {
switchFlag("true");
- NotificationEntry entry = getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_UNCHANGED);
- assertEquals(STATUS_PROMOTED, mAssistantFeedbackController.getFeedbackStatus(entry));
- assertNotNull(mAssistantFeedbackController.getFeedbackIcon(entry));
+ NotificationListenerService.Ranking ranking =
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_UNCHANGED).getRanking();
+ assertEquals(STATUS_PROMOTED, mAssistantFeedbackController.getFeedbackStatus(ranking));
+ assertNotNull(mAssistantFeedbackController.getFeedbackIcon(ranking));
- entry = getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_LOW, RANKING_UNCHANGED);
- assertEquals(STATUS_SILENCED, mAssistantFeedbackController.getFeedbackStatus(entry));
- assertNotNull(mAssistantFeedbackController.getFeedbackIcon(entry));
+ ranking = getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_LOW, RANKING_UNCHANGED).getRanking();
+ assertEquals(STATUS_SILENCED, mAssistantFeedbackController.getFeedbackStatus(ranking));
+ assertNotNull(mAssistantFeedbackController.getFeedbackIcon(ranking));
- entry = getEntry(IMPORTANCE_LOW, IMPORTANCE_MIN, RANKING_UNCHANGED);
- assertEquals(STATUS_DEMOTED, mAssistantFeedbackController.getFeedbackStatus(entry));
- assertNotNull(mAssistantFeedbackController.getFeedbackIcon(entry));
+ ranking = getEntry(IMPORTANCE_LOW, IMPORTANCE_MIN, RANKING_UNCHANGED).getRanking();
+ assertEquals(STATUS_DEMOTED, mAssistantFeedbackController.getFeedbackStatus(ranking));
+ assertNotNull(mAssistantFeedbackController.getFeedbackIcon(ranking));
}
@Test
public void testFeedback_changedRanking() {
switchFlag("true");
- NotificationEntry entry =
- getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_PROMOTED);
- assertEquals(STATUS_PROMOTED, mAssistantFeedbackController.getFeedbackStatus(entry));
- assertNotNull(mAssistantFeedbackController.getFeedbackIcon(entry));
+ NotificationListenerService.Ranking ranking =
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_PROMOTED).getRanking();
+ assertEquals(STATUS_PROMOTED, mAssistantFeedbackController.getFeedbackStatus(ranking));
+ assertNotNull(mAssistantFeedbackController.getFeedbackIcon(ranking));
- entry = getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_DEMOTED);
- assertEquals(STATUS_DEMOTED, mAssistantFeedbackController.getFeedbackStatus(entry));
- assertNotNull(mAssistantFeedbackController.getFeedbackIcon(entry));
+ ranking = getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_DEFAULT, RANKING_DEMOTED).getRanking();
+ assertEquals(STATUS_DEMOTED, mAssistantFeedbackController.getFeedbackStatus(ranking));
+ assertNotNull(mAssistantFeedbackController.getFeedbackIcon(ranking));
}
@Test
@@ -155,7 +157,7 @@
FeedbackIcon expected = new FeedbackIcon(com.android.internal.R.drawable.ic_feedback_uprank,
com.android.internal.R.string.notification_feedback_indicator_promoted);
assertEquals(expected, mAssistantFeedbackController.getFeedbackIcon(
- getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_PROMOTED)));
+ getEntry(IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, RANKING_PROMOTED).getRanking()));
}
private NotificationEntry getEntry(int oldImportance, int newImportance,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/ConversationNotificationProcessorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/ConversationNotificationProcessorTest.kt
index 0caddf4..d56890d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/ConversationNotificationProcessorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/ConversationNotificationProcessorTest.kt
@@ -137,9 +137,28 @@
@Test
@EnableFlags(Flags.FLAG_NM_SUMMARIZATION)
+ fun processNotification_messagingStyleUpdateSummarizationToNull() {
+ val nb = getMessagingNotification()
+ val newRow: ExpandableNotificationRow = testHelper.createRow(nb.build())
+ newRow.entry.setRanking(
+ RankingBuilder(newRow.entry.ranking).setSummarization("hello").build()
+ )
+ assertThat(conversationNotificationProcessor.processNotification(newRow.entry, nb, logger))
+ .isNotNull()
+
+ newRow.entry.setRanking(RankingBuilder(newRow.entry.ranking).setSummarization(null).build())
+
+ assertThat(conversationNotificationProcessor.processNotification(newRow.entry, nb, logger))
+ .isNotNull()
+ assertThat(nb.build().extras.getCharSequence(EXTRA_SUMMARIZED_CONTENT)).isNull()
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_NM_SUMMARIZATION)
fun processNotification_messagingStyleWithoutSummarization() {
val nb = getMessagingNotification()
val newRow: ExpandableNotificationRow = testHelper.createRow(nb.build())
+
assertThat(conversationNotificationProcessor.processNotification(newRow.entry, nb, logger))
.isNotNull()
assertThat(nb.build().extras.getCharSequence(EXTRA_SUMMARIZED_CONTENT)).isNull()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimatorTest.kt
index 0bb4737..c22b03c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimatorTest.kt
@@ -207,6 +207,21 @@
}
@Test
+ fun testCancelAnimationResetsOffset() {
+ PhysicsPropertyAnimator.setProperty(
+ view,
+ property,
+ 200f,
+ animationProperties,
+ true,
+ finishListener,
+ )
+ val propertyData = ViewState.getChildTag(view, property.tag) as PropertyData
+ propertyData.animator?.cancel()
+ Assert.assertTrue(propertyData.offset == 0f)
+ }
+
+ @Test
fun testUsingListenerProperties() {
val finishListener2 = Mockito.mock(DynamicAnimation.OnAnimationEndListener::class.java)
val animationProperties: AnimationProperties =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapterTest.kt
index 1018748..52f68bf 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapterTest.kt
@@ -25,7 +25,9 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
+import com.android.systemui.statusbar.notification.row.entryAdapterFactory
import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
+import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
@@ -36,13 +38,15 @@
@RunWith(AndroidJUnit4::class)
@RunWithLooper
class BundleEntryAdapterTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
private lateinit var underTest: BundleEntryAdapter
@get:Rule val setFlagsRule = SetFlagsRule()
+ private val factory: EntryAdapterFactory = kosmos.entryAdapterFactory
@Before
fun setUp() {
- underTest = BundleEntryAdapter(BundleEntry("key"))
+ underTest = factory.create(BundleEntry("key")) as BundleEntryAdapter
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt
index 7449064..02c6a48 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt
@@ -29,6 +29,9 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.res.R
import com.android.systemui.statusbar.RankingBuilder
+import com.android.systemui.statusbar.notification.collection.coordinator.mockVisualStabilityCoordinator
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
+import com.android.systemui.statusbar.notification.collection.provider.mockHighPriorityProvider
import com.android.systemui.statusbar.notification.mockNotificationActivityStarter
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_FULL_PERSON
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
@@ -41,9 +44,12 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Mockito
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -257,6 +263,109 @@
@Test
@EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun getRanking() {
+ val notification: Notification =
+ Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .addAction(Mockito.mock(Notification.Action::class.java))
+ .build()
+
+ val entry = NotificationEntryBuilder().setNotification(notification).build()
+
+ underTest = factory.create(entry) as NotificationEntryAdapter
+ assertThat(underTest.ranking).isEqualTo(entry.ranking)
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun endLifetimeExtension() {
+ val notification: Notification =
+ Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .addAction(Mockito.mock(Notification.Action::class.java))
+ .build()
+
+ val entry = NotificationEntryBuilder().setNotification(notification).build()
+ val callback =
+ Mockito.mock(NotifLifetimeExtender.OnEndLifetimeExtensionCallback::class.java)
+
+ underTest = factory.create(entry) as NotificationEntryAdapter
+ underTest.endLifetimeExtension(callback, Mockito.mock(NotifLifetimeExtender::class.java))
+ verify(callback).onEndLifetimeExtension(any(), eq(entry))
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun onImportanceChanged() {
+ val notification: Notification =
+ Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .addAction(Mockito.mock(Notification.Action::class.java))
+ .build()
+
+ val entry = NotificationEntryBuilder().setNotification(notification).build()
+
+ underTest = factory.create(entry) as NotificationEntryAdapter
+
+ underTest.onImportanceChanged()
+ verify(kosmos.mockVisualStabilityCoordinator)
+ .temporarilyAllowSectionChanges(eq(entry), anyLong())
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun markForUserTriggeredMovement() {
+ val notification: Notification =
+ Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .addAction(Mockito.mock(Notification.Action::class.java))
+ .build()
+
+ val entry = NotificationEntryBuilder().setNotification(notification).build()
+ underTest = factory.create(entry) as NotificationEntryAdapter
+
+ assertThat(underTest.isMarkedForUserTriggeredMovement)
+ .isEqualTo(entry.isMarkedForUserTriggeredMovement)
+
+ underTest.markForUserTriggeredMovement()
+ assertThat(underTest.isMarkedForUserTriggeredMovement)
+ .isEqualTo(entry.isMarkedForUserTriggeredMovement)
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun isHighPriority() {
+ val notification: Notification =
+ Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .addAction(Mockito.mock(Notification.Action::class.java))
+ .build()
+
+ val entry = NotificationEntryBuilder().setNotification(notification).build()
+ underTest = factory.create(entry) as NotificationEntryAdapter
+
+ underTest.isHighPriority
+
+ verify(kosmos.mockHighPriorityProvider).isHighPriority(entry)
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun isBlockable() {
+ val notification: Notification =
+ Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .addAction(Mockito.mock(Notification.Action::class.java))
+ .build()
+
+ val entry = NotificationEntryBuilder().setNotification(notification).build()
+ underTest = factory.create(entry) as NotificationEntryAdapter
+
+ assertThat(underTest.isBlockable).isEqualTo(entry.isBlockable)
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
fun canDragAndDrop() {
val pi = mock(PendingIntent::class.java)
Mockito.`when`(pi.isActivity).thenReturn(true)
@@ -436,7 +545,6 @@
underTest = factory.create(entry) as NotificationEntryAdapter
-
underTest.onEntryClicked(row)
verify(kosmos.mockNotificationActivityStarter).onNotificationClicked(entry, row)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
index 7fe97d2..928b001 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
@@ -15,12 +15,15 @@
*/
package com.android.systemui.statusbar.notification.collection.coordinator
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.testing.TestableLooper.RunWithLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.logcatLogBuffer
+import com.android.systemui.statusbar.notification.collection.EntryAdapter
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
@@ -30,6 +33,9 @@
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager
import com.android.systemui.statusbar.notification.row.NotificationGuts
import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent
+import com.android.systemui.statusbar.notification.row.entryAdapterFactory
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
+import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -45,12 +51,16 @@
@RunWith(AndroidJUnit4::class)
@RunWithLooper
class GutsCoordinatorTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
private lateinit var coordinator: GutsCoordinator
private lateinit var notifLifetimeExtender: NotifLifetimeExtender
private lateinit var notifGutsViewListener: NotifGutsViewListener
private lateinit var entry1: NotificationEntry
private lateinit var entry2: NotificationEntry
+ private lateinit var entryAdapter1: EntryAdapter
+ private lateinit var entryAdapter2: EntryAdapter
@Mock private lateinit var notifGutsViewManager: NotifGutsViewManager
@Mock private lateinit var pipeline: NotifPipeline
@@ -73,22 +83,71 @@
notifLifetimeExtender.setCallback(lifetimeExtenderCallback)
entry1 = NotificationEntryBuilder().setId(1).build()
entry2 = NotificationEntryBuilder().setId(2).build()
+ entryAdapter1 = kosmos.entryAdapterFactory.create(entry1)
+ entryAdapter2 = kosmos.entryAdapterFactory.create(entry2)
whenever(notificationGuts.gutsContent).thenReturn(mock(GutsContent::class.java))
}
@Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
fun testSimpleLifetimeExtension() {
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
- notifGutsViewListener.onGutsOpen(entry1, notificationGuts)
+ notifGutsViewListener.onGutsOpen(entryAdapter1, notificationGuts)
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
- notifGutsViewListener.onGutsClose(entry1)
+ notifGutsViewListener.onGutsClose(entryAdapter1)
verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
}
@Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
fun testDoubleOpenLifetimeExtension() {
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ notifGutsViewListener.onGutsOpen(entryAdapter1, notificationGuts)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
+ notifGutsViewListener.onGutsOpen(entryAdapter1, notificationGuts)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
+ notifGutsViewListener.onGutsClose(entryAdapter1)
+ verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun testTwoEntryLifetimeExtension() {
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isFalse()
+ notifGutsViewListener.onGutsOpen(entryAdapter1, notificationGuts)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isFalse()
+ notifGutsViewListener.onGutsOpen(entryAdapter2, notificationGuts)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isTrue()
+ notifGutsViewListener.onGutsClose(entryAdapter1)
+ verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isTrue()
+ notifGutsViewListener.onGutsClose(entryAdapter2)
+ verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry2)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isFalse()
+ }
+
+ @Test
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
+ fun testSimpleLifetimeExtension_entry() {
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ notifGutsViewListener.onGutsOpen(entry1, notificationGuts)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
+ notifGutsViewListener.onGutsClose(entry1)
+ verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ }
+
+ @Test
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
+ fun testDoubleOpenLifetimeExtension_entry() {
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
notifGutsViewListener.onGutsOpen(entry1, notificationGuts)
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
notifGutsViewListener.onGutsOpen(entry1, notificationGuts)
@@ -99,7 +158,8 @@
}
@Test
- fun testTwoEntryLifetimeExtension() {
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
+ fun testTwoEntryLifetimeExtension_entry() {
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isFalse()
notifGutsViewListener.onGutsOpen(entry1, notificationGuts)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index 44d88c3..247c66a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -17,7 +17,9 @@
import android.app.Notification.GROUP_ALERT_ALL
import android.app.Notification.GROUP_ALERT_SUMMARY
+import android.app.NotificationChannel.SYSTEM_RESERVED_IDS
import android.platform.test.annotations.EnableFlags
+import android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION
import android.testing.TestableLooper.RunWithLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -28,6 +30,7 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager
import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
+import com.android.systemui.statusbar.chips.uievents.statusBarChipsUiEventLogger
import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
import com.android.systemui.statusbar.notification.collection.NotifPipeline
@@ -49,6 +52,7 @@
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper.DecisionImpl
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper.FullScreenIntentDecisionImpl
+import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionLogger
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider
import com.android.systemui.statusbar.notification.row.mockNotificationActionClickManager
import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
@@ -60,7 +64,6 @@
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.withArgCaptor
import com.android.systemui.util.time.FakeSystemClock
-import java.util.ArrayList
import java.util.function.Consumer
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
@@ -104,6 +107,7 @@
private val notifPipeline: NotifPipeline = mock()
private val logger = HeadsUpCoordinatorLogger(logcatLogBuffer(), verbose = true)
+ private val interruptLogger: VisualInterruptionDecisionLogger = mock()
private val headsUpManager: HeadsUpManagerImpl = mock()
private val headsUpViewBinder: HeadsUpViewBinder = mock()
private val visualInterruptionDecisionProvider: VisualInterruptionDecisionProvider = mock()
@@ -134,6 +138,7 @@
HeadsUpCoordinator(
kosmos.applicationCoroutineScope,
logger,
+ interruptLogger,
systemClock,
notifCollection,
headsUpManager,
@@ -144,6 +149,7 @@
launchFullScreenIntentProvider,
flags,
statusBarNotificationChipsInteractor,
+ kosmos.statusBarChipsUiEventLogger,
headerController,
executor,
)
@@ -164,15 +170,15 @@
verify(notifPipeline).addOnBeforeFinalizeFilterListener(capture())
}
onHeadsUpChangedListener = withArgCaptor { verify(headsUpManager).addListener(capture()) }
- actionPressListener = if (NotificationBundleUi.isEnabled) {
- withArgCaptor {
- verify(kosmos.mockNotificationActionClickManager).addActionClickListener(capture())
+ actionPressListener =
+ if (NotificationBundleUi.isEnabled) {
+ withArgCaptor {
+ verify(kosmos.mockNotificationActionClickManager)
+ .addActionClickListener(capture())
+ }
+ } else {
+ withArgCaptor { verify(remoteInputManager).addActionPressListener(capture()) }
}
- } else {
- withArgCaptor {
- verify(remoteInputManager).addActionPressListener(capture())
- }
- }
given(headsUpManager.allEntries).willAnswer { huns.stream() }
given(headsUpManager.isHeadsUpEntry(anyString())).willAnswer { invocation ->
val key = invocation.getArgument<String>(0)
@@ -918,6 +924,48 @@
assertFalse(groupSummary.hasInterrupted())
}
+ private fun helpTestNoTransferToBundleChildForChannel(channelId: String) {
+ // Set up for normal alert transfer from summary to child
+ // but here child is classified so it should not happen
+ val bundleChild =
+ helper.createClassifiedEntry(/* isSummary= */ false, GROUP_ALERT_SUMMARY, channelId);
+ setShouldHeadsUp(bundleChild, true)
+ setShouldHeadsUp(groupSummary, true)
+ whenever(notifPipeline.allNotifs).thenReturn(listOf(groupSummary, bundleChild))
+
+ collectionListener.onEntryAdded(groupSummary)
+ collectionListener.onEntryAdded(bundleChild)
+
+ beforeTransformGroupsListener.onBeforeTransformGroups(listOf(groupSummary, bundleChild))
+ beforeFinalizeFilterListener.onBeforeFinalizeFilter(listOf(groupSummary, bundleChild))
+
+ verify(headsUpViewBinder, never()).bindHeadsUpView(eq(groupSummary), any(), any())
+ verify(headsUpViewBinder, never()).bindHeadsUpView(eq(bundleChild), any(), any())
+
+ verify(headsUpManager, never()).showNotification(groupSummary)
+ verify(headsUpManager, never()).showNotification(bundleChild)
+
+ // Capture last param
+ val decision = withArgCaptor {
+ verify(interruptLogger)
+ .logDecision(capture(), capture(), capture())
+ }
+ assertFalse(decision.shouldInterrupt)
+ assertEquals(decision.logReason, "disqualified-transfer-target")
+
+ // Must clear invocations, otherwise these calls get stored for the next call from the same
+ // test, which complains that there are more invocations than expected
+ clearInvocations(interruptLogger)
+ }
+
+ @Test
+ @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
+ fun testNoTransfer_toBundleChild() {
+ for (id in SYSTEM_RESERVED_IDS) {
+ helpTestNoTransferToBundleChildForChannel(id)
+ }
+ }
+
@Test
fun testOnRankingApplied_newEntryShouldAlert() {
// GIVEN that mEntry has never interrupted in the past, and now should
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
index d61fc05..28ca891 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.logging;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.nano.Notifications;
@@ -49,6 +50,11 @@
public void logNotificationDrag(NotificationEntry draggedNotification) {
}
+ @Override
+ public void logNotificationDrag(EntryAdapter draggedNotification) {
+
+ }
+
public static class CallRecord {
public boolean isLockscreen;
public Notifications.NotificationList list;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
index fd49f60..bbff9cf 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
@@ -40,9 +40,12 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.shade.ShadeController;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.headsup.PinnedStatus;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import org.junit.Before;
import org.junit.Test;
@@ -99,7 +102,13 @@
mRow.doDragCallback(0, 0);
verify(controller).startDragAndDrop(mRow);
verify(mHeadsUpManager, times(1)).releaseAllImmediately();
- verify(mNotificationPanelLogger, times(1)).logNotificationDrag(any());
+ if (NotificationBundleUi.isEnabled()) {
+ verify(mNotificationPanelLogger, times(1))
+ .logNotificationDrag(any(EntryAdapter.class));
+ } else {
+ verify(mNotificationPanelLogger, times(1))
+ .logNotificationDrag(any(NotificationEntry.class));
+ }
}
@Test
@@ -111,7 +120,13 @@
verify(controller).startDragAndDrop(mRow);
verify(mShadeController).animateCollapseShade(eq(0), eq(true),
eq(false), anyFloat());
- verify(mNotificationPanelLogger, times(1)).logNotificationDrag(any());
+ if (NotificationBundleUi.isEnabled()) {
+ verify(mNotificationPanelLogger, times(1))
+ .logNotificationDrag(any(EntryAdapter.class));
+ } else {
+ verify(mNotificationPanelLogger, times(1))
+ .logNotificationDrag(any(NotificationEntry.class));
+ }
}
@Test
@@ -129,8 +144,13 @@
// Verify that we never start the actual drag since there is no content
verify(mRow, never()).startDragAndDrop(any(), any(), any(), anyInt());
- verify(mNotificationPanelLogger, never()).logNotificationDrag(any());
- }
+ if (NotificationBundleUi.isEnabled()) {
+ verify(mNotificationPanelLogger, never())
+ .logNotificationDrag(any(EntryAdapter.class));
+ } else {
+ verify(mNotificationPanelLogger, never())
+ .logNotificationDrag(any(NotificationEntry.class));
+ } }
private ExpandableNotificationRowDragController createSpyController() {
return spy(mController);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
index 0947cd5..e808deb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
@@ -44,6 +44,7 @@
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.view.LayoutInflater;
import android.view.View;
@@ -132,7 +133,7 @@
@Test
public void testBindNotification_SetsTextApplicationName() {
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
- mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(),
+ mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry().getRanking(),
mMockNotificationRow, mAssistantFeedbackController, mStatusBarService,
mNotificationGutsManager);
final TextView textView = mFeedbackInfo.findViewById(R.id.pkg_name);
@@ -144,7 +145,7 @@
final Drawable iconDrawable = mock(Drawable.class);
when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class)))
.thenReturn(iconDrawable);
- mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(),
+ mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry().getRanking(),
mMockNotificationRow, mAssistantFeedbackController, mStatusBarService,
mNotificationGutsManager);
final ImageView iconView = mFeedbackInfo.findViewById(R.id.pkg_icon);
@@ -153,9 +154,11 @@
@Test
public void testPrompt_silenced() {
- when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class)))
+ when(mAssistantFeedbackController.getFeedbackStatus(
+ any(NotificationListenerService.Ranking.class)))
.thenReturn(STATUS_SILENCED);
- mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
+ mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry().getRanking(),
+ mMockNotificationRow,
mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
assertEquals("This notification was automatically demoted to Silent by the system. "
@@ -165,9 +168,11 @@
@Test
public void testPrompt_promoted() {
- when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class)))
+ when(mAssistantFeedbackController.getFeedbackStatus(
+ any(NotificationListenerService.Ranking.class)))
.thenReturn(STATUS_PROMOTED);
- mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
+ mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry().getRanking(),
+ mMockNotificationRow,
mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
assertEquals("This notification was automatically ranked higher in your shade. "
@@ -177,9 +182,11 @@
@Test
public void testPrompt_alerted() {
- when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class)))
+ when(mAssistantFeedbackController.getFeedbackStatus(
+ any(NotificationListenerService.Ranking.class)))
.thenReturn(STATUS_ALERTED);
- mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
+ mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry().getRanking(),
+ mMockNotificationRow,
mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
assertEquals("This notification was automatically promoted to Default by the system. "
@@ -189,9 +196,11 @@
@Test
public void testPrompt_demoted() {
- when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class)))
+ when(mAssistantFeedbackController.getFeedbackStatus(
+ any(NotificationListenerService.Ranking.class)))
.thenReturn(STATUS_DEMOTED);
- mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
+ mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry().getRanking(),
+ mMockNotificationRow,
mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
assertEquals("This notification was automatically ranked lower in your shade. "
@@ -201,7 +210,8 @@
@Test
public void testPositiveFeedback() {
- mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
+ mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry().getRanking(),
+ mMockNotificationRow,
mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
final View yes = mFeedbackInfo.findViewById(R.id.yes);
@@ -218,7 +228,8 @@
any(NotificationMenuRowPlugin.MenuItem.class)))
.thenReturn(true);
- mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
+ mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry().getRanking(),
+ mMockNotificationRow,
mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);
final View no = mFeedbackInfo.findViewById(R.id.no);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
index 387c62d..324487b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
@@ -67,15 +67,19 @@
import com.android.systemui.statusbar.NotificationPresenter
import com.android.systemui.statusbar.notification.AssistantFeedbackController
import com.android.systemui.statusbar.notification.NotificationActivityStarter
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
+import com.android.systemui.statusbar.notification.collection.provider.mockHighPriorityProvider
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
+import com.android.systemui.statusbar.notification.headsup.mockHeadsUpManager
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.promoted.domain.interactor.PackageDemotionInteractor
import com.android.systemui.statusbar.notification.row.icon.AppIconProvider
import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider
import com.android.systemui.statusbar.notification.row.icon.appIconProvider
import com.android.systemui.statusbar.notification.row.icon.notificationIconStyleProvider
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.testKosmos
@@ -263,7 +267,11 @@
assertEquals(View.INVISIBLE.toLong(), guts.visibility.toLong())
executor.runAllReady()
verify(guts).openControls(anyInt(), anyInt(), anyBoolean(), any<Runnable>())
- verify(headsUpManager).setGutsShown(realRow.entry, true)
+ if (NotificationBundleUi.isEnabled) {
+ verify(kosmos.mockHeadsUpManager).setGutsShown(any<NotificationEntry>(), eq(true))
+ } else {
+ verify(headsUpManager).setGutsShown(realRow.entry, true)
+ }
assertEquals(View.VISIBLE.toLong(), guts.visibility.toLong())
gutsManager.closeAndSaveGuts(false, false, true, 0, 0, false)
@@ -271,7 +279,11 @@
verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean())
verify(row, times(1)).setGutsView(any<MenuItem>())
executor.runAllReady()
- verify(headsUpManager).setGutsShown(realRow.entry, false)
+ if (NotificationBundleUi.isEnabled) {
+ verify(kosmos.mockHeadsUpManager).setGutsShown(any<NotificationEntry>(), eq(false))
+ } else {
+ verify(headsUpManager).setGutsShown(realRow.entry, false)
+ }
}
@Test
@@ -301,7 +313,11 @@
verify(guts).closeControls(anyInt(), anyInt(), eq(false), eq(false))
verify(row, times(1)).setGutsView(any<MenuItem>())
executor.runAllReady()
- verify(headsUpManager).setGutsShown(realRow.entry, false)
+ if (NotificationBundleUi.isEnabled) {
+ verify(kosmos.mockHeadsUpManager).setGutsShown(any<NotificationEntry>(), eq(false))
+ } else {
+ verify(headsUpManager).setGutsShown(realRow.entry, false)
+ }
}
@Test
@@ -505,17 +521,22 @@
@Throws(Exception::class)
fun testInitializeNotificationInfoView_highPriority() {
val notificationInfoView: NotificationInfo = mock()
- val row = spy(helper.createRow())
+ val row = createTestNotificationRow()
val entry = row.entry
NotificationEntryHelper.modifyRanking(entry)
.setUserSentiment(NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE)
.setImportance(NotificationManager.IMPORTANCE_HIGH)
.build()
- whenever(row.canViewBeDismissed()).thenReturn(true)
whenever(highPriorityProvider.isHighPriority(entry)).thenReturn(true)
+ whenever(kosmos.mockHighPriorityProvider.isHighPriority(entry)).thenReturn(true)
val statusBarNotification = entry.sbn
- gutsManager.initializeNotificationInfo(row, notificationInfoView)
+ gutsManager.initializeNotificationInfo(
+ row,
+ statusBarNotification,
+ entry.ranking,
+ notificationInfoView,
+ )
verify(notificationInfoView)
.bindNotification(
@@ -527,15 +548,17 @@
eq(channelEditorDialogController),
any<PackageDemotionInteractor>(),
eq(statusBarNotification.packageName),
- any<NotificationChannel>(),
- eq(entry),
+ eq(entry.ranking),
+ eq(statusBarNotification),
+ if (NotificationBundleUi.isEnabled) eq(null) else eq(entry),
+ if (NotificationBundleUi.isEnabled) eq(row.entryAdapter) else eq(null),
any<NotificationInfo.OnSettingsClickListener>(),
any<NotificationInfo.OnAppSettingsClickListener>(),
any<NotificationInfo.OnFeedbackClickListener>(),
any<UiEventLogger>(),
/* isDeviceProvisioned = */ eq(false),
/* isNonblockable = */ eq(false),
- /* isDismissable = */ eq(true),
+ /* isDismissable = */ eq(false),
/* wasShownHighPriority = */ eq(true),
eq(assistantFeedbackController),
eq(metricsLogger),
@@ -547,17 +570,21 @@
@Throws(Exception::class)
fun testInitializeNotificationInfoView_PassesAlongProvisionedState() {
val notificationInfoView: NotificationInfo = mock()
- val row = spy(helper.createRow())
+ val row = createTestNotificationRow()
NotificationEntryHelper.modifyRanking(row.entry)
.setUserSentiment(NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE)
.build()
- whenever(row.canViewBeDismissed()).thenReturn(true)
val statusBarNotification = row.entry.sbn
val entry = row.entry
whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
- gutsManager.initializeNotificationInfo(row, notificationInfoView)
+ gutsManager.initializeNotificationInfo(
+ row,
+ statusBarNotification,
+ entry.ranking,
+ notificationInfoView,
+ )
verify(notificationInfoView)
.bindNotification(
@@ -569,15 +596,17 @@
eq(channelEditorDialogController),
any<PackageDemotionInteractor>(),
eq(statusBarNotification.packageName),
- any<NotificationChannel>(),
- eq(entry),
+ eq(entry.ranking),
+ eq(statusBarNotification),
+ if (NotificationBundleUi.isEnabled) eq(null) else eq(entry),
+ if (NotificationBundleUi.isEnabled) eq(row.entryAdapter) else eq(null),
any<NotificationInfo.OnSettingsClickListener>(),
any<NotificationInfo.OnAppSettingsClickListener>(),
any<NotificationInfo.OnFeedbackClickListener>(),
any<UiEventLogger>(),
/* isDeviceProvisioned = */ eq(true),
/* isNonblockable = */ eq(false),
- /* isDismissable = */ eq(true),
+ /* isDismissable = */ eq(false),
/* wasShownHighPriority = */ eq(false),
eq(assistantFeedbackController),
eq(metricsLogger),
@@ -589,15 +618,19 @@
@Throws(Exception::class)
fun testInitializeNotificationInfoView_withInitialAction() {
val notificationInfoView: NotificationInfo = mock()
- val row = spy(helper.createRow())
+ val row = createTestNotificationRow()
NotificationEntryHelper.modifyRanking(row.entry)
.setUserSentiment(NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE)
.build()
- whenever(row.canViewBeDismissed()).thenReturn(true)
val statusBarNotification = row.entry.sbn
val entry = row.entry
- gutsManager.initializeNotificationInfo(row, notificationInfoView)
+ gutsManager.initializeNotificationInfo(
+ row,
+ statusBarNotification,
+ entry.ranking,
+ notificationInfoView,
+ )
verify(notificationInfoView)
.bindNotification(
@@ -609,15 +642,17 @@
eq(channelEditorDialogController),
any<PackageDemotionInteractor>(),
eq(statusBarNotification.packageName),
- any<NotificationChannel>(),
- eq(entry),
+ eq(entry.ranking),
+ eq(statusBarNotification),
+ if (NotificationBundleUi.isEnabled) eq(null) else eq(entry),
+ if (NotificationBundleUi.isEnabled) eq(row.entryAdapter) else eq(null),
any<NotificationInfo.OnSettingsClickListener>(),
any<NotificationInfo.OnAppSettingsClickListener>(),
any<NotificationInfo.OnFeedbackClickListener>(),
any<UiEventLogger>(),
/* isDeviceProvisioned = */ eq(false),
/* isNonblockable = */ eq(false),
- /* isDismissable = */ eq(true),
+ /* isDismissable = */ eq(false),
/* wasShownHighPriority = */ eq(false),
eq(assistantFeedbackController),
eq(metricsLogger),
@@ -639,6 +674,7 @@
NotificationEntryHelper.modifyRanking(row.entry)
.setChannel(testNotificationChannel)
.build()
+ row.entryAdapter = kosmos.entryAdapterFactory.create(row.entry)
return row
} catch (e: Exception) {
fail()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.kt
index 16663de..b2521b0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.kt
@@ -62,13 +62,16 @@
import com.android.systemui.res.R
import com.android.systemui.statusbar.RankingBuilder
import com.android.systemui.statusbar.notification.AssistantFeedbackController
+import com.android.systemui.statusbar.notification.collection.EntryAdapter
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.coordinator.mockVisualStabilityCoordinator
import com.android.systemui.statusbar.notification.promoted.domain.interactor.PackageDemotionInteractor
import com.android.systemui.statusbar.notification.row.icon.AppIconProvider
import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider
import com.android.systemui.statusbar.notification.row.icon.mockAppIconProvider
import com.android.systemui.statusbar.notification.row.icon.mockNotificationIconStyleProvider
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
import com.android.systemui.testKosmos
import com.android.telecom.telecomManager
import com.google.common.truth.Truth.assertThat
@@ -100,6 +103,7 @@
private lateinit var classifiedNotificationChannel: NotificationChannel
private lateinit var sbn: StatusBarNotification
private lateinit var entry: NotificationEntry
+ private lateinit var entryAdapter: EntryAdapter
private val mockPackageManager = kosmos.mockPackageManager
private val mockAppIconProvider = kosmos.mockAppIconProvider
@@ -189,7 +193,12 @@
null,
0,
)
- entry = NotificationEntryBuilder().setSbn(sbn).build()
+ entry =
+ NotificationEntryBuilder()
+ .setSbn(sbn)
+ .updateRanking { it.setChannel(notificationChannel) }
+ .build()
+ entryAdapter = kosmos.entryAdapterFactory.create(entry)
whenever(assistantFeedbackController.isFeedbackEnabled).thenReturn(false)
whenever(assistantFeedbackController.getInlineDescriptionResource(any()))
.thenReturn(R.string.notification_channel_summary_automatic)
@@ -263,7 +272,7 @@
.thenReturn(applicationInfo)
whenever(mockPackageManager.getApplicationLabel(any())).thenReturn("Other")
- val entry = NotificationEntryBuilder().setSbn(sbn).build()
+ val entry = NotificationEntryBuilder(entry).setSbn(sbn).build()
bindNotification(entry = entry)
val nameView = underTest.findViewById<TextView>(R.id.delegate_name)
assertThat(nameView.visibility).isEqualTo(VISIBLE)
@@ -304,6 +313,10 @@
@Test
fun testBindNotification_DefaultChannelDoesNotUseChannelName() {
+ entry =
+ NotificationEntryBuilder(entry)
+ .updateRanking { it.setChannel(defaultNotificationChannel) }
+ .build()
bindNotification(notificationChannel = defaultNotificationChannel)
val textView = underTest.findViewById<TextView>(R.id.channel_name)
assertThat(textView.visibility).isEqualTo(GONE)
@@ -320,6 +333,10 @@
)
)
.thenReturn(10)
+ entry =
+ NotificationEntryBuilder(entry)
+ .updateRanking { it.setChannel(notificationChannel) }
+ .build()
bindNotification(notificationChannel = defaultNotificationChannel)
val textView = underTest.findViewById<TextView>(R.id.channel_name)
assertThat(textView.visibility).isEqualTo(VISIBLE)
@@ -747,7 +764,13 @@
underTest.findViewById<View>(R.id.done).performClick()
underTest.handleCloseControls(true, false)
- verify(onUserInteractionCallback).onImportanceChanged(entry)
+ if (NotificationBundleUi.isEnabled) {
+ verify(kosmos.mockVisualStabilityCoordinator)
+ .temporarilyAllowSectionChanges(eq(entry), any())
+ } else {
+ verify(onUserInteractionCallback).onImportanceChanged(entry)
+ }
+
assertThat(underTest.shouldBeSavedOnClose()).isFalse()
}
@@ -866,7 +889,12 @@
@EnableFlags(Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
@Throws(RemoteException::class)
fun testBindNotification_SetsFeedbackLink_isReservedChannel() {
- entry.setRanking(RankingBuilder(entry.ranking).setSummarization("something").build())
+ entry.setRanking(
+ RankingBuilder(entry.ranking)
+ .setSummarization("something")
+ .setChannel(classifiedNotificationChannel)
+ .build()
+ )
val latch = CountDownLatch(1)
bindNotification(
notificationChannel = classifiedNotificationChannel,
@@ -927,6 +955,7 @@
pkg: String = TEST_PACKAGE_NAME,
notificationChannel: NotificationChannel = this.notificationChannel,
entry: NotificationEntry = this.entry,
+ entryAdapter: EntryAdapter = this.entryAdapter,
onSettingsClick: NotificationInfo.OnSettingsClickListener? = null,
onAppSettingsClick: NotificationInfo.OnAppSettingsClickListener? = null,
onFeedbackClickListener: NotificationInfo.OnFeedbackClickListener? = null,
@@ -948,8 +977,10 @@
channelEditorDialogController,
packageDemotionInteractor,
pkg,
- notificationChannel,
+ entry.ranking,
+ entry.sbn,
entry,
+ entryAdapter,
onSettingsClick,
onAppSettingsClick,
onFeedbackClickListener,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index e6b2c25..bda2ba7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -81,6 +81,7 @@
import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
@@ -746,7 +747,9 @@
mock(PeopleNotificationIdentifier.class),
mock(NotificationIconStyleProvider.class),
mock(VisualStabilityCoordinator.class),
- mock(NotificationActionClickManager.class)
+ mock(NotificationActionClickManager.class),
+ mock(HighPriorityProvider.class),
+ mock(HeadsUpManager.class)
).create(entry);
row.initialize(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
index 57b0f3f..0eb6016 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
@@ -40,6 +40,7 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.UserHandle;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.testing.TestableLooper;
import android.text.SpannableString;
@@ -81,7 +82,6 @@
private TestableLooper mTestableLooper;
private PartialConversationInfo mInfo;
private NotificationChannel mNotificationChannel;
- private NotificationChannel mDefaultNotificationChannel;
private StatusBarNotification mSbn;
private NotificationEntry mEntry;
@@ -141,15 +141,14 @@
// Some test channels.
mNotificationChannel = new NotificationChannel(
TEST_CHANNEL, TEST_CHANNEL_NAME, IMPORTANCE_LOW);
- mDefaultNotificationChannel = new NotificationChannel(
- NotificationChannel.DEFAULT_CHANNEL_ID, TEST_CHANNEL_NAME,
- IMPORTANCE_LOW);
Notification n = new Notification.Builder(mContext, mNotificationChannel.getId())
.setContentTitle(new SpannableString("title"))
.build();
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
n, UserHandle.CURRENT, null, 0);
- mEntry = new NotificationEntryBuilder().setSbn(mSbn).build();
+ mEntry = new NotificationEntryBuilder().setSbn(mSbn).updateRanking(rankingBuilder -> {
+ rankingBuilder.setChannel(mNotificationChannel);
+ }).build();
}
@Test
@@ -160,8 +159,8 @@
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
+ mEntry.getRanking(),
+ mSbn,
null,
true,
false);
@@ -178,8 +177,8 @@
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
+ mEntry.getRanking(),
+ mSbn,
null,
true,
false);
@@ -194,8 +193,8 @@
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
+ mEntry.getRanking(),
+ mSbn,
null,
true,
false);
@@ -219,8 +218,8 @@
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- entry,
+ mEntry.getRanking(),
+ mSbn,
null,
true,
false);
@@ -237,8 +236,8 @@
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
+ mEntry.getRanking(),
+ mSbn,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
latch.countDown();
@@ -260,8 +259,8 @@
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
+ mEntry.getRanking(),
+ mSbn,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
latch.countDown();
@@ -282,8 +281,8 @@
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
+ mEntry.getRanking(),
+ mSbn,
null,
true,
false);
@@ -298,8 +297,8 @@
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
+ mEntry.getRanking(),
+ mSbn,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
},
@@ -316,8 +315,8 @@
mMockINotificationManager,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
+ mEntry.getRanking(),
+ mSbn,
null,
true,
true);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfoTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfoTest.java
index 209dfb2d..9b86412 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfoTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfoTest.java
@@ -31,6 +31,7 @@
import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.platform.test.annotations.EnableFlags;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.telecom.TelecomManager;
import android.testing.TestableLooper;
@@ -46,9 +47,16 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
+import com.android.systemui.statusbar.notification.NotificationActivityStarter;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
import com.android.systemui.statusbar.notification.promoted.domain.interactor.PackageDemotionInteractor;
+import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.icon.AppIconProvider;
import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider;
@@ -74,6 +82,8 @@
private NotificationChannel mNotificationChannel;
private StatusBarNotification mSbn;
private NotificationEntry mEntry;
+ private NotificationListenerService.Ranking mRanking;
+ private EntryAdapter mEntryAdapter;
private UiEventLoggerFake mUiEventLogger = new UiEventLoggerFake();
@Rule
@@ -110,7 +120,20 @@
notification.extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, applicationInfo);
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
notification, UserHandle.getUserHandleForUid(TEST_UID), null, 0);
- mEntry = new NotificationEntryBuilder().setSbn(mSbn).build();
+ mEntry = new NotificationEntryBuilder().setSbn(mSbn).updateRanking(rankingBuilder -> {
+ rankingBuilder.setChannel(mNotificationChannel);
+ }).build();
+ mEntryAdapter = new EntryAdapterFactoryImpl(
+ mock(NotificationActivityStarter.class),
+ mock(MetricsLogger.class),
+ mock(PeopleNotificationIdentifier.class),
+ mock(NotificationIconStyleProvider.class),
+ mock(VisualStabilityCoordinator.class),
+ mock(NotificationActionClickManager.class),
+ mock(HighPriorityProvider.class),
+ mock(HeadsUpManager.class)
+ ).create(mEntry);
+ mRanking = mEntry.getRanking();
when(mAssistantFeedbackController.isFeedbackEnabled()).thenReturn(false);
mTestableLooper = TestableLooper.get(this);
@@ -143,8 +166,10 @@
mChannelEditorDialogController,
mPackageDemotionInteractor,
TEST_PACKAGE_NAME,
- mNotificationChannel,
+ mRanking,
+ mSbn,
mEntry,
+ mEntryAdapter,
null,
null,
null,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
index 19e9838..533b7a6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
@@ -23,6 +24,7 @@
import android.app.ActivityManager;
import android.app.Notification;
+import android.app.NotificationChannel;
import android.content.Context;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
@@ -85,6 +87,33 @@
return entry;
}
+ public NotificationEntry createClassifiedEntry(boolean isSummary,
+ int groupAlertBehavior, String channelId) {
+
+ Notification notif = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+ .setContentTitle("Title")
+ .setSmallIcon(R.drawable.ic_person)
+ .setGroupAlertBehavior(groupAlertBehavior)
+ .setGroupSummary(isSummary)
+ .setGroup(TEST_GROUP_ID)
+ .build();
+
+ NotificationChannel channel = new NotificationChannel(channelId, channelId, IMPORTANCE_LOW);
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_NAME)
+ .setOpPkg(TEST_PACKAGE_NAME)
+ .setId(mId++)
+ .setNotification(notif)
+ .updateRanking((rankingBuilder -> rankingBuilder.setChannel(channel)))
+ .setUser(new UserHandle(ActivityManager.getCurrentUser()))
+ .build();
+
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+ entry.setRow(row);
+ when(row.getEntryLegacy()).thenReturn(entry);
+ return entry;
+ }
+
public NotificationEntry createEntry(int id, String tag, boolean isSummary,
int groupAlertBehavior) {
Notification notif = new Notification.Builder(mContext, TEST_CHANNEL_ID)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairosAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairosAdapterTest.kt
new file mode 100644
index 0000000..3cf787d
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairosAdapterTest.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.pipeline.mobile.data.repository.prod
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.activated
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.launchKairosNetwork
+import com.android.systemui.kairos.stateOf
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfig
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runCurrent
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+
+@OptIn(ExperimentalKairosApi::class, ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CarrierMergedConnectionRepositoryKairosAdapterTest :
+ CarrierMergedConnectionRepositoryTestBase() {
+
+ var job: Job? = null
+ val kairosNetwork = testScope.backgroundScope.launchKairosNetwork()
+
+ override fun recreateRepo(): MobileConnectionRepositoryKairosAdapter {
+ lateinit var adapter: MobileConnectionRepositoryKairosAdapter
+ job?.cancel()
+ Mockito.clearInvocations(telephonyManager)
+ job =
+ testScope.backgroundScope.launch {
+ kairosNetwork.activateSpec {
+ val repo = activated {
+ CarrierMergedConnectionRepositoryKairos(
+ SUB_ID,
+ logger,
+ telephonyManager,
+ wifiRepository,
+ isInEcmMode = stateOf(false),
+ )
+ }
+ adapter =
+ MobileConnectionRepositoryKairosAdapter(
+ repo,
+ SystemUiCarrierConfig(SUB_ID, testCarrierConfig()),
+ )
+ Unit
+ }
+ }
+ testScope.runCurrent() // ensure the lateinit is set
+ return adapter
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
index 8e55f2e..8a6829c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
@@ -43,16 +44,30 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
-class CarrierMergedConnectionRepositoryTest : SysuiTestCase() {
+class CarrierMergedConnectionRepositoryTest : CarrierMergedConnectionRepositoryTestBase() {
+ override fun recreateRepo() =
+ CarrierMergedConnectionRepository(
+ SUB_ID,
+ logger,
+ telephonyManager,
+ testScope.backgroundScope.coroutineContext,
+ testScope.backgroundScope,
+ wifiRepository,
+ )
+}
- private lateinit var underTest: CarrierMergedConnectionRepository
+abstract class CarrierMergedConnectionRepositoryTestBase : SysuiTestCase() {
- private lateinit var wifiRepository: FakeWifiRepository
- @Mock private lateinit var logger: TableLogBuffer
- @Mock private lateinit var telephonyManager: TelephonyManager
+ protected lateinit var underTest: MobileConnectionRepository
- private val testDispatcher = UnconfinedTestDispatcher()
- private val testScope = TestScope(testDispatcher)
+ protected lateinit var wifiRepository: FakeWifiRepository
+ @Mock protected lateinit var logger: TableLogBuffer
+ @Mock protected lateinit var telephonyManager: TelephonyManager
+
+ protected val testDispatcher = UnconfinedTestDispatcher()
+ protected val testScope = TestScope(testDispatcher)
+
+ abstract fun recreateRepo(): MobileConnectionRepository
@Before
fun setUp() {
@@ -62,15 +77,7 @@
wifiRepository = FakeWifiRepository()
- underTest =
- CarrierMergedConnectionRepository(
- SUB_ID,
- logger,
- telephonyManager,
- testScope.backgroundScope.coroutineContext,
- testScope.backgroundScope,
- wifiRepository,
- )
+ underTest = recreateRepo()
}
@Test
@@ -121,10 +128,7 @@
wifiRepository.setIsWifiDefault(true)
wifiRepository.setWifiNetwork(
- WifiNetworkModel.CarrierMerged.of(
- subscriptionId = SUB_ID,
- level = 3,
- )
+ WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3)
)
assertThat(latest).isEqualTo(3)
@@ -141,26 +145,17 @@
wifiRepository.setIsWifiEnabled(true)
wifiRepository.setIsWifiDefault(true)
wifiRepository.setWifiNetwork(
- WifiNetworkModel.CarrierMerged.of(
- subscriptionId = SUB_ID,
- level = 3,
- )
+ WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3)
)
wifiRepository.setWifiActivity(
- DataActivityModel(
- hasActivityIn = true,
- hasActivityOut = false,
- )
+ DataActivityModel(hasActivityIn = true, hasActivityOut = false)
)
assertThat(latest!!.hasActivityIn).isTrue()
assertThat(latest!!.hasActivityOut).isFalse()
wifiRepository.setWifiActivity(
- DataActivityModel(
- hasActivityIn = false,
- hasActivityOut = true,
- )
+ DataActivityModel(hasActivityIn = false, hasActivityOut = true)
)
assertThat(latest!!.hasActivityIn).isFalse()
@@ -178,10 +173,7 @@
val typeJob = underTest.resolvedNetworkType.onEach { latestType = it }.launchIn(this)
wifiRepository.setWifiNetwork(
- WifiNetworkModel.CarrierMerged.of(
- subscriptionId = SUB_ID + 10,
- level = 3,
- )
+ WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID + 10, level = 3)
)
assertThat(latestLevel).isNotEqualTo(3)
@@ -199,10 +191,7 @@
val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this)
wifiRepository.setWifiNetwork(
- WifiNetworkModel.CarrierMerged.of(
- subscriptionId = SUB_ID,
- level = 3,
- )
+ WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3)
)
wifiRepository.setIsWifiEnabled(false)
@@ -219,10 +208,7 @@
val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this)
wifiRepository.setWifiNetwork(
- WifiNetworkModel.CarrierMerged.of(
- subscriptionId = SUB_ID,
- level = 3,
- )
+ WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3)
)
wifiRepository.setIsWifiDefault(false)
@@ -280,6 +266,7 @@
fun networkName_usesSimOperatorNameAsInitial() =
testScope.runTest {
whenever(telephonyManager.simOperatorName).thenReturn("Test SIM name")
+ underTest = recreateRepo()
var latest: NetworkNameModel? = null
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
@@ -293,6 +280,10 @@
fun networkName_updatesOnNetworkUpdate() =
testScope.runTest {
whenever(telephonyManager.simOperatorName).thenReturn("Test SIM name")
+ underTest = recreateRepo()
+
+ wifiRepository.setIsWifiEnabled(true)
+ wifiRepository.setIsWifiDefault(true)
var latest: NetworkNameModel? = null
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
@@ -301,10 +292,7 @@
whenever(telephonyManager.simOperatorName).thenReturn("New SIM name")
wifiRepository.setWifiNetwork(
- WifiNetworkModel.CarrierMerged.of(
- subscriptionId = SUB_ID,
- level = 3,
- )
+ WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3)
)
assertThat(latest).isEqualTo(NetworkNameModel.SimDerived("New SIM name"))
@@ -320,7 +308,7 @@
assertThat(latest).isTrue()
}
- private companion object {
+ companion object {
const val SUB_ID = 123
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosAdapterTest.kt
new file mode 100644
index 0000000..e72d0c2
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosAdapterTest.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.pipeline.mobile.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.MobileIconCarrierIdOverrides
+import com.android.systemui.activated
+import com.android.systemui.kairos.BuildScope
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.Incremental
+import com.android.systemui.kairos.State
+import com.android.systemui.kairos.asIncremental
+import com.android.systemui.kairos.buildSpec
+import com.android.systemui.kairos.combine
+import com.android.systemui.kairos.launchKairosNetwork
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorKairosAdapterTest.Companion.wrapRepo
+import com.android.systemui.util.mockito.mock
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runCurrent
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalKairosApi::class, ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MobileIconInteractorKairosAdapterTest : MobileIconInteractorTestBase() {
+
+ var job: Job? = null
+ val kairosNetwork = testScope.backgroundScope.launchKairosNetwork()
+
+ override fun createInteractor(overrides: MobileIconCarrierIdOverrides): MobileIconInteractor {
+ lateinit var result: MobileIconInteractor
+ job?.cancel()
+ job =
+ testScope.backgroundScope.launch {
+ kairosNetwork.activateSpec {
+ val wrapped = wrap(mobileIconsInteractor)
+ result =
+ MobileIconInteractorKairosAdapter(
+ kairosImpl =
+ activated {
+ MobileIconInteractorKairosImpl(
+ defaultSubscriptionHasDataEnabled =
+ wrapped.activeDataConnectionHasDataEnabled,
+ alwaysShowDataRatIcon = wrapped.alwaysShowDataRatIcon,
+ alwaysUseCdmaLevel = wrapped.alwaysUseCdmaLevel,
+ isSingleCarrier = wrapped.isSingleCarrier,
+ mobileIsDefault = wrapped.mobileIsDefault,
+ defaultMobileIconMapping = wrapped.defaultMobileIconMapping,
+ defaultMobileIconGroup = wrapped.defaultMobileIconGroup,
+ isDefaultConnectionFailed =
+ wrapped.isDefaultConnectionFailed,
+ isForceHidden = wrapped.isForceHidden,
+ connectionRepository = wrapRepo(connectionRepository),
+ context = context,
+ carrierIdOverrides = overrides,
+ )
+ }
+ )
+ Unit
+ }
+ }
+ testScope.runCurrent() // ensure the lateinit is set
+ return result
+ }
+
+ /** Allows us to wrap a (likely fake) MobileIconsInteractor into a Kairos version. */
+ private fun BuildScope.wrap(interactor: MobileIconsInteractor): MobileIconsInteractorKairos {
+ val filteredSubscriptions = interactor.filteredSubscriptions.toState(emptyList())
+ val icons = interactor.icons.toState()
+ return InteractorWrapper(
+ mobileIsDefault = interactor.mobileIsDefault.toState(),
+ filteredSubscriptions = filteredSubscriptions,
+ icons =
+ combine(filteredSubscriptions, icons) { subs, icons ->
+ subs.zip(icons).associate { (subModel, icon) ->
+ subModel.subscriptionId to buildSpec { wrap(icon) }
+ }
+ }
+ .asIncremental()
+ .applyLatestSpecForKey(),
+ isStackable = interactor.isStackable.toState(),
+ activeDataConnectionHasDataEnabled =
+ interactor.activeDataConnectionHasDataEnabled.toState(),
+ activeDataIconInteractor =
+ interactor.activeDataIconInteractor.toState().mapLatestBuild {
+ it?.let { wrap(it) }
+ },
+ alwaysShowDataRatIcon = interactor.alwaysShowDataRatIcon.toState(),
+ alwaysUseCdmaLevel = interactor.alwaysUseCdmaLevel.toState(),
+ isSingleCarrier = interactor.isSingleCarrier.toState(),
+ defaultMobileIconMapping = interactor.defaultMobileIconMapping.toState(),
+ defaultMobileIconGroup = interactor.defaultMobileIconGroup.toState(),
+ isDefaultConnectionFailed = interactor.isDefaultConnectionFailed.toState(),
+ isUserSetUp = interactor.isUserSetUp.toState(),
+ isForceHidden = interactor.isForceHidden.toState(false),
+ isDeviceInEmergencyCallsOnlyMode =
+ interactor.isDeviceInEmergencyCallsOnlyMode.toState(false),
+ )
+ }
+
+ private fun BuildScope.wrap(interactor: MobileIconInteractor): MobileIconInteractorKairos =
+ // unused in tests
+ mock()
+
+ private class InteractorWrapper(
+ override val mobileIsDefault: State<Boolean>,
+ override val filteredSubscriptions: State<List<SubscriptionModel>>,
+ override val icons: Incremental<Int, MobileIconInteractorKairos>,
+ override val isStackable: State<Boolean>,
+ override val activeDataConnectionHasDataEnabled: State<Boolean>,
+ override val activeDataIconInteractor: State<MobileIconInteractorKairos?>,
+ override val alwaysShowDataRatIcon: State<Boolean>,
+ override val alwaysUseCdmaLevel: State<Boolean>,
+ override val isSingleCarrier: State<Boolean>,
+ override val defaultMobileIconMapping: State<Map<String, SignalIcon.MobileIconGroup>>,
+ override val defaultMobileIconGroup: State<SignalIcon.MobileIconGroup>,
+ override val isDefaultConnectionFailed: State<Boolean>,
+ override val isUserSetUp: State<Boolean>,
+ override val isForceHidden: State<Boolean>,
+ override val isDeviceInEmergencyCallsOnlyMode: State<Boolean>,
+ ) : MobileIconsInteractorKairos
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index 8c70da7..974a475 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -22,6 +22,7 @@
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.internal.telephony.flags.Flags
import com.android.settingslib.mobile.MobileIconCarrierIdOverrides
import com.android.settingslib.mobile.MobileIconCarrierIdOverridesImpl
import com.android.settingslib.mobile.TelephonyIcons
@@ -58,21 +59,40 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
-class MobileIconInteractorTest : SysuiTestCase() {
- private val kosmos = testKosmos()
+class MobileIconInteractorTest : MobileIconInteractorTestBase() {
+ override fun createInteractor(overrides: MobileIconCarrierIdOverrides) =
+ MobileIconInteractorImpl(
+ testScope.backgroundScope,
+ mobileIconsInteractor.activeDataConnectionHasDataEnabled,
+ mobileIconsInteractor.alwaysShowDataRatIcon,
+ mobileIconsInteractor.alwaysUseCdmaLevel,
+ mobileIconsInteractor.isSingleCarrier,
+ mobileIconsInteractor.mobileIsDefault,
+ mobileIconsInteractor.defaultMobileIconMapping,
+ mobileIconsInteractor.defaultMobileIconGroup,
+ mobileIconsInteractor.isDefaultConnectionFailed,
+ mobileIconsInteractor.isForceHidden,
+ connectionRepository,
+ context,
+ overrides,
+ )
+}
- private lateinit var underTest: MobileIconInteractor
- private val mobileMappingsProxy = FakeMobileMappingsProxy()
- private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy, mock())
+abstract class MobileIconInteractorTestBase : SysuiTestCase() {
+ protected val kosmos = testKosmos()
- private val connectionRepository =
+ protected lateinit var underTest: MobileIconInteractor
+ protected val mobileMappingsProxy = FakeMobileMappingsProxy()
+ protected val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy, mock())
+
+ protected val connectionRepository =
FakeMobileConnectionRepository(
SUB_1_ID,
logcatTableLogBuffer(kosmos, "MobileIconInteractorTest"),
)
- private val testDispatcher = UnconfinedTestDispatcher()
- private val testScope = TestScope(testDispatcher)
+ protected val testDispatcher = UnconfinedTestDispatcher()
+ protected val testScope = TestScope(testDispatcher)
@Before
fun setUp() {
@@ -835,24 +855,9 @@
assertThat(latest!!.level).isEqualTo(0)
}
- private fun createInteractor(
+ abstract fun createInteractor(
overrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl()
- ) =
- MobileIconInteractorImpl(
- testScope.backgroundScope,
- mobileIconsInteractor.activeDataConnectionHasDataEnabled,
- mobileIconsInteractor.alwaysShowDataRatIcon,
- mobileIconsInteractor.alwaysUseCdmaLevel,
- mobileIconsInteractor.isSingleCarrier,
- mobileIconsInteractor.mobileIsDefault,
- mobileIconsInteractor.defaultMobileIconMapping,
- mobileIconsInteractor.defaultMobileIconGroup,
- mobileIconsInteractor.isDefaultConnectionFailed,
- mobileIconsInteractor.isForceHidden,
- connectionRepository,
- context,
- overrides,
- )
+ ): MobileIconInteractor
companion object {
private const val GSM_LEVEL = 1
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairosAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairosAdapterTest.kt
new file mode 100644
index 0000000..787731e
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairosAdapterTest.kt
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.pipeline.mobile.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.MobileMappings
+import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.KairosBuilder
+import com.android.systemui.flags.featureFlagsClassic
+import com.android.systemui.kairos.BuildScope
+import com.android.systemui.kairos.Events
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.Incremental
+import com.android.systemui.kairos.State
+import com.android.systemui.kairos.activateKairosActivatable
+import com.android.systemui.kairos.asIncremental
+import com.android.systemui.kairos.buildSpec
+import com.android.systemui.kairos.kairos
+import com.android.systemui.kairos.map
+import com.android.systemui.kairos.mapValues
+import com.android.systemui.kairos.stateOf
+import com.android.systemui.kairosBuilder
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.runCurrent
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.tableLogBufferFactory
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.shared.data.repository.connectivityRepository
+import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+
+@OptIn(ExperimentalKairosApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MobileIconsInteractorKairosAdapterTest : MobileIconsInteractorTestBase() {
+ override fun Kosmos.createInteractor(): MobileIconsInteractor {
+ val userSetupRepo = FakeUserSetupRepository()
+ val repoK =
+ MobileConnectionsRepoWrapper(connectionsRepository).also {
+ activateKairosActivatable(it)
+ }
+ val kairosInteractor =
+ MobileIconsInteractorKairosImpl(
+ mobileConnectionsRepo = repoK,
+ carrierConfigTracker = carrierConfigTracker,
+ tableLogger = mock(),
+ connectivityRepository = connectivityRepository,
+ userSetupRepo = userSetupRepo,
+ context = context,
+ featureFlagsClassic = featureFlagsClassic,
+ )
+ .also { activateKairosActivatable(it) }
+ return MobileIconsInteractorKairosAdapter(
+ kairosInteractor = kairosInteractor,
+ repo = connectionsRepository,
+ repoK = repoK,
+ kairosNetwork = kairos,
+ scope = applicationCoroutineScope,
+ context = context,
+ mobileMappingsProxy = mobileMappingsProxy,
+ userSetupRepo = userSetupRepo,
+ logFactory = tableLogBufferFactory,
+ )
+ .also {
+ activateKairosActivatable(it)
+ runCurrent()
+ }
+ }
+
+ /** Allows us to wrap a (likely fake) MobileConnectionsRepository into a Kairos version. */
+ private class MobileConnectionsRepoWrapper(val unwrapped: MobileConnectionsRepository) :
+ MobileConnectionsRepositoryKairos, KairosBuilder by kairosBuilder() {
+
+ override val mobileConnectionsBySubId: Incremental<Int, MobileConnectionRepositoryKairos> =
+ buildIncremental {
+ unwrapped.subscriptions
+ .toState()
+ .map { it.associate { it.subscriptionId to Unit } }
+ .asIncremental()
+ .mapValues { (subId, _) ->
+ buildSpec { wrapRepo(unwrapped.getRepoForSubId(subId)) }
+ }
+ .applyLatestSpecForKey()
+ }
+ override val subscriptions: State<Collection<SubscriptionModel>> = buildState {
+ unwrapped.subscriptions.toState()
+ }
+ override val activeMobileDataSubscriptionId: State<Int?> = buildState {
+ unwrapped.activeMobileDataSubscriptionId.toState()
+ }
+ override val activeMobileDataRepository: State<MobileConnectionRepositoryKairos?> =
+ buildState {
+ unwrapped.activeMobileDataRepository.toState().mapLatestBuild {
+ it?.let { wrapRepo(it) }
+ }
+ }
+ override val activeSubChangedInGroupEvent: Events<Unit> = buildEvents {
+ unwrapped.activeSubChangedInGroupEvent.toEvents()
+ }
+ override val defaultDataSubId: State<Int?> = buildState {
+ unwrapped.defaultDataSubId.toState()
+ }
+ override val mobileIsDefault: State<Boolean> = buildState {
+ unwrapped.mobileIsDefault.toState()
+ }
+ override val hasCarrierMergedConnection: State<Boolean> = buildState {
+ unwrapped.hasCarrierMergedConnection.toState(false)
+ }
+ override val defaultConnectionIsValidated: State<Boolean> = buildState {
+ unwrapped.defaultConnectionIsValidated.toState()
+ }
+ override val defaultDataSubRatConfig: State<MobileMappings.Config> = buildState {
+ unwrapped.defaultDataSubRatConfig.toState()
+ }
+ override val defaultMobileIconMapping: State<Map<String, SignalIcon.MobileIconGroup>> =
+ buildState {
+ unwrapped.defaultMobileIconMapping.toState(emptyMap())
+ }
+ override val defaultMobileIconGroup: State<SignalIcon.MobileIconGroup> = buildState {
+ unwrapped.defaultMobileIconGroup.toState(TelephonyIcons.THREE_G)
+ }
+ override val isDeviceEmergencyCallCapable: State<Boolean> = buildState {
+ unwrapped.isDeviceEmergencyCallCapable.toState()
+ }
+ override val isAnySimSecure: State<Boolean> = buildState {
+ unwrapped.isDeviceEmergencyCallCapable.toState()
+ }
+ override val isInEcmMode: State<Boolean> = stateOf(false)
+ }
+
+ private class MobileConnectionRepoWrapper(
+ override val subId: Int,
+ override val carrierId: State<Int>,
+ override val inflateSignalStrength: State<Boolean>,
+ override val allowNetworkSliceIndicator: State<Boolean>,
+ override val tableLogBuffer: TableLogBuffer,
+ override val isEmergencyOnly: State<Boolean>,
+ override val isRoaming: State<Boolean>,
+ override val operatorAlphaShort: State<String?>,
+ override val isInService: State<Boolean>,
+ override val isNonTerrestrial: State<Boolean>,
+ override val isGsm: State<Boolean>,
+ override val cdmaLevel: State<Int>,
+ override val primaryLevel: State<Int>,
+ override val satelliteLevel: State<Int>,
+ override val dataConnectionState: State<DataConnectionState>,
+ override val dataActivityDirection: State<DataActivityModel>,
+ override val carrierNetworkChangeActive: State<Boolean>,
+ override val resolvedNetworkType: State<ResolvedNetworkType>,
+ override val numberOfLevels: State<Int>,
+ override val dataEnabled: State<Boolean>,
+ override val cdmaRoaming: State<Boolean>,
+ override val networkName: State<NetworkNameModel>,
+ override val carrierName: State<NetworkNameModel>,
+ override val isAllowedDuringAirplaneMode: State<Boolean>,
+ override val hasPrioritizedNetworkCapabilities: State<Boolean>,
+ override val isInEcmMode: State<Boolean>,
+ ) : MobileConnectionRepositoryKairos
+
+ companion object {
+ /** Allows us to wrap a (likely fake) MobileConnectionRepository into a Kairos version. */
+ fun BuildScope.wrapRepo(
+ conn: MobileConnectionRepository
+ ): MobileConnectionRepositoryKairos =
+ with(conn) {
+ MobileConnectionRepoWrapper(
+ subId = subId,
+ carrierId = carrierId.toState(),
+ inflateSignalStrength = inflateSignalStrength.toState(),
+ allowNetworkSliceIndicator = allowNetworkSliceIndicator.toState(),
+ tableLogBuffer = tableLogBuffer,
+ isEmergencyOnly = isEmergencyOnly.toState(),
+ isRoaming = isRoaming.toState(),
+ operatorAlphaShort = operatorAlphaShort.toState(),
+ isInService = isInService.toState(),
+ isNonTerrestrial = isNonTerrestrial.toState(),
+ isGsm = isGsm.toState(),
+ cdmaLevel = cdmaLevel.toState(),
+ primaryLevel = primaryLevel.toState(),
+ satelliteLevel = satelliteLevel.toState(),
+ dataConnectionState = dataConnectionState.toState(),
+ dataActivityDirection = dataActivityDirection.toState(),
+ carrierNetworkChangeActive = carrierNetworkChangeActive.toState(),
+ resolvedNetworkType = resolvedNetworkType.toState(),
+ numberOfLevels = numberOfLevels.toState(),
+ dataEnabled = dataEnabled.toState(),
+ cdmaRoaming = cdmaRoaming.toState(),
+ networkName = networkName.toState(),
+ carrierName = carrierName.toState(),
+ isAllowedDuringAirplaneMode = isAllowedDuringAirplaneMode.toState(),
+ hasPrioritizedNetworkCapabilities = hasPrioritizedNetworkCapabilities.toState(),
+ isInEcmMode = stateOf(false),
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index 9e914ad..356e567 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -58,8 +58,35 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
-class MobileIconsInteractorTest : SysuiTestCase() {
- private val kosmos by lazy {
+class MobileIconsInteractorTest : MobileIconsInteractorTestBase() {
+ override fun Kosmos.createInteractor() =
+ MobileIconsInteractorImpl(
+ mobileConnectionsRepository,
+ carrierConfigTracker,
+ tableLogger = mock(),
+ connectivityRepository,
+ FakeUserSetupRepository(),
+ testScope.backgroundScope,
+ context,
+ featureFlagsClassic,
+ )
+
+ @Test
+ fun iconInteractor_cachedPerSubId() =
+ kosmos.runTest {
+ connectionsRepository.setSubscriptions(listOf(SUB_1))
+ runCurrent()
+
+ val interactor1 = underTest.getMobileConnectionInteractorForSubId(SUB_1_ID)
+ val interactor2 = underTest.getMobileConnectionInteractorForSubId(SUB_1_ID)
+
+ assertThat(interactor1).isNotNull()
+ assertThat(interactor1).isSameInstanceAs(interactor2)
+ }
+}
+
+abstract class MobileIconsInteractorTestBase : SysuiTestCase() {
+ protected val kosmos by lazy {
testKosmos().apply {
mobileConnectionsRepositoryLogbufferName = "MobileIconsInteractorTest"
mobileConnectionsRepository.fake.run {
@@ -78,22 +105,13 @@
}
// shortcut rename
- private val Kosmos.connectionsRepository by Fixture { mobileConnectionsRepository.fake }
+ protected val Kosmos.connectionsRepository by Fixture { mobileConnectionsRepository.fake }
- private val Kosmos.carrierConfigTracker by Fixture { mock<CarrierConfigTracker>() }
+ protected val Kosmos.carrierConfigTracker by Fixture { mock<CarrierConfigTracker>() }
- private val Kosmos.underTest by Fixture {
- MobileIconsInteractorImpl(
- mobileConnectionsRepository,
- carrierConfigTracker,
- tableLogger = mock(),
- connectivityRepository,
- FakeUserSetupRepository(),
- testScope.backgroundScope,
- context,
- featureFlagsClassic,
- )
- }
+ protected val Kosmos.underTest by Fixture { createInteractor() }
+
+ abstract fun Kosmos.createInteractor(): MobileIconsInteractor
@Test
fun filteredSubscriptions_default() =
@@ -744,12 +762,15 @@
val latest by collectLastValue(underTest.mobileIsDefault)
connectionsRepository.mobileIsDefault.value = true
+ runCurrent()
assertThat(latest).isTrue()
connectionsRepository.mobileIsDefault.value = false
+ runCurrent()
assertThat(latest).isFalse()
connectionsRepository.hasCarrierMergedConnection.value = true
+ runCurrent()
assertThat(latest).isTrue()
}
@@ -874,16 +895,6 @@
}
@Test
- fun iconInteractor_cachedPerSubId() =
- kosmos.runTest {
- val interactor1 = underTest.getMobileConnectionInteractorForSubId(SUB_1_ID)
- val interactor2 = underTest.getMobileConnectionInteractorForSubId(SUB_1_ID)
-
- assertThat(interactor1).isNotNull()
- assertThat(interactor1).isSameInstanceAs(interactor2)
- }
-
- @Test
fun deviceBasedEmergencyMode_emergencyCallsOnly_followsDeviceServiceStateFromRepo() =
kosmos.runTest {
val latest by collectLastValue(underTest.isDeviceInEmergencyCallsOnlyMode)
@@ -1007,8 +1018,8 @@
companion object {
- private const val SUB_1_ID = 1
- private val SUB_1 =
+ const val SUB_1_ID = 1
+ val SUB_1 =
SubscriptionModel(
subscriptionId = SUB_1_ID,
carrierName = "Carrier $SUB_1_ID",
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModelTest.kt
new file mode 100644
index 0000000..0847281
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModelTest.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.volume.dialog.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.data.repository.accessibilityRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.android.systemui.volume.Events
+import com.android.systemui.volume.dialog.data.repository.volumeDialogVisibilityRepository
+import com.android.systemui.volume.dialog.domain.interactor.volumeDialogVisibilityInteractor
+import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
+import com.google.common.truth.Truth.assertThat
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.test.advanceTimeBy
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class VolumeDialogPluginViewModelTest : SysuiTestCase() {
+
+ private val kosmos: Kosmos = testKosmos()
+
+ private val underTest: VolumeDialogPluginViewModel by lazy {
+ kosmos.volumeDialogPluginViewModel
+ }
+
+ @Before
+ fun setUp() =
+ with(kosmos) {
+ volumeDialogVisibilityRepository.updateVisibility {
+ VolumeDialogVisibilityModel.Visible(Events.SHOW_REASON_VOLUME_CHANGED, false, 0)
+ }
+ }
+
+ @Test
+ fun safetyWarningAppears_timeoutReset() =
+ kosmos.runTest {
+ accessibilityRepository.setRecommendedTimeout(3.seconds)
+ val visibility by collectLastValue(volumeDialogVisibilityInteractor.dialogVisibility)
+ testScope.advanceTimeBy(2.seconds)
+ assertThat(visibility).isInstanceOf(VolumeDialogVisibilityModel.Visible::class.java)
+
+ underTest.onSafetyWarningDialogShown()
+ testScope.advanceTimeBy(2.seconds)
+ assertThat(visibility).isInstanceOf(VolumeDialogVisibilityModel.Visible::class.java)
+ }
+
+ @Test
+ fun csdWarningAppears_timeoutReset() =
+ kosmos.runTest {
+ accessibilityRepository.setRecommendedTimeout(3.seconds)
+ val visibility by collectLastValue(volumeDialogVisibilityInteractor.dialogVisibility)
+ testScope.advanceTimeBy(2.seconds)
+ assertThat(visibility).isInstanceOf(VolumeDialogVisibilityModel.Visible::class.java)
+
+ underTest.onCsdWarningDialogShown()
+ testScope.advanceTimeBy(2.seconds)
+ assertThat(visibility).isInstanceOf(VolumeDialogVisibilityModel.Visible::class.java)
+ }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockAnimations.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockAnimations.kt
index 77c18ea..8943276 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockAnimations.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockAnimations.kt
@@ -61,4 +61,7 @@
/** Runs when an animation when the view is tapped on the lockscreen */
fun onFidgetTap(x: Float, y: Float)
+
+ /** Update reactive axes for this clock */
+ fun onFontAxesChanged(style: ClockAxisStyle)
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockEvents.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockEvents.kt
index 0fc3470..7c0e486 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockEvents.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockEvents.kt
@@ -42,7 +42,4 @@
/** Call with zen/dnd information */
fun onZenDataChanged(data: ZenData)
-
- /** Update reactive axes for this clock */
- fun onFontAxesChanged(axes: ClockAxisStyle)
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt
index 5b67edd..4f04aaa 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt
@@ -90,10 +90,11 @@
}
}
- fun updateAxes(lsFVar: String, aodFVar: String) {
- i({ "updateAxes(LS = $str1, AOD = $str2)" }) {
+ fun updateAxes(lsFVar: String, aodFVar: String, isAnimated: Boolean) {
+ i({ "updateAxes(LS = $str1, AOD = $str2, isAnimated=$bool1)" }) {
str1 = lsFVar
str2 = aodFVar
+ bool1 = isAnimated
}
}
diff --git a/packages/SystemUI/res/drawable/magic_action_button_background.xml b/packages/SystemUI/res/drawable/animated_action_button_background.xml
similarity index 80%
rename from packages/SystemUI/res/drawable/magic_action_button_background.xml
rename to packages/SystemUI/res/drawable/animated_action_button_background.xml
index 7199b2d..1cecec5 100644
--- a/packages/SystemUI/res/drawable/magic_action_button_background.xml
+++ b/packages/SystemUI/res/drawable/animated_action_button_background.xml
@@ -10,10 +10,10 @@
android:insetRight="0dp"
android:insetTop="8dp">
<shape android:shape="rectangle">
- <corners android:radius="@dimen/magic_action_button_corner_radius" />
+ <corners android:radius="@dimen/animated_action_button_corner_radius" />
<solid android:color="@androidprv:color/materialColorPrimaryContainer" />
<stroke
- android:width="@dimen/magic_action_button_outline_stroke_width"
+ android:width="@dimen/animated_action_button_outline_stroke_width"
android:color="@androidprv:color/materialColorOutlineVariant" />
</shape>
</inset>
diff --git a/packages/SystemUI/res/layout/animated_action_button.xml b/packages/SystemUI/res/layout/animated_action_button.xml
new file mode 100644
index 0000000..3e5e35b
--- /dev/null
+++ b/packages/SystemUI/res/layout/animated_action_button.xml
@@ -0,0 +1,17 @@
+<com.android.systemui.statusbar.notification.row.AnimatedActionButton
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@android:style/Widget.Material.Button"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/animated_action_button_touch_target_height"
+ android:background="@drawable/animated_action_button_background"
+ android:drawablePadding="@dimen/animated_action_button_drawable_padding"
+ android:ellipsize="none"
+ android:fontFamily="google-sans-flex-medium"
+ android:gravity="center"
+ android:minWidth="0dp"
+ android:paddingHorizontal="@dimen/animated_action_button_padding_horizontal"
+ android:paddingVertical="@dimen/animated_action_button_inset_vertical"
+ android:stateListAnimator="@null"
+ android:textColor="@color/animated_action_button_text_color"
+ android:textSize="@dimen/animated_action_button_font_size"
+ android:textStyle="normal" />
diff --git a/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml
index 43808f2..4002f78 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml
@@ -21,6 +21,9 @@
style="@style/AuthCredentialPanelStyle"
android:layout_width="0dp"
android:layout_height="0dp"
+ android:accessibilityLiveRegion="assertive"
+ android:importantForAccessibility="yes"
+ android:clickable="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/rightGuideline"
app:layout_constraintStart_toStartOf="@id/leftGuideline"
diff --git a/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml
index 51117a7..3c8cb68 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml
@@ -22,6 +22,9 @@
style="@style/AuthCredentialPanelStyle"
android:layout_width="0dp"
android:layout_height="0dp"
+ android:accessibilityLiveRegion="assertive"
+ android:importantForAccessibility="yes"
+ android:clickable="false"
android:paddingHorizontal="16dp"
android:paddingVertical="16dp"
android:visibility="visible"
diff --git a/packages/SystemUI/res/layout/magic_action_button.xml b/packages/SystemUI/res/layout/magic_action_button.xml
deleted file mode 100644
index 63fc1e4..0000000
--- a/packages/SystemUI/res/layout/magic_action_button.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<com.android.systemui.statusbar.notification.row.MagicActionButton
- xmlns:android="http://schemas.android.com/apk/res/android"
- style="@android:style/Widget.Material.Button"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/magic_action_button_touch_target_height"
- android:background="@drawable/magic_action_button_background"
- android:drawablePadding="@dimen/magic_action_button_drawable_padding"
- android:ellipsize="none"
- android:fontFamily="google-sans-flex-medium"
- android:gravity="center"
- android:minWidth="0dp"
- android:paddingHorizontal="@dimen/magic_action_button_padding_horizontal"
- android:paddingVertical="@dimen/magic_action_button_inset_vertical"
- android:stateListAnimator="@null"
- android:textColor="@color/magic_action_button_text_color"
- android:textSize="@dimen/magic_action_button_font_size"
- android:textStyle="normal" />
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 0619281..5ed44a8 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik om nuwe toestel saam te bind"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Kon nie voorafstelling opdateer nie"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Voorafstelling"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Verstekmikrofoon vir oproepe"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Gehoortoestelmikrofoon"</item>
+ <item msgid="8501466270452446450">"Hierdie foon se mikrofoon"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Gekies"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Omgewing"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Links"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Aan – gesiggegrond"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Klaar"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Pas toe"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Skakel af"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Stil"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Verstek"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Outomaties"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Regs-ikoon"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Hou en sleep om teëls by te voeg"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Hou en sleep om teëls te herrangskik"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Sleep hierheen om te verwyder"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Jy moet minstens <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> teëls hê"</string>
<string name="qs_edit" msgid="5583565172803472437">"Wysig"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Ander"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"wissel die teël se grootte"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"verwyder teël"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"voeg teël by die laaste posisie"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Skuif teël"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Voeg teël by die verlangde posisie"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Onbekend"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Stel alle teëls terug?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alle Kitsinstellingsteëls sal na die toestel se oorspronklike instellings teruggestel word"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 3e4ca1c..de3e437 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"ለጥሪዎች ነባሪ ማይክሮፎን"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"የመስሚያ አጋዥ መሣሪያ ማይክሮፎን"</item>
+ <item msgid="8501466270452446450">"የዚህ ስልክ ማይክሮፎን"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"ተመርጧል"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"በዙሪያ ያሉ"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ግራ"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"በርቷል - መልክ ላይ የተመሠረተ"</string>
<string name="inline_done_button" msgid="6043094985588909584">"ተከናውኗል"</string>
<string name="inline_ok_button" msgid="603075490581280343">"ተግብር"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"አጥፋ"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"ፀጥ ያለ"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ነባሪ"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ራስ-ሰር"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"የቀኝ አዶ"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"ፋይሎችን ለማከል ይዘት ይጎትቱ"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"ሰድሮችን ዳግም ለማስተካከል ይያዙ እና ይጎትቱ።"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"ለማስወገድ ወደዚህ ይጎትቱ"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"ቢያንስ <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> ሰቆች ያስፈልገዎታል"</string>
<string name="qs_edit" msgid="5583565172803472437">"አርትዕ"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"ሌላ"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"የርዕሱን መጠን ይቀያይሩ"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ሰቅ አስወግድ"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"በመጨረሻው ቦታ ላይ ሰቅ ያክሉ"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ሰቁን ውሰድ"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"ወደተፈለገው ቦታ ሰቅ ያክሉ"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ያልታወቀ"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"ሁሉም ሰቆች ዳግም ይጀምሩ?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ሁሉም የፈጣን ቅንብሮች ሰቆች ወደ የመሣሪያው የመጀመሪያ ቅንብሮች ዳግም ይጀምራሉ"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>፣ <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index f9660a3..b0f96d6 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"الميكروفون التلقائي لإجراء المكالمات"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"ميكروفون سماعة الأذن الطبية"</item>
+ <item msgid="8501466270452446450">"ميكروفون هذا الهاتف"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"تمّ اختياره"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"الأصوات المحيطة"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"اليسرى"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"ستتم مشاركة كل المحتوى المعروض أو المشغَّل على شاشة هذا التطبيق مع تطبيق \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\"، لذا يُرجى توخي الحذر بشأن المعلومات الظاهرة على الشاشة، مثل كلمات المرور وتفاصيل الدفع والرسائل والصور والمقاطع الصوتية والفيديوهات."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"مشاركة الشاشة"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"تم إيقاف هذا الخيار من خلال تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"لا يتيح التطبيق هذه الميزة"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"يُرجى اختيار تطبيق لمشاركة محتواه"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"هل تريد بث محتوى الشاشة؟"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"بث محتوى تطبيق واحد"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"تفعيل - استنادًا للوجه"</string>
<string name="inline_done_button" msgid="6043094985588909584">"تمّ"</string>
<string name="inline_ok_button" msgid="603075490581280343">"تطبيق"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"إيقاف"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"إشعارات صامتة"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"تلقائية"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"تلقائي"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"رمز اليمين"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"اضغط باستمرار مع السحب لإضافة المربّعات"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"اضغط باستمرار مع السحب لإعادة ترتيب الميزات"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"اسحب هنا للإزالة"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"الحدّ الأدنى من عدد المربعات الذي تحتاج إليه هو <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
<string name="qs_edit" msgid="5583565172803472437">"تعديل"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"غير ذلك"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"تبديل حجم المربّع"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"إزالة بطاقة"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"إضافة مربّع إلى الموضع الأخير"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"نقل بطاقة"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"إضافة مربّع إلى الموضع المطلوب"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"غير معروفة"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"هل تريد إعادة ضبط كل المربّعات؟"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ستتم إعادة ضبط جميع مربّعات \"الإعدادات السريعة\" إلى الإعدادات الأصلية للجهاز"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"\"<xliff:g id="STREAM_NAME">%1$s</xliff:g>\"، <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/tiles_states_strings.xml b/packages/SystemUI/res/values-ar/tiles_states_strings.xml
index 31607b9..ba73b9b 100644
--- a/packages/SystemUI/res/values-ar/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ar/tiles_states_strings.xml
@@ -56,9 +56,11 @@
<item msgid="5376619709702103243">"الميزة غير مفعّلة"</item>
<item msgid="4875147066469902392">"الميزة مفعّلة"</item>
</string-array>
- <!-- no translation found for tile_states_modes_dnd:0 (6509540227356524582) -->
- <!-- no translation found for tile_states_modes_dnd:1 (8589336868985358191) -->
- <!-- no translation found for tile_states_modes_dnd:2 (726072717827778234) -->
+ <string-array name="tile_states_modes_dnd">
+ <item msgid="6509540227356524582">"غير متوفّر"</item>
+ <item msgid="8589336868985358191">"غير مفعَّل"</item>
+ <item msgid="726072717827778234">"مفعّل"</item>
+ </string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"الميزة غير متاحة"</item>
<item msgid="5044688398303285224">"الميزة غير مفعّلة"</item>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 595432e..ccec3dd 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"কলৰ বাবে ডিফ’ল্ট মাইক্ৰ’ফ’ন"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"শ্ৰৱণ যন্ত্ৰৰ মাইক্ৰ’ফ’ন"</item>
+ <item msgid="8501466270452446450">"এই ফ’নটোৰ মাইক্ৰ’ফ’ন"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"বাছনি কৰা হৈছে"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"আশ-পাশ"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"বাওঁফাল"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"অন আছে - মুখাৱয়ব ভিত্তিক"</string>
<string name="inline_done_button" msgid="6043094985588909584">"কৰা হ’ল"</string>
<string name="inline_ok_button" msgid="603075490581280343">"প্ৰয়োগ কৰক"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"অফ কৰক"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"নীৰৱ"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ডিফ’ল্ট"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"স্বয়ংক্ৰিয়"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"সোঁ আইকন"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"টাইল যোগ কৰিবলৈ হেঁচি ধৰি টানি আনক"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"টাইলসমূহ পুনৰ সজাবলৈ ধৰি টানক"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"আঁতৰাবৰ বাবে টানি আনি ইয়াত এৰি দিয়ক"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"আপোনাক অতিকমেও <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>খন টাইল লাগিব"</string>
<string name="qs_edit" msgid="5583565172803472437">"সম্পাদনা কৰক"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"অন্যান্য"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"টাইলৰ আকাৰ ট’গল কৰক"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"টাইল আঁতৰাবলৈ"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"অন্তিম স্থানত টাইল যোগ দিয়ক"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"টাইল স্থানান্তৰ কৰক"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"বিচৰা স্থানত টাইল যোগ দিয়ক"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"অজ্ঞাত"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"আটাইবোৰ টাইল ৰিছেট কৰিবনে?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"আটাইবোৰ ক্ষিপ্ৰ ছেটিঙৰ টাইল ডিভাইচৰ মূল ছেটিংছলৈ ৰিছেট হ’ব"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 3cf675d..37091c3 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yeni cihaz birləşdirmək üçün klikləyin"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Hazır ayar güncəllənmədi"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Hazır Ayar"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Zənglər üçün defolt mikrofon"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Eşitmə aparatı mikrofonu"</item>
+ <item msgid="8501466270452446450">"Bu telefonun mikrofonu"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Seçilib"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ətraf mühit"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Sol"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Tətbiq paylaşdığınız zaman həmin tətbiqdə göstərilən və ya işə salınan hər şey <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> üçün görünən olacaq. Parol, ödəniş məlumatı, mesaj, foto, habelə audio və video kimi məlumatlarla bağlı diqqətli olun."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Ekranı paylaşın"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> bu seçimi deaktiv edib"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"Tətbiq tərəfindən dəstəklənmir"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Paylaşmaq üçün tətbiq seçin"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Ekran yayımlansın?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Bir tətbiqi yayımlayın"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Aktiv - Üz əsaslı"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Hazırdır"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Tətbiq edin"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Söndürün"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Səssiz"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Defolt"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Avtomatik"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"Sağ ikona"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Mozaika əlavə etmək üçün basıb saxlayaraq çəkin"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"İkonları yenidən düzənləmək üçün saxlayaraq dartın"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Silmək üçün bura sürüşdürün"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Minimum <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> mozaika lazımdır"</string>
<string name="qs_edit" msgid="5583565172803472437">"Redaktə edin"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"Digər"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"mozaik ölçüsünü aktiv/deaktiv edin"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"lövhəni silin"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"son mövqeyə mozaik əlavə edin"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Lövhəni köçürün"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"İstənilən mövqeyə mozaik əlavə edin"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Naməlum"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Bütün mozaiklər sıfırlansın?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Bütün Sürətli Ayarlar mozaiki cihazın orijinal ayarlarına sıfırlanacaq"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index b74094e5..98aabe7 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da biste uparili nov uređaj"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Ažuriranje zadatih podešavanja nije uspelo"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Unapred određena podešavanja"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Podrazumevani mikrofon za pozive"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Mikrofon slušnog aparata"</item>
+ <item msgid="8501466270452446450">"Mikrofon ovog telefona"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Izabrano"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Okruženje"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Levo"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kada delite aplikaciju, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vidi sav sadržaj koji se prikazuje ili pušta u njoj. Zato pazite na lozinke, informacije o plaćanju, poruke, slike, audio i video sadržaj."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Deli ekran"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je onemogućila ovu opciju"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"Aplikacija to ne podržava"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Odaberite aplikaciju za deljenje"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Želite da prebacite ekran?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Prebaci jednu aplikaciju"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Uključeno – na osnovu lica"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Gotovo"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Primeni"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Isključi"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Nečujno"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Podrazumevano"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatska"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"Desna ikona"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Zadržite i prevucite da biste dodali pločice"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Zadržite i prevucite da biste promenili raspored pločica"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Prevucite ovde da biste uklonili"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Minimalan broj pločica je <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
<string name="qs_edit" msgid="5583565172803472437">"Izmeni"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"Drugo"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"uključivanje ili isključivanje veličine pločice"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"uklonili pločicu"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"dodali pločicu na poslednju poziciju"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Premestite pločicu"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Dodajte pločicu na željenu poziciju"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nepoznato"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Želite da resetujete sve pločice?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Sve pločice Brzih podešavanja će se resetovati na prvobitna podešavanja uređaja"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 11c2715..bf9929e 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Стандартны мікрафон для выклікаў"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Мікрафон слыхавога апарата"</item>
+ <item msgid="8501466270452446450">"Мікрафон гэтага тэлефона"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Выбрана"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Навакольныя гукі"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Левы бок"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Калі вы абагульваеце праграму, праграма \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" можа бачыць усё, што паказваецца ці прайграецца ў гэтай праграме. Таму прадухіліце паказ пароляў, плацежных рэквізітаў, паведамленняў, фота, відэа і аўдыя."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Абагуліць экран"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" адключыла гэты параметр"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"Не падтрымліваецца праграмай"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Выберыце праграму для абагульвання"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Уключыць трансляцыю экрана?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Трансліраваць адну праграму"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Уключана – З улікам паставы галавы"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Гатова"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Прымяніць"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Выключыць"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Бязгучны рэжым"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Стандартна"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Аўтаматычна"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"Значок \"управа\""</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Перацягніце патрэбныя пліткі"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Каб змяніць парадак плітак, утрымлівайце і перацягвайце іх"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Перацягніце сюды, каб выдаліць"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Мінімальная колькасць плітак: <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
<string name="qs_edit" msgid="5583565172803472437">"Рэдагаваць"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"Іншае"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"змяніць памер пліткі"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"выдаліць плітку"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"дадаць плітку ў апошнюю пазіцыю"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Перамясціць плітку"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Дадаць плітку ў патрэбную пазіцыю"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Невядома"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Скінуць усе пліткі?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Усе пліткі хуткіх налад будуць скінуты да першапачатковых налад прылады"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index a085b154..4a0b80b 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Микрофон по подразбиране за обажданията"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Микрофонът на слуховия апарат"</item>
+ <item msgid="8501466270452446450">"Микрофонът на този телефон"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Избрано"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Околни звуци"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Ляво"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Когато споделяте приложение, всичко, което се показва или възпроизвежда в него, е видимо за <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Затова бъдете внимателни с неща като пароли, подробности за начини на плащане, съобщения, снимки, аудио и видео."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Споделяне на екрана"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> деактивира тази опция"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"Не се поддържа от приложението"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Изберете приложение за споделяне"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Искате ли да предавате екрана си?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Предаване на едно приложение"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Вкл. – въз основа на лицето"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Готово"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Прилагане"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Изключване"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Тих режим"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Стандартно"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматично"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"Дясна икона"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Задръжте и плъзнете, за да добавите плочки"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Задръжте и плъзнете, за да пренаредите плочките"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Преместете тук с плъзгане за премахване"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Трябва да останат поне <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> плочки"</string>
<string name="qs_edit" msgid="5583565172803472437">"Редактиране"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"Друго"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"превключване на размера на панела"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"премахване на панел"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"добавяне на панела на последната позиция"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Преместване на панел"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Добавяне на панела на желаната позиция"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Неизвестно"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Да се нулират ли всички панели?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Всички панели с бързи настройки ще бъдат нулирани до първоначалните настройки на устройството"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g> – <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 18d632e..ac365f8 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"কলের জন্য ডিফল্ট মাইক্রোফোন"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"হিয়ারিং এড মাইক্রোফোন"</item>
+ <item msgid="8501466270452446450">"এই ফোনের মাইক্রোফোন"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"বেছে নেওয়া হয়েছে"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"সারাউন্ডিং"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"বাঁদিক"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"চালু আছে - মুখের হিসেবে"</string>
<string name="inline_done_button" msgid="6043094985588909584">"হয়ে গেছে"</string>
<string name="inline_ok_button" msgid="603075490581280343">"প্রয়োগ করুন"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"বন্ধ করুন"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"সাইলেন্ট"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ডিফল্ট"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"অটোমেটিক"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"ডানদিকের আইকন"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"টাইল যোগ করতে ধরে থেকে টেনে আনুন"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"টাইলগুলি আবার সাজানোর জন্য ধরে থেকে টেনে আনুন"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"সরানোর জন্য এখানে টেনে আনুন"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"আপনাকে কমপক্ষে <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>টি টাইল রাখতে হবে"</string>
<string name="qs_edit" msgid="5583565172803472437">"এডিট করুন"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"অন্যান্য"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"টাইলের সাইজ টগল করুন"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"টাইল সরান"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"শেষ জায়গাতে টাইল যোগ করুন"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"টাইল সরান"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"আপনার পছন্দের জায়গাতে টাইল যোগ করুন"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"অজানা"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"সব টাইল রিসেট করবেন?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"সব কুইক সেটিংস টাইল, ডিভাইসের আসল সেটিংসে রিসেট হয়ে যাবে"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/tiles_states_strings.xml b/packages/SystemUI/res/values-bn/tiles_states_strings.xml
index 852986c..95a567a 100644
--- a/packages/SystemUI/res/values-bn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bn/tiles_states_strings.xml
@@ -56,9 +56,11 @@
<item msgid="5376619709702103243">"বন্ধ আছে"</item>
<item msgid="4875147066469902392">"চালু আছে"</item>
</string-array>
- <!-- no translation found for tile_states_modes_dnd:0 (6509540227356524582) -->
- <!-- no translation found for tile_states_modes_dnd:1 (8589336868985358191) -->
- <!-- no translation found for tile_states_modes_dnd:2 (726072717827778234) -->
+ <string-array name="tile_states_modes_dnd">
+ <item msgid="6509540227356524582">"উপলভ্য নেই"</item>
+ <item msgid="8589336868985358191">"বন্ধ করুন"</item>
+ <item msgid="726072717827778234">"চালু করুন"</item>
+ </string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"উপলভ্য নেই"</item>
<item msgid="5044688398303285224">"বন্ধ আছে"</item>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index c18af99..c026090 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da uparite novi uređaj"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Ažuriranje zadane postavke nije uspjelo"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Zadana postavka"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Zadani mikrofon za pozive"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Mikrofon slušnog aparata"</item>
+ <item msgid="8501466270452446450">"Mikrofon telefona"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Odabrano"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Okruženje"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Lijevo"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Uključeno – na osnovu lica"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Gotovo"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Primijeni"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Isključi"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Nečujno"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Zadano"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatski"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Ikona desno"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Držite i prevucite da dodate polja"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Držite i prevucite da preuredite polja"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Prevucite ovdje za uklanjanje"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Broj polja mora biti najmanje <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
<string name="qs_edit" msgid="5583565172803472437">"Uredite"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Ostalo"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"uključivanje/isključivanje veličine kartice"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"uklanjanje kartice"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"dodavanje kartice na posljednji položaj"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Pomjeranje kartice"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Dodavanje kartice na željeni položaj"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nepoznato"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vratiti sve kartice na zadano?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Sve kartice Brze postavke će se vratiti na originalne postavke uređaja"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 0404bc7..ad14824 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fes clic per vincular un dispositiu nou"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"No s\'ha pogut actualitzar el valor predefinit"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Valors predefinits"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Micròfon predeterminat per a trucades"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Micròfon d\'audiòfon"</item>
+ <item msgid="8501466270452446450">"El micròfon d\'aquest telèfon"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Seleccionat"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Entorn"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Esquerra"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Activat: basat en cares"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Fet"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Aplica"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Desactiva"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silenci"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Predeterminat"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automàtic"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Icona de la dreta"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Mantén premudes les icones i arrossega-les per afegir-les"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Mantén premudes les icones i arrossega-les per reordenar-les"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Arrossega aquí per suprimir"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Necessites com a mínim <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> mosaics"</string>
<string name="qs_edit" msgid="5583565172803472437">"Edita"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Altres"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"commutar la mida de la icona"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"suprimir el mosaic"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"afegir una icona a la darrera posició"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mou el mosaic"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Afegeix una icona a la posició que vulguis"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconegut"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vols restablir totes les icones?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Totes les icones de configuració ràpida es restabliran a les opcions originals del dispositiu"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index e438d63..9fde63c 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknutím spárujete nové zařízení"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Předvolbu nelze aktualizovat"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Předvolba"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Výchozí mikrofon pro hovory"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Mikrofon naslouchátka"</item>
+ <item msgid="8501466270452446450">"Mikrofon tohohle telefonu"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Vybráno"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Okolí"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Vlevo"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Zapnuto – podle obličeje"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Hotovo"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Použít"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Vypnout"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Tichý režim"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Výchozí"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automaticky"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Ikona vpravo"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Dlaždice přidáte podržením a přetažením"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Dlaždice můžete uspořádat podržením a přetažením"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Přetažením sem dlaždice odstraníte"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Potřebujete alespoň tento počet dlaždic: <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
<string name="qs_edit" msgid="5583565172803472437">"Upravit"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Jiné"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"přepnout velikost dlaždice"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"odstranit dlaždici"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"přidat dlaždici na poslední pozici"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Přesunout dlaždici"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Přidat dlaždici na požadované místo"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Neznámé"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Resetovat všechny dlaždice?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Všechny dlaždice Rychlého nastavení se resetují do původní konfigurace zařízení"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 52abc4a..fbb293b 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik for at parre en ny enhed"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Forindstillingen kunne ikke opdateres"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Forindstilling"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Standardmikrofon til opkald"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Mikrofon i høreapparat"</item>
+ <item msgid="8501466270452446450">"Denne telefons mikrofon"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Valgt"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Omgivelser"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Venstre"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Til – ansigtsbaseret"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Udfør"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Anvend"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Deaktiver"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Lydløs"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Standard"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatisk"</string>
@@ -912,7 +912,7 @@
<string name="system_multitasking_rhs" msgid="8779289852395243004">"Brug opdelt skærm med appen til højre"</string>
<string name="system_multitasking_lhs" msgid="7348595296208696452">"Brug opdelt skærm med appen til venstre"</string>
<string name="system_multitasking_full_screen" msgid="4221409316059910349">"Brug fuld skærm"</string>
- <string name="system_multitasking_desktop_view" msgid="8871367687089347180">"Brug vinduer på skrivebordet"</string>
+ <string name="system_multitasking_desktop_view" msgid="8871367687089347180">"Brug skrivebordsvinduer"</string>
<string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Skift til en app til højre eller nedenfor, når du bruger opdelt skærm"</string>
<string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Skift til en app til venstre eller ovenfor, når du bruger opdelt skærm"</string>
<string name="system_multitasking_replace" msgid="7410071959803642125">"Ved opdelt skærm: Udskift én app med en anden"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Højre ikon"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Tilføj felter ved at holde dem nede og trække dem"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Flyt rundt på felterne ved at holde dem nede og trække"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Træk herhen for at fjerne"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Du skal bruge mindst <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> felter"</string>
<string name="qs_edit" msgid="5583565172803472437">"Rediger"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Andet"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ændre feltets størrelse"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"fjern felt"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"føj handlingsfeltet til den sidste position"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Flyt felt"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Føj handlingsfeltet til den ønskede placering"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Ukendt"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vil du nulstille alle handlingsfelter?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alle handlingsfelter i kvikmenuen nulstilles til enhedens oprindelige indstillinger"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 612c52f..86304f7 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klicken, um neues Gerät zu koppeln"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Voreinstellung konnte nicht aktualisiert werden"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Voreinstellung"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Standardmikrofon für Anrufe"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Mikrofon des Hörgeräts"</item>
+ <item msgid="8501466270452446450">"Mikrofon dieses Smartphones"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Ausgewählt"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Umgebungsgeräusche"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Links"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"An – gesichtsbasiert"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Fertig"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Anwenden"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Deaktivieren"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Lautlos"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Standard"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatisch"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Rechtes Symbol"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Zum Hinzufügen Kachel halten und ziehen"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Zum Verschieben Kachel halten und ziehen"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Zum Entfernen hierher ziehen"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Du brauchst mindestens <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> Kacheln"</string>
<string name="qs_edit" msgid="5583565172803472437">"Bearbeiten"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Sonstiges"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"Größe der Kachel umschalten"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"Entfernen der Kachel"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"Kachel an letzter Position hinzufügen"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Kachel verschieben"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Kachel an gewünschter Position hinzufügen"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unbekannt"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Alle Kacheln zurücksetzen?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alle Schnelleinstellungen-Kacheln werden auf die Standardeinstellungen des Geräts zurückgesetzt"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 2c17a39..478ac05 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -49,23 +49,23 @@
<string name="label_view" msgid="6815442985276363364">"Προβολή"</string>
<string name="always_use_device" msgid="210535878779644679">"Να ανοίγει πάντα η εφ. <xliff:g id="APPLICATION">%1$s</xliff:g> όταν είναι συνδεδεμένo το <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
<string name="always_use_accessory" msgid="1977225429341838444">"Να ανοίγει πάντα η εφ. <xliff:g id="APPLICATION">%1$s</xliff:g> όταν είναι συνδεδεμένο το <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
- <string name="usb_debugging_title" msgid="8274884945238642726">"Να επιτρέπεται ο εντοπισμός σφαλμάτων USB;"</string>
+ <string name="usb_debugging_title" msgid="8274884945238642726">"Να επιτρέπεται η αποσφαλμάτωση USB;"</string>
<string name="usb_debugging_message" msgid="5794616114463921773">"Το μοναδικό χαρακτηριστικό του κλειδιού RSA είναι:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="4003121804294739548">"Να επιτρέπεται πάντα από αυτόν τον υπολογιστή"</string>
<string name="usb_debugging_allow" msgid="1722643858015321328">"Να επιτρέπεται"</string>
- <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Δεν επιτρέπεται ο εντοπισμός σφαλμάτων USB"</string>
- <string name="usb_debugging_secondary_user_message" msgid="1888835696965417845">"Ο χρήστης που είναι συνδεδεμένος αυτήν τη στιγμή σε αυτήν τη συσκευή δεν μπορεί να ενεργοποιήσει τον εντοπισμό σφαλμάτων USB. Για να χρησιμοποιήσετε αυτήν τη λειτουργία, κάντε εναλλαγή σε έναν χρήστη με δικαιώματα διαχειριστή."</string>
+ <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Δεν επιτρέπεται η αποσφαλμάτωση USB"</string>
+ <string name="usb_debugging_secondary_user_message" msgid="1888835696965417845">"Ο χρήστης που είναι συνδεδεμένος αυτήν τη στιγμή σε αυτήν τη συσκευή δεν μπορεί να ενεργοποιήσει την αποσφαλμάτωση USB. Για να χρησιμοποιήσετε αυτήν τη λειτουργία, κάντε εναλλαγή σε έναν χρήστη με δικαιώματα διαχειριστή."</string>
<string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Θέλετε να αλλάξετε τη γλώσσα συστήματος σε <xliff:g id="LANGUAGE">%1$s</xliff:g>;"</string>
<string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Ζητήθηκε αλλαγή της γλώσσας συστήματος από άλλη συσκευή"</string>
<string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Αλλαγή γλώσσας"</string>
<string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Διατήρ. τρέχουσας γλώσσας"</string>
<string name="share_wifi_button_text" msgid="1285273973812029240">"Μοιραστείτε το Wi‑Fi"</string>
- <string name="wifi_debugging_title" msgid="7300007687492186076">"Να επιτρέπεται ασύρματος εντοπ. σφαλ. στο δίκτυο;"</string>
+ <string name="wifi_debugging_title" msgid="7300007687492186076">"Να επιτρέπεται ασύρματη αποσφαλμάτωση στο δίκτυο;"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Όνομα δικτύου (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nΔιεύθυνση Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Να επιτρέπεται πάντα σε αυτό το δίκτυο"</string>
<string name="wifi_debugging_allow" msgid="4573224609684957886">"Να επιτρέπεται"</string>
- <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Ο ασύρματος εντοπισμός σφαλμάτων δεν επιτρέπεται"</string>
- <string name="wifi_debugging_secondary_user_message" msgid="9085779370142222881">"Ο χρήστης που είναι συνδεδεμένος αυτήν τη στιγμή στη συγκεκριμένη συσκευή δεν μπορεί να ενεργοποιήσει τον ασύρματο εντοπισμό σφαλμάτων. Για να χρησιμοποιήσετε αυτήν τη λειτουργία, κάντε εναλλαγή σε έναν χρήστη με δικαιώματα διαχειριστή."</string>
+ <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Η ασύρματη αποσφαλμάτωση δεν επιτρέπεται"</string>
+ <string name="wifi_debugging_secondary_user_message" msgid="9085779370142222881">"Ο χρήστης που είναι συνδεδεμένος αυτήν τη στιγμή στη συγκεκριμένη συσκευή δεν μπορεί να ενεργοποιήσει την ασύρματη αποσφαλμάτωση. Για να χρησιμοποιήσετε αυτήν τη λειτουργία, κάντε εναλλαγή σε έναν χρήστη με δικαιώματα διαχειριστή."</string>
<string name="usb_contaminant_title" msgid="894052515034594113">"Η θύρα USB απενεργοποιήθηκε"</string>
<string name="usb_contaminant_message" msgid="7730476585174719805">"Για την προστασία της συσκευής σας από υγρασία ή ακαθαρσίες, η θύρα USB έχει απενεργοποιηθεί και δεν θα εντοπίζει τυχόν αξεσουάρ.\n\nΘα ειδοποιηθείτε όταν θα μπορείτε να χρησιμοποιήσετε ξανά τη θύρα USB."</string>
<string name="usb_port_enabled" msgid="531823867664717018">"Η θύρα USB ενεργοποιήθηκε για τον εντοπισμό φορτιστών και αξεσουάρ"</string>
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Προεπιλεγμένο μικρόφωνο για κλήσεις"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Μικρόφωνο του βοηθήματος ακοής"</item>
+ <item msgid="8501466270452446450">"Μικρόφωνο αυτού του τηλεφώνου"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Έχει επιλεγεί"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ήχοι περιβάλλοντος"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Αριστερά"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Όταν μοιράζεστε μια εφαρμογή, οτιδήποτε εμφανίζεται ή αναπαράγεται σε αυτή την εφαρμογή, είναι ορατό στην εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα, τις φωτογραφίες, τον ήχο και το βίντεο."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Κοινή χρήση οθόνης"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> απενεργοποίησε αυτή την επιλογή"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"Δεν υποστηρίζεται από την εφαρμογή"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Επιλογή εφαρμογής για κοινή χρήση"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Να γίνει μετάδοση της οθόνης σας;"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Μετάδοση μίας εφαρμογής"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Ενεργό - Βάσει προσώπου"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Τέλος"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Εφαρμογή"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Απενεργοποίηση"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Σίγαση"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Προεπιλογή"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Αυτόματο"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"Δεξιό εικονίδιο"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Κρατήστε και σύρετε για την προσθήκη πλακιδίων"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Κρατήστε και σύρετε για αναδιάταξη των πλακιδίων"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Σύρετε εδώ για κατάργηση"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Χρειάζεστε τουλάχιστον <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> πλακίδια"</string>
<string name="qs_edit" msgid="5583565172803472437">"Επεξεργασία"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"Άλλο"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"εναλλαγή μεγέθους για το πλακάκι"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"κατάργηση πλακιδίου"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"προσθήκη πλακιδίου στην τελευταία θέση"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Μετακίνηση πλακιδίου"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Προσθήκη πλακιδίου στην επιθυμητή θέση"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Άγνωστο"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Επαναφορά σε όλα τα πλακάκια;"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Σε όλα τα πλακάκια Γρήγορων ρυθμίσεων θα γίνει επαναφορά στις αρχικές ρυθμίσεις της συσκευής"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 7b8f982..ea332cb 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Couldn\'t update preset"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Default microphone for calls"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Hearing aid microphone"</item>
+ <item msgid="8501466270452446450">"This phone\'s microphone"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selected"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Surroundings"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Left"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"On – Face-based"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Done"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Apply"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Turn off"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silent"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Default"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatic"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Right icon"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Hold and drag to add tiles"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Hold and drag to rearrange tiles"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Drag here to remove"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"You need at least <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> tiles"</string>
<string name="qs_edit" msgid="5583565172803472437">"Edit"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Other"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"toggle the tile\'s size"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remove tile"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"add tile to the last position"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Move tile"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Add tile to desired position"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unknown"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Reset all tiles?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"All Quick Settings tiles will reset to the device\'s original settings"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 15056c6..b6dd88a 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -982,11 +982,11 @@
<string name="right_icon" msgid="1103955040645237425">"Right icon"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Hold and drag to add tiles"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Hold and drag to rearrange tiles"</string>
+ <string name="tap_to_position_tile" msgid="6282815817773342757">"Tap to position tile"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Drag here to remove"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"You need at least <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> tiles"</string>
<string name="qs_edit" msgid="5583565172803472437">"Edit"</string>
- <!-- no translation found for qs_edit_tiles (2105215324060865035) -->
- <skip />
+ <string name="qs_edit_tiles" msgid="2105215324060865035">"Edit tiles"</string>
<string name="tuner_time" msgid="2450785840990529997">"Time"</string>
<string-array name="clock_options">
<item msgid="3986445361435142273">"Show hours, minutes, and seconds"</item>
@@ -1002,6 +1002,8 @@
<string name="other" msgid="429768510980739978">"Other"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"toggle the tile\'s size"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remove tile"</string>
+ <string name="accessibility_qs_edit_toggle_placement_mode" msgid="3870429389210569610">"toggle placement mode"</string>
+ <string name="accessibility_qs_edit_toggle_selection" msgid="2201248304072372239">"toggle selection"</string>
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"add tile to the last position"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Move tile"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Add tile to desired position"</string>
@@ -1577,5 +1579,6 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unknown"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Reset all tiles?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"All Quick Settings tiles will reset to the device’s original settings"</string>
+ <string name="demote_explain_text" msgid="1600426458580544250">"<xliff:g id="APPLICATION">%1$s</xliff:g> will no longer show Live Updates here. You can change this any time in Settings."</string>
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 7b8f982..ea332cb 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Couldn\'t update preset"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Default microphone for calls"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Hearing aid microphone"</item>
+ <item msgid="8501466270452446450">"This phone\'s microphone"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selected"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Surroundings"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Left"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"On – Face-based"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Done"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Apply"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Turn off"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silent"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Default"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatic"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Right icon"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Hold and drag to add tiles"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Hold and drag to rearrange tiles"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Drag here to remove"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"You need at least <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> tiles"</string>
<string name="qs_edit" msgid="5583565172803472437">"Edit"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Other"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"toggle the tile\'s size"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remove tile"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"add tile to the last position"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Move tile"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Add tile to desired position"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unknown"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Reset all tiles?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"All Quick Settings tiles will reset to the device\'s original settings"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 7b8f982..ea332cb 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Couldn\'t update preset"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Default microphone for calls"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Hearing aid microphone"</item>
+ <item msgid="8501466270452446450">"This phone\'s microphone"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selected"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Surroundings"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Left"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"On – Face-based"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Done"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Apply"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Turn off"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silent"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Default"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatic"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Right icon"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Hold and drag to add tiles"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Hold and drag to rearrange tiles"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Drag here to remove"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"You need at least <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> tiles"</string>
<string name="qs_edit" msgid="5583565172803472437">"Edit"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Other"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"toggle the tile\'s size"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remove tile"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"add tile to the last position"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Move tile"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Add tile to desired position"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unknown"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Reset all tiles?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"All Quick Settings tiles will reset to the device\'s original settings"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 1b15b1b..e9e58e1 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Haz clic para vincular un dispositivo nuevo"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"No se pudo actualizar el ajuste predeterminado"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Ajuste predeterminado"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Micrófono predeterminado para llamadas"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Micrófono de audífonos"</item>
+ <item msgid="8501466270452446450">"Micrófono de este teléfono"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Seleccionado"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Sonido envolvente"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Izquierda"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Activa - En función del rostro"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Listo"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Aplicar"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Desactivar"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silenciada"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Predeterminada"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Ícono derecho"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Mantén presionada una tarjeta y arrástrala para agregarla"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Mantén presionada una tarjeta y arrástrala para reubicarla"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Arrastra aquí para quitar"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Necesitas al menos <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> tarjetas"</string>
<string name="qs_edit" msgid="5583565172803472437">"Editar"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Otros"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"alternar el tamaño del mosaico"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"quitar tarjeta"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"agregar tarjeta a la última posición"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover la tarjeta"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Agregar tarjeta a la posición deseada"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconocido"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"¿Quieres restablecer todas las tarjetas?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Se restablecerán todas las tarjeta de Configuración rápida a la configuración original del dispositivo"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
index 3310d2b..2eb8435 100644
--- a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
@@ -56,9 +56,11 @@
<item msgid="5376619709702103243">"Desactivado"</item>
<item msgid="4875147066469902392">"Activado"</item>
</string-array>
- <!-- no translation found for tile_states_modes_dnd:0 (6509540227356524582) -->
- <!-- no translation found for tile_states_modes_dnd:1 (8589336868985358191) -->
- <!-- no translation found for tile_states_modes_dnd:2 (726072717827778234) -->
+ <string-array name="tile_states_modes_dnd">
+ <item msgid="6509540227356524582">"No disponible"</item>
+ <item msgid="8589336868985358191">"Desactivado"</item>
+ <item msgid="726072717827778234">"Activado"</item>
+ </string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"No disponible"</item>
<item msgid="5044688398303285224">"Desactivada"</item>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 2311b48..011b9cc 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Haz clic para emparejar un nuevo dispositivo"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"No se ha podido actualizar el preajuste"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preajuste"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Micrófono predeterminado para llamadas"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Micrófono del audífono"</item>
+ <item msgid="8501466270452446450">"El micrófono de este teléfono"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Seleccionado"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Alrededores"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Izquierda"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Activado: basado en caras"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Hecho"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Aplicar"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Desactivar"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silencio"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Predeterminado"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Icono a la derecha"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Mantén pulsado un recuadro y arrástralo para añadirlo"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Mantén pulsado un recuadro y arrástralo para reubicarlo"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Arrastra aquí para quitar una función"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Necesitas al menos <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> recuadros"</string>
<string name="qs_edit" msgid="5583565172803472437">"Editar"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Otros"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"mostrar el tamaño del recuadro"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"quitar recuadro"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"añadir el recuadro a la última posición"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover recuadro"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Añadir recuadro a la posición deseada"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconocido"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"¿Borrar todos los recuadros?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Todos los recuadros de ajustes rápidos se restablecerán a los ajustes originales del dispositivo"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/tiles_states_strings.xml b/packages/SystemUI/res/values-es/tiles_states_strings.xml
index 546190f..57b140d 100644
--- a/packages/SystemUI/res/values-es/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es/tiles_states_strings.xml
@@ -56,9 +56,11 @@
<item msgid="5376619709702103243">"Desactivado"</item>
<item msgid="4875147066469902392">"Activado"</item>
</string-array>
- <!-- no translation found for tile_states_modes_dnd:0 (6509540227356524582) -->
- <!-- no translation found for tile_states_modes_dnd:1 (8589336868985358191) -->
- <!-- no translation found for tile_states_modes_dnd:2 (726072717827778234) -->
+ <string-array name="tile_states_modes_dnd">
+ <item msgid="6509540227356524582">"No disponible"</item>
+ <item msgid="8589336868985358191">"Desactivado"</item>
+ <item msgid="726072717827778234">"Activado"</item>
+ </string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"No disponible"</item>
<item msgid="5044688398303285224">"Desactivado"</item>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 9d22171..2412cfb 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Uue seadme sidumiseks klõpsake"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Eelseadistust ei saanud värskendada"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Eelseadistus"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Kõnede vaikemikrofon"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Kuuldeaparaadi mikrofon"</item>
+ <item msgid="8501466270452446450">"Selle telefoni mikrofon"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Valitud"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ümbritsevad helid"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Vasakule"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Sees – näopõhine"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Valmis"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Rakenda"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Lülita välja"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Hääletu"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Vaikeseade"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automaatne"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Parem ikoon"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Paanide lisamiseks hoidke all ja lohistage"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Paanide ümberpaigutamiseks hoidke neid all ja lohistage"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Lohistage eemaldamiseks siia"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Teil on vaja vähemalt <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> paani"</string>
<string name="qs_edit" msgid="5583565172803472437">"Muutmine"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Muu"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"muutke paani suurust"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"paani eemaldamiseks"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"lisage paan viimasesse asukohta"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Teisalda paan"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Lisage paan soovitud asukohta"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Teadmata"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Kas lähtestada kõik paanid?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Kõik kiirseadete paanid lähtestatakse seadme algseadetele"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 443632b..1a960ec 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Egin klik beste gailu bat parekatzeko"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Ezin izan da eguneratu aurrezarpena"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Aurrezarpena"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Deiak egiteko mikrofono lehenetsia"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Audifonoaren mikrofonoa"</item>
+ <item msgid="8501466270452446450">"Telefono honen mikrofonoa"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Hautatuta"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ingurunea"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Ezkerrekoa"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Aktibatuta: aurpegian oinarrituta"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Eginda"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Aplikatu"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Desaktibatu"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Isila"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Lehenetsia"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatikoa"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Eskuineko ikonoa"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Lauzak gehitzeko, eduki itzazu sakatuta, eta arrastatu"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Lauzak antolatzeko, eduki itzazu sakatuta, eta arrastatu"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Kentzeko, arrastatu hona"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"<xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> lauza behar dituzu gutxienez"</string>
<string name="qs_edit" msgid="5583565172803472437">"Editatu"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Beste bat"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"aldatu lauzaren tamaina"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"kendu lauza"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"gehitu lauza azken posizioan"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mugitu lauza"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Gehitu lauza nahi duzun posizioan"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Ezezagunak"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Lauza guztiak berrezarri nahi dituzu?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Gailuaren jatorrizko ezarpenak berrezarriko dira ezarpen bizkorren lauza guztietan"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/tiles_states_strings.xml b/packages/SystemUI/res/values-eu/tiles_states_strings.xml
index 923d84f..b37154e 100644
--- a/packages/SystemUI/res/values-eu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-eu/tiles_states_strings.xml
@@ -56,9 +56,11 @@
<item msgid="5376619709702103243">"Desaktibatuta"</item>
<item msgid="4875147066469902392">"Aktibatuta"</item>
</string-array>
- <!-- no translation found for tile_states_modes_dnd:0 (6509540227356524582) -->
- <!-- no translation found for tile_states_modes_dnd:1 (8589336868985358191) -->
- <!-- no translation found for tile_states_modes_dnd:2 (726072717827778234) -->
+ <string-array name="tile_states_modes_dnd">
+ <item msgid="6509540227356524582">"Ez dago erabilgarri"</item>
+ <item msgid="8589336868985358191">"Desaktibatuta"</item>
+ <item msgid="726072717827778234">"Aktibatuta"</item>
+ </string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"Ez dago erabilgarri"</item>
<item msgid="5044688398303285224">"Desaktibatuta"</item>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 58f35d1..3b214ba 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"میکروفون پیشفرض برای تماسها"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"میکروفون سمعک"</item>
+ <item msgid="8501466270452446450">"میکروفون این تلفن"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"انتخابشده"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"پیرامون"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"چپ"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"وقتی برنامهای را همرسانی میکنید، هر چیزی که در آن برنامه نمایش داده شود یا پخش شود برای <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> قابلمشاهده خواهد بود. درنتیجه مراقب چیزهایی مثل گذرواژهها، جزئیات پرداخت، پیامها، عکسها، و صدا و تصویر باشید."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"همرسانی صفحهنمایش"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g>این گزینه را غیرفعال کرده است"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"توسط برنامه پشتیبانی نمیشود"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"برنامهای را برای همرسانی انتخاب کنید"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"محتوای صفحهنمایش شما پخش شود؟"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"پخش کردن محتوای یک برنامه"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"روشن - براساس چهره"</string>
<string name="inline_done_button" msgid="6043094985588909584">"تمام"</string>
<string name="inline_ok_button" msgid="603075490581280343">"اعمال"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"خاموش کردن"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"بیصدا"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"پیشفرض"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"خودکار"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"نماد راست"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"برای افزودن کاشی، نگه دارید و بکشید"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"برای تغییر دادن ترتیب کاشیها، آنها را نگه دارید و بکشید"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"برای حذف، به اینجا بکشید"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"حداقل به <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> کاشی نیاز دارید"</string>
<string name="qs_edit" msgid="5583565172803472437">"ویرایش"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"موارد دیگر"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"تغییر اندازه کاشی"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"برداشتن کاشی"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"افزودن کاشی به آخرین جایگاه"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"انتقال کاشی"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"افزودن کاشی به جایگاه دلخواه"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"نامشخص"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"همه کاشیها بازنشانی شود؟"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"همه کاشیهای «تنظیمات فوری» به تنظیمات اصلی دستگاه بازنشانی خواهد شد"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>، <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 1b767db..3838303 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -421,10 +421,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Muodosta uusi laitepari klikkaamalla"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Esiasetusta ei voitu muuttaa"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Esiasetus"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Puhelujen oletusmikrofoni"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Kuulolaitteen mikrofoni"</item>
+ <item msgid="8501466270452446450">"Tämän puhelimen mikrofoni"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Valittu"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ympäristö"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Vasen"</string>
@@ -802,8 +803,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Päällä – kasvojen perusteella"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Valmis"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Käytä"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Laita pois päältä"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Äänetön"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Oletus"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automaattinen"</string>
@@ -985,6 +985,8 @@
<string name="right_icon" msgid="1103955040645237425">"Oikea kuvake"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Lisää osioita koskettamalla pitkään ja vetämällä"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Järjestele koskettamalla pitkään ja vetämällä"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Poista vetämällä tähän."</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"<xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> kiekkoa on vähimmäismäärä"</string>
<string name="qs_edit" msgid="5583565172803472437">"Muokkaa"</string>
@@ -1005,6 +1007,10 @@
<string name="other" msgid="429768510980739978">"Muu"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ruudun koko päälle/pois"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"poista kiekko"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"lisää laatta viimeiseen kohtaan"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Siirrä kiekkoa"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Lisää laatta haluttuun kohtaan"</string>
@@ -1580,5 +1586,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Tuntematon"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Nollataanko kaikki laatat?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Kaikki pika-asetuslaatat palautetaan laitteen alkuperäisiin asetuksiin"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 2a315e4..a6395b8 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Cliquez ici pour associer un nouvel appareil"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Impossible de mettre à jour le préréglage"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Préréglage"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Microphone par défaut pour les appels"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Microphone pour prothèse auditive"</item>
+ <item msgid="8501466270452446450">"Le microphone de ce téléphone"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Sélectionné"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Environnement"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Gauche"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Lorsque vous partagez une appli, tout ce qui s\'y affiche ou s\'y joue est visible par <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Par conséquent, soyez prudent avec les mots de passe, les détails du mode de paiement, les messages, les photos et les contenus audio et vidéo."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Partager l\'écran"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> a désactivé cette option"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"Non pris en charge par l\'appli"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Choisir l\'appli à partager"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Diffuser votre écran?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Diffuser une appli"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Activé : en fonction du visage"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Terminé"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Appliquer"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Désactiver"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Mode silencieux"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Par défaut"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatique"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"Icône droite"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Sélectionnez et faites glisser les tuiles pour les ajouter"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Faites glisser les tuiles pour les réorganiser"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Faites glisser les tuiles ici pour les retirer"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Vous avez besoin d\'au moins <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> tuiles"</string>
<string name="qs_edit" msgid="5583565172803472437">"Modifier"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"Autre"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"activer ou désactiver la taille de la tuile"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"retirer la tuile"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"Ajouter une tuile à la dernière position"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Déplacer la tuile"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Ajouter une tuile à la position désirée"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Inconnu"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Réinitialiser toutes les tuiles?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Toutes les tuiles des paramètres rapides seront réinitialisées aux paramètres par défaut de l\'appareil."</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index d7e9d44..97181d6 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Cliquer pour associer un nouvel appareil"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Impossible de mettre à jour les préréglages"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Préréglage"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Micro par défaut pour les appels"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Micro de l\'appareil auditif"</item>
+ <item msgid="8501466270452446450">"Micro de ce téléphone"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Sélectionné"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Sons environnants"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Gauche"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Active - En fonction du visage"</string>
<string name="inline_done_button" msgid="6043094985588909584">"OK"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Appliquer"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Désactiver"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silencieux"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Par défaut"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatique"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Icône droite"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Faites glisser les blocs pour les ajouter"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Faites glisser les blocs pour les réorganiser"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Faites glisser les blocs ici pour les supprimer"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Au minimum <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> tuiles sont nécessaires"</string>
<string name="qs_edit" msgid="5583565172803472437">"Modifier"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Autre"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"activer/désactiver la taille du bloc"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"supprimer le bloc"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"ajouter le bloc à la dernière position"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Déplacer le bloc"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Ajouter le bloc à la position souhaitée"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Inconnu"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Réinitialiser tous les blocs ?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Tous les blocs \"Réglages rapides\" seront réinitialisés aux paramètres d\'origine de l\'appareil"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index f4a4ceb..42f943f 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fai clic para vincular un novo dispositivo"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Non se puido actualizar a configuración predeterminada"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Configuración predeterminada"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Micrófono predefinido para as chamadas"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"O micrófono do audiófono"</item>
+ <item msgid="8501466270452446450">"O micrófono deste teléfono"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Elemento seleccionado"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ambiente"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Esquerdo"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Activada: baseada na cara"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Feito"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Aplicar"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Desactivar"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silenciadas"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Configuración predeterminada"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Icona á dereita"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Mantén premido e arrastra para engadir atallos"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Para reorganizar os atallos, mantenos premidos e arrástraos"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Arrastra o elemento ata aquí para quitalo"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Como mínimo ten que haber <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> mosaicos"</string>
<string name="qs_edit" msgid="5583565172803472437">"Editar"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Outros"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"cambiar o tamaño do atallo"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"quitar atallo"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"engadir o atallo á última posición"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover atallo"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Engadir o atallo á última posición"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Categoría descoñecida"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Queres restablecer todos os atallos?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Restablecerase a configuración orixinal do dispositivo para todos os atallos de Configuración rápida"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 2a8fe31..17b5981 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"કૉલ માટે ડિફૉલ્ટ માઇક્રોફોન"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"સાંભળવામાં મદદ આપતો માઇક્રોફોન"</item>
+ <item msgid="8501466270452446450">"આ ફોનનો માઇક્રોફોન"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"પસંદ કરી છે"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"આસપાસના અવાજો"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ડાબે"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"ચાલુ છે - ચહેરા આધારિત રોટેશન"</string>
<string name="inline_done_button" msgid="6043094985588909584">"થઈ ગયું"</string>
<string name="inline_ok_button" msgid="603075490581280343">"લાગુ કરો"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"બંધ કરો"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"સાઇલન્ટ"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ડિફૉલ્ટ"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ઑટોમૅટિક રીતે"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"જમણું આઇકન"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"ટાઇલ ઉમેરવા માટે તેના પર આંગળી દબાવીને ખેંચો"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"ટાઇલને ફરીથી ગોઠવવા માટે આંગળી દબાવીને ખેંચો"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"દૂર કરવા માટે અહીં ખેંચો"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"તમને ઓછામાં ઓછી <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> ટાઇલની જરૂર છે"</string>
<string name="qs_edit" msgid="5583565172803472437">"ફેરફાર કરો"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"અન્ય"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ટાઇલના કદને ટૉગલ કરો"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ટાઇલ કાઢી નાખો"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"છેલ્લા સ્થાનમાં ટાઇલ ઉમેરો"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ટાઇલ ખસેડો"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"ઇચ્છિત સ્થાનમાં ટાઇલ ઉમેરો"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"અજાણ"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"તમામ ટાઇલ રીસેટ કરીએ?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"તમામ ઝડપી સેટિંગ ટાઇલને ડિવાઇસના ઑરિજિનલ સેટિંગ પર રીસેટ કરવામાં આવશે"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 922794d..0ce73c9 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"कॉल के लिए डिफ़ॉल्ट माइक्रोफ़ोन"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"कान की मशीन के लिए माइक्रोफ़ोन"</item>
+ <item msgid="8501466270452446450">"इस फ़ोन का माइक्रोफ़ोन"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"चुना गया"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"आस-पास का वॉल्यूम"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"बाईं ओर के वॉल्यूम के लिए"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"चालू है - चेहरे की गतिविधि के हिसाब से कैमरे को घुमाने की सुविधा"</string>
<string name="inline_done_button" msgid="6043094985588909584">"हो गया"</string>
<string name="inline_ok_button" msgid="603075490581280343">"लागू करें"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"बंद करें"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"बिना आवाज़ के सूचनाएं दिखाएं"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"डिफ़ॉल्ट"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"अपने-आप"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"दायां आइकॉन"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"टाइल जोड़ने के लिए दबाकर खींचे और छोड़ें"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"टाइल का क्रम फिर से बदलने के लिए उन्हें दबाकर रखें और खींचें"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"हटाने के लिए यहां खींचें और छोड़ें"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"आपके पास कम से कम <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> टाइलें होनी चाहिए"</string>
<string name="qs_edit" msgid="5583565172803472437">"बदलाव करें"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"अन्य"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"टाइल के साइज़ को टॉगल करने के लिए दो बार टैप करें"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"टाइल हटाएं"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"आखिरी जगह पर टाइल जोड़ें"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"टाइल को किसी और पोज़िशन पर ले जाएं"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"अपनी पसंदीदा जगह पर टाइल जोड़ें"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"कोई जानकारी नहीं है"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"क्या सभी टाइल रीसेट करनी हैं?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"क्विक सेटिंग टाइल, डिवाइस की ओरिजनल सेटिंग पर रीसेट हो जाएंगी"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 3213d59..3b2d127 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da biste uparili novi uređaj"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Ažuriranje unaprijed definiranih postavki nije uspjelo"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Unaprijed definirana postavka"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Zadani mikrofon za pozive"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Mikrofon slušnog pomagala"</item>
+ <item msgid="8501466270452446450">"Mikrofon ovog telefona"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Odabrano"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Okruženje"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Lijevo"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Uključeno – na temelju lica"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Gotovo"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Primijeni"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Isključi"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Bešumno"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Zadano"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatski"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Desna ikona"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Zadržite i povucite da biste dodali pločice"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Zadržite i povucite da biste premjestili pločice"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Povucite ovdje za uklanjanje"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Potrebno je barem <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> pločica"</string>
<string name="qs_edit" msgid="5583565172803472437">"Uređivanje"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Ostalo"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"promjenu veličine pločice"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"uklanjanje kartice"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"dodavanje kartice na posljednji položaj"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Premještanje kartice"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Dodajte karticu na željeni položaj"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nepoznato"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Želite li poništiti sve pločice?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Sve pločice Brze postavke vratit će se na izvorne postavke uređaja"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 4327594..b4042be 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kattintson új eszköz párosításához"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Nem sikerült frissíteni a beállításkészletet"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Beállításkészlet"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Alapértelmezett mikrofon a hívásokhoz"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Hallókészülék mikrofonja"</item>
+ <item msgid="8501466270452446450">"A telefon mikrofonja"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Kiválasztva"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Környezet"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Bal"</string>
@@ -982,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Jobb oldali ikon"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Tartsa lenyomva, és húzza a mozaikok hozzáadásához"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Tartsa lenyomva, és húzza a mozaikok átrendezéséhez"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Húzza ide az eltávolításhoz"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Legalább <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> kártya szükséges"</string>
<string name="qs_edit" msgid="5583565172803472437">"Szerkesztés"</string>
@@ -1002,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Egyéb"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"a mozaik méretének módosítása"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"mozaik eltávolításához"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"mozaik hozzáadása az utolsó pozícióhoz"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mozaik áthelyezése"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Mozaik hozzáadása a kívánt pozícióhoz"</string>
@@ -1577,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Ismeretlen"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Visszaállítja az összes mozaikot?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Az összes Gyorsbeállítások mozaik visszaáll az eszköz eredeti beállításaira"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index eaff824..d606213 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Կանխադրված խոսափող զանգերի համար"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Լսողական սարքի խոսափող"</item>
+ <item msgid="8501466270452446450">"Այս հեռախոսի խոսափողը"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Ընտրված է"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Շրջակայք"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Ձախ"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Միաց․ – Դիմաճանաչման հիման վրա"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Փակել"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Կիրառել"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Անջատել"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Անձայն"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Կանխադրված"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Ավտոմատ"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Աջ պատկերակ"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Պահեք և քաշեք՝ սալիկներ ավելացնելու համար"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Պահեք և քաշեք՝ սալիկները վերադասավորելու համար"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Քաշեք այստեղ՝ հեռացնելու համար"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Հարկավոր է առնվազն <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> սալիկ"</string>
<string name="qs_edit" msgid="5583565172803472437">"Փոփոխել"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Այլ"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"փոխեք սալիկի չափը"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"հեռացնել սալիկը"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"ավելացնել սալիկը վերջին դիրքում"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Տեղափոխել սալիկը"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Ավելացնել սալիկը նախընտրած դիրքում"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Անհայտ"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Զրոյացնե՞լ բոլոր սալիկները"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Արագ կարգավորումների բոլոր սալիկները կզրոյացվեն սարքի սկզբնական կարգավորումների համաձայն։"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 763f767..a117599c 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik untuk menyambungkan perangkat baru"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Tidak dapat memperbarui preset"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Mikrofon default untuk panggilan"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Mikrofon alat bantu dengar"</item>
+ <item msgid="8501466270452446450">"Mikrofon ponsel ini"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Dipilih"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Suara sekitar"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Kiri"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Aktif - Berbasis deteksi wajah"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Selesai"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Terapkan"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Nonaktifkan"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Senyap"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Default"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Otomatis"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Ikon kanan"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Tahan dan tarik untuk menambahkan kartu"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Tahan dan tarik untuk menata ulang kartu"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Tarik ke sini untuk menghapus"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Anda membutuhkan setidaknya <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> kartu"</string>
<string name="qs_edit" msgid="5583565172803472437">"Edit"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Lainnya"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"mengubah ukuran kartu"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"menghapus kartu"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"menambahkan kartu ke posisi terakhir"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Pindahkan kartu"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Tambahkan kartu ke posisi yang diinginkan"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Tidak diketahui"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Reset semua kartu?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Semua kartu Setelan Cepat akan direset ke setelan asli perangkat"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 970a913..bd8c7d1 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Smelltu til að para nýtt tæki"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Tókst ekki að uppfæra forstillingu"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Forstilling"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Sjálfgefinn hljóðnemi fyrir símtöl"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Hljóðnemi heyrnartækis"</item>
+ <item msgid="8501466270452446450">"Hljóðnemi þessa síma"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Valið"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Umhverfi"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Vinstri"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Kveikt – út frá andliti"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Lokið"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Nota"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Slökkva"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Hljóðlaust"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Sjálfgefið"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Sjálfvirk"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Tákn til hægri"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Haltu inni og dragðu til að bæta við flísum"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Haltu og dragðu til að endurraða flísum"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Dragðu hingað til að fjarlægja"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Flísarnar mega ekki vera færri en <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
<string name="qs_edit" msgid="5583565172803472437">"Breyta"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Annað"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"breyta stærð reitsins"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"fjarlægja flís"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"bæta reit við síðustu stöðu"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Færa flís"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Bæta reit við óskaða stöðu"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Óþekkt"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Endurstilla alla reiti?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Allir flýtistillingareitir munu endurstillast á upprunalegar stillingar tækisins"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 7323037..7d170a9 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fai clic per accoppiare un nuovo dispositivo"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Impossibile aggiornare preset"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Microfono predefinito per le chiamate"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Microfono dell\'apparecchio acustico"</item>
+ <item msgid="8501466270452446450">"Microfono di questo smartphone"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selezionato"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Audio ambientale"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Sinistra"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Quando condividi un\'app, tutto ciò che viene mostrato o riprodotto al suo interno è visibile a <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Presta quindi attenzione a password, dati di pagamento, messaggi, foto, audio e video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Condividi schermo"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ha disattivato questa opzione"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"Non supportata dall\'app"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Scegli l\'app da condividere"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Trasmettere lo schermo?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Trasmetti un\'app"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"On - Rotazione basata sul viso"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Fine"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Applica"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Disattiva"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Modalità silenziosa"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Modalità predefinita"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatico"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"Icona destra"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Tieni premuto e trascina per aggiungere riquadri"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Tieni premuto e trascina per riordinare i riquadri"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Trascina qui per rimuovere"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Occorrono almeno <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> schede"</string>
<string name="qs_edit" msgid="5583565172803472437">"Modifica"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"Altro"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"attivare/disattivare le dimensioni del riquadro"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"rimuovere il riquadro"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"aggiungere il riquadro all\'ultima posizione"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Sposta riquadro"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Aggiungi il riquadro alla posizione desiderata"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Sconosciuti"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Reimpostare tutti i riquadri?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Tutti i riquadri Impostazioni rapide verranno reimpostati sulle impostazioni originali del dispositivo"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 3ee24a3..cf6d80a 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"פועל – מבוסס על זיהוי פנים"</string>
<string name="inline_done_button" msgid="6043094985588909584">"סיום"</string>
<string name="inline_ok_button" msgid="603075490581280343">"אישור"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"השבתה"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"שקט"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ברירת מחדל"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"באופן אוטומטי"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"סמל ימני"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"יש ללחוץ ולגרור כדי להוסיף לחצנים"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"יש ללחוץ ולגרור כדי לסדר מחדש את כרטיסי המידע"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"אפשר לגרור לכאן כדי להסיר"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"יש צורך ב-<xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> אריחים לפחות"</string>
<string name="qs_edit" msgid="5583565172803472437">"עריכה"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"אחר"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"שינוי גודל הלחצן"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"הסרת הלחצן"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"הוספת הלחצן במיקום האחרון"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"העברת הלחצן"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"הוספת הלחצן במיקום הרצוי"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"לא ידוע"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"לאפס את כל הלחצנים?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"כל הלחצנים ב\'הגדרות מהירות\' יאופסו להגדרות המקוריות של המכשיר"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/tiles_states_strings.xml b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
index 42aa531..4ff8fe4 100644
--- a/packages/SystemUI/res/values-iw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
@@ -56,9 +56,11 @@
<item msgid="5376619709702103243">"כבוי"</item>
<item msgid="4875147066469902392">"פועל"</item>
</string-array>
- <!-- no translation found for tile_states_modes_dnd:0 (6509540227356524582) -->
- <!-- no translation found for tile_states_modes_dnd:1 (8589336868985358191) -->
- <!-- no translation found for tile_states_modes_dnd:2 (726072717827778234) -->
+ <string-array name="tile_states_modes_dnd">
+ <item msgid="6509540227356524582">"לא זמין"</item>
+ <item msgid="8589336868985358191">"מושבת"</item>
+ <item msgid="726072717827778234">"מופעל"</item>
+ </string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"לא זמין"</item>
<item msgid="5044688398303285224">"כבוי"</item>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 1e85479..ca4dfc8 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"通話に使うデフォルトのマイク"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"補聴器のマイク"</item>
+ <item msgid="8501466270452446450">"このスマートフォンのマイク"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"選択中"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"周囲の音"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"左"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"アプリを共有すると、そのアプリで表示または再生される内容が <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> にすべて公開されます。パスワード、お支払い情報、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"画面を共有"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> がこのオプションを無効にしています"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"このアプリではサポートされていません"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"共有するアプリを選択"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"画面をキャストしますか?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"1 つのアプリをキャスト"</string>
@@ -982,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"右アイコン"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"タイルを追加するには長押ししてドラッグ"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"タイルを並べ替えるには長押ししてドラッグ"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"削除するにはここにドラッグ"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"タイルは <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> 個以上必要です"</string>
<string name="qs_edit" msgid="5583565172803472437">"編集"</string>
@@ -1002,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"その他"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"タイルのサイズを切り替えます"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"タイルを削除"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"タイルを最後の位置に追加する"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"タイルを移動"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"タイルを目的の位置に追加する"</string>
@@ -1577,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"不明"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"すべてのタイルをリセットしますか?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"すべてのクイック設定タイルがデバイスの元の設定にリセットされます"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>、<xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 0a25f83..42b9a3c 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"ნაგულისხმევი მიკროფონი ზარებისთვის"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"სმენის მოწყობილობის მიკროფონი"</item>
+ <item msgid="8501466270452446450">"ამ ტელეფონის მიკროფონი"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"არჩეულია"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"გარემოცვა"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"მარცხენა"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"აპის გაზიარებისას <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ხედავს ყველაფერს, რაც ჩანს ან უკრავს ამ აპში. ამიტომ სიფრთხილე გამოიჩინეთ ისეთ ინფორმაციასთან, როგორიცაა პაროლები, გადახდის დეტალები, შეტყობინებები, ფოტოები, აუდიო და ვიდეო."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"ეკრანის გაზიარება"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g>-მა გათიშა ეს ვარიანტი"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"არ არის მხარდაჭერილი აპის მიერ"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"გაზიარებისთვის აპის არჩევა"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"გსურთ თქვენი ეკრანის ტრანსლირება?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"ერთი აპის ტრანსლირება"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"ჩართული — სახის მიხედვით"</string>
<string name="inline_done_button" msgid="6043094985588909584">"მზადაა"</string>
<string name="inline_ok_button" msgid="603075490581280343">"მისადაგება"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"გამორთვა"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"ჩუმი"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ნაგულისხმევი"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ავტომატური"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"მარჯვენა ხატულა"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"ჩავლებით გადაიტანეთ ბლოკების დასამატებლად"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"ფილების გადაწყობა შეგიძლიათ მათი ჩავლებით გადატანით"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"ამოსაშლელად, ჩავლებით გადმოიტანეთ აქ"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"თქვენ გჭირდებათ მოზაიკის <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> ფილა მაინც"</string>
<string name="qs_edit" msgid="5583565172803472437">"რედაქტირება"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"სხვა"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"მოზაიკის ფილის ზომის გადასართავად"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"მოზაიკის ფილის წაშლა"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"მოზაიკის ფილის ბოლო პოზიციაზე დამატება"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"მოზაიკის გადატანა"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"მოზაიკის ფილის სასურველ პოზიციაზე დამატება"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"უცნობი"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"გსურთ ყველა ფილის გადაყენება?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"სწრაფი პარამეტრების ყველა ფილა გადაყენდება მოწყობილობის ორიგინალ პარამეტრებზე"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index c7e8d81..42d2874 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Қоңырауларға арналған әдепкі микрофон"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Есту аппаратының микрофоны"</item>
+ <item msgid="8501466270452446450">"Осы телефонның микрофоны"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Таңдалды"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Айнала"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Сол жақ"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Қосулы – бет негізінде"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Дайын"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Қолдану"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Өшіру"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Үнсіз"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Әдепкі"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматты"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Оң жақ белгіше"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Қажетті элементтерді сүйреп әкеліп қойыңыз"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Элементтердің ретін өзгерту үшін оларды басып тұрып сүйреңіз"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Керексіздерін осы жерге сүйреңіз"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Кемінде <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> бөлшек қажет."</string>
<string name="qs_edit" msgid="5583565172803472437">"Өзгерту"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Басқа"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"бөлшек өлшемін ауыстыру"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"бөлшекті өшіру"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"соңғы позицияға бөлшек қосу"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Бөлшекті жылжыту"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Қалаған позицияға бөлшек қосу"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Белгісіз"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Барлық бөлшекті бастапқы күйге қайтару керек пе?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Барлық \"Жылдам параметрлер\" бөлшегі құрылғының бастапқы параметрлеріне қайтарылады."</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 349e34a..e85b81d 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"មីក្រូហ្វូនលំនាំដើមសម្រាប់ការហៅទូរសព្ទ"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"មីក្រូហ្វូនដែលមានឧបករណ៍ជំនួយការស្ដាប់"</item>
+ <item msgid="8501466270452446450">"មីក្រូហ្វូនរបស់ទូរសព្ទនេះ"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"បានជ្រើសរើស"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"មជ្ឈដ្ឋានជុំវិញ"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ឆ្វេង"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"នៅពេលអ្នកបង្ហាញកម្មវិធីណាមួយ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> មើលឃើញអ្វីគ្រប់យ៉ាងដែលបង្ហាញ ឬចាក់ក្នុងកម្មវិធីនោះ។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះអ្វីៗដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ សារ រូបថត ព្រមទាំងសំឡេង និងវីដេអូ។"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"បង្ហាញអេក្រង់"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> បានបិទជម្រើសនេះ"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"មិនអាចប្រើបានតាមកម្មវិធីនេះទេ"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"ជ្រើសរើសកម្មវិធីដើម្បីចែករំលែក"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"បញ្ជូនអេក្រង់របស់អ្នកឬ?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"បញ្ជូនកម្មវិធីមួយ"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"បើក - ផ្អែកលើមុខ"</string>
<string name="inline_done_button" msgid="6043094985588909584">"រួចរាល់"</string>
<string name="inline_ok_button" msgid="603075490581280343">"ប្រើ"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"បិទ"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"ស្ងាត់"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"លំនាំដើម"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ស្វ័យប្រវត្តិ"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"រូបតំណាងខាងស្ដាំ"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"ចុចឱ្យជាប់ រួចអូសដើម្បីបញ្ចូលប្រអប់"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"ចុចឱ្យជាប់ រួចអូសដើម្បីរៀបចំប្រអប់ឡើងវិញ"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"អូសទីនេះដើម្បីយកចេញ"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"អ្នកត្រូវការប្រអប់យ៉ាងតិច <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
<string name="qs_edit" msgid="5583565172803472437">"កែ"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"ផ្សេងៗ"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"បិទ/បើកទំហំរបស់ប្រអប់"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ដកប្រអប់ចេញ"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"បញ្ចូលប្រអប់ទៅទីតាំងចុងក្រោយ"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ផ្លាស់ទីប្រអប់"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"បញ្ចូលប្រអប់ទៅទីតាំងដែលចង់បាន"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"មិនស្គាល់"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"កំណត់ប្រអប់ទាំងអស់ឡើងវិញឬ?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ប្រអប់ការកំណត់រហ័សទាំងអស់នឹងកំណត់ឡើងវិញទៅការកំណត់ដើមរបស់ឧបករណ៍"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 0fa4c24..3bddcbd 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"ಕರೆಗಳಿಗಾಗಿ ಡೀಫಾಲ್ಟ್ ಮೈಕ್ರೊಫೋನ್"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"ಶ್ರವಣ ಸಾಧನದ ಮೈಕ್ರೊಫೋನ್"</item>
+ <item msgid="8501466270452446450">"ಈ ಫೋನ್ನ ಮೈಕ್ರೊಫೋನ್"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"ಆ್ಯಂಬಿಯೆಂಟ್ ವಾಲ್ಯೂಮ್"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ಎಡ"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"ನೀವು ಆ್ಯಪ್ ಅನ್ನು ಹಂಚಿಕೊಳ್ಳುತ್ತಿರುವಾಗ, ಆ ಆ್ಯಪ್ನಲ್ಲಿ ತೋರಿಸಿರುವ ಅಥವಾ ಪ್ಲೇ ಮಾಡಿದ ಏನಾದರೂ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ಗೆ ಗೋಚರಿಸುತ್ತದೆ. ಆದ್ದರಿಂದ ಪಾಸ್ವರ್ಡ್ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಸಂದೇಶಗಳು, ಫೋಟೋಗಳು ಮತ್ತು ಆಡಿಯೋ ಮತ್ತು ವೀಡಿಯೊದಂತಹ ವಿಷಯಗಳ ಬಗ್ಗೆ ಜಾಗರೂಕರಾಗಿರಿ."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"ಸ್ಕ್ರೀನ್ ಹಂಚಿಕೊಳ್ಳಿ"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಈ ಆಯ್ಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿದೆ"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"ಆ್ಯಪ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"ಹಂಚಿಕೊಳ್ಳಲು ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಬಿತ್ತರಿಸಬೇಕೇ?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"ಒಂದು ಆ್ಯಪ್ ಅನ್ನು ಬಿತ್ತರಿಸಿ"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"ಆನ್ ಆಗಿದೆ - ಮುಖ-ಆಧಾರಿತ"</string>
<string name="inline_done_button" msgid="6043094985588909584">"ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
<string name="inline_ok_button" msgid="603075490581280343">"ಅನ್ವಯಿಸಿ"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"ಆಫ್ ಮಾಡಿ"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"ನಿಶ್ಶಬ್ದ"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ಡೀಫಾಲ್ಟ್"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ಸ್ವಯಂಚಾಲಿತ"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"ಬಲ ಐಕಾನ್"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"ಟೈಲ್ಗಳನ್ನು ಸೇರಿಸಲು ಹೋಲ್ಡ್ ಮಾಡಿ ಮತ್ತು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"ಟೈಲ್ಗಳನ್ನು ಮರುಹೊಂದಿಸಲು ಹೋಲ್ಡ್ ಮಾಡಿ ಮತ್ತು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"ತೆಗೆದುಹಾಕಲು ಇಲ್ಲಿ ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"ನಿಮಗೆ ಕನಿಷ್ಠ <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> ಟೈಲ್ಗಳ ಅಗತ್ಯವಿದೆ"</string>
<string name="qs_edit" msgid="5583565172803472437">"ಎಡಿಟ್"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"ಇತರ"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ಟೈಲ್ ನ ಗಾತ್ರವನ್ನು ಟಾಗಲ್ ಮಾಡಿ"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ಟೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"ಕೊನೆಯ ಸ್ಥಾನಕ್ಕೆ ಟೈಲ್ ಅನ್ನು ಸೇರಿಸಿ"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ಟೈಲ್ ಸರಿಸಿ"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"ಬಯಸಿದ ಸ್ಥಾನಕ್ಕೆ ಟೈಲ್ ಅನ್ನು ಸೇರಿಸಿ"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ಅಪರಿಚಿತ"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"ಎಲ್ಲಾ ಟೈಲ್ಗಳನ್ನು ರೀಸೆಟ್ ಮಾಡಬೇಕೆ?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ಎಲ್ಲಾ ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳ ಟೈಲ್ಗಳನ್ನು ಸಾಧನದ ಮೂಲ ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ರೀಸೆಟ್ ಮಾಡಲಾಗುತ್ತದೆ"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 2b9fc89..970096e 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"통화용 기본 마이크"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"보청기 마이크"</item>
+ <item msgid="8501466270452446450">"이 휴대전화의 마이크"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"선택됨"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"주변 소리"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"왼쪽"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"켜짐 - 얼굴 기준"</string>
<string name="inline_done_button" msgid="6043094985588909584">"완료"</string>
<string name="inline_ok_button" msgid="603075490581280343">"적용"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"사용 중지"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"무음"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"기본값"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"자동"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"오른쪽 아이콘"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"길게 터치하고 드래그하여 타일 추가"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"길게 터치하고 드래그하여 타일 재정렬"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"여기로 드래그하여 삭제"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"<xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>개 이상의 타일이 필요합니다."</string>
<string name="qs_edit" msgid="5583565172803472437">"수정"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"기타"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"타일 크기 전환"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"타일 삭제"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"마지막 위치에 타일 추가"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"타일 이동"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"원하는 위치에 타일 추가"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"알 수 없음"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"모든 타일을 재설정하시겠습니까?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"모든 빠른 설정 타일이 기기의 원래 설정으로 재설정됩니다."</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index b1f6f48..46c67e7 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Чалуулар үчүн демейки микрофон"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Угуу аппаратынын микрофону"</item>
+ <item msgid="8501466270452446450">"Ушул телефондун микрофону"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Тандалды"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Айланадагы үндөр"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Сол"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Колдонмону бөлүшкөндө, андагы нерселер <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> колдонмосуна көрүнөт. Андыктан сырсөздөр, төлөмдүн чоо-жайы, билдирүүлөр, сүрөттөр, аудио жана видеолор менен этият болуңуз."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Экранды бөлүшүү"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> бул параметрди өчүрүп койду"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"Колдонмодо иштебейт"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Бөлүшүү үчүн колдонмо тандоо"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Экранды башка түзмөккө чыгарасызбы?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Бир колдонмону чыгаруу"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Күйүк – Жүздүн негизинде"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Бүттү"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Колдонуу"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Өчүрүү"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Үнсүз"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Демейки"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматтык"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"¨Оңго¨ сүрөтчөсү"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Керектүү элементтерди сүйрөп келиңиз"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Иретин өзгөртүү үчүн кармап туруп, сүйрөңүз"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Өчүрүү үчүн бул жерге сүйрөңүз"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Сизге жок дегенде <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> мозаика керек"</string>
<string name="qs_edit" msgid="5583565172803472437">"Түзөтүү"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"Башка"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"плитканын өлчөмүн которуштуруу"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ыкчам баскычты өчүрүү"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"аягына карта кошуу"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Ыкчам баскычты жылдыруу"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Керектүү жерге карта кошуу"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Белгисиз"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Бардык параметрлерди кайра коесузбу?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Бардык ыкчам параметрлер түзмөктүн баштапкы маанилерине кайтарылат"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index c2a4e8f..961cab3 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"ໄມໂຄຣໂຟນເລີ່ມຕົ້ນສຳລັບການໂທ"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"ໄມໂຄຣໂຟນເຄື່ອງຊ່ວຍຟັງ"</item>
+ <item msgid="8501466270452446450">"ໄມໂຄຣໂຟນຂອງໂທລະສັບເຄື່ອງນີ້"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"ເລືອກແລ້ວ"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"ສຽງແວດລ້ອມ"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ຊ້າຍ"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"ເມື່ອທ່ານແບ່ງປັນແອັບຂອງທ່ານ, ຄົນອື່ນຈະເບິ່ງເຫັນທຸກຢ່າງທີ່ສະແດງ ຫຼື ຫຼິ້ນໃນແອັບໃນ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. ດັ່ງນັ້ນ, ໃຫ້ລະມັດລະວັງສິ່ງຕ່າງໆ ເຊັ່ນ: ລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຂໍ້ຄວາມ, ຮູບພາບ, ພ້ອມທັງສຽງ ແລະ ວິດີໂອ."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"ແບ່ງປັນໜ້າຈໍ"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ປິດການນຳໃຊ້ຕົວເລືອກນີ້ແລ້ວ"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"ບໍ່ຮອງຮັບໂດຍແອັບ"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"ເລືອກແອັບທີ່ຈະແບ່ງປັນ"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"ສົ່ງສັນຍານໜ້າຈໍຂອງທ່ານບໍ?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"ສົ່ງສັນຍານແອັບ 1 ລາຍການ"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"ເປີດ - ອ້າງອີງໃບໜ້າ"</string>
<string name="inline_done_button" msgid="6043094985588909584">"ແລ້ວໆ"</string>
<string name="inline_ok_button" msgid="603075490581280343">"ນຳໃຊ້"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"ປິດ"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"ປິດສຽງ"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ຄ່າເລີ່ມຕົ້ນ"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ອັດຕະໂນມັດ"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"ໄອຄອນຂວາ"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"ກົດຄ້າງໄວ້ແລ້ວລາກເພື່ອເພີ່ມຊ່ອງ"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"ກົດຄ້າງໄວ້ແລ້ວລາກເພື່ອຈັດຮຽງໃໝ່"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"ລາກມາບ່ອນນີ້ເພື່ອລຶບອອກ"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"ທ່ານຍຕ້ອງໃຊ້ຢ່າງໜ້ອຍ <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> ຊ່ອງ"</string>
<string name="qs_edit" msgid="5583565172803472437">"ແກ້ໄຂ"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"ອື່ນໆ"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ສະຫຼັບຂະໜາດຂອງແຜ່ນ"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ລຶບແຜ່ນອອກ"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"ເພີ່ມແຜ່ນໃສ່ຕຳແໜ່ງສຸດທ້າຍ"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ຍ້າຍແຜ່ນ"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"ເພີ່ມແຜ່ນໃສ່ຕຳແໜ່ງທີ່ຕ້ອງການ"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ບໍ່ຮູ້ຈັກ"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"ຣີເຊັດແຜ່ນທັງໝົດບໍ?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ແຜ່ນການຕັ້ງຄ່າດ່ວນທັງໝົດຈະຣີເຊັດເປັນການຕັ້ງຄ່າແບບເກົ່າຂອງອຸປະກອນ"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 48ab51b..46ef5cf 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Spustelėkite, kad susietumėte naują įrenginį"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Išankstinių nustatymų atnaujinti nepavyko"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Išankstiniai nustatymai"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Numatytasis mikrofonas skambučiams"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Klausos aparato mikrofonas"</item>
+ <item msgid="8501466270452446450">"Šio telefono mikrofonas"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Pasirinkta"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Aplinka"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Kairė"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Įjungta – pagal veidą"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Atlikta"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Taikyti"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Išjungti"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Tylūs"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Numatytasis"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatinis"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Piktograma dešinėje"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Jei norite pridėti išklotinių, laikykite nuspaudę ir vilkite"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Norėdami pertvarkyti išklot., laikykite nuspaudę ir vilkite"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Vilkite čia, jei norite pašalinti"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Turi būti bent <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> išklotinės elem."</string>
<string name="qs_edit" msgid="5583565172803472437">"Redaguoti"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Kita"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"perjungti išklotinės elemento dydį"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"pašalintumėte išklotinės elementą"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"pridėti išklotinės elementą paskutinėje pozicijoje"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Perkelti išklotinės elementą"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Pridėti išklotinės elementą norimoje pozicijoje"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nežinoma"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Iš naujo nustatyti visus išklotines elementus?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Visi sparčiųjų nustatymų išklotinės elementai bus iš naujo nustatyti į pradinius įrenginio nustatymus"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index e5c407f..5c052d9 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Noklikšķiniet, lai savienotu pārī jaunu ierīci"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Nevarēja atjaunināt pirmsiestatījumu"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Pirmsiestatījums"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Noklusējuma mikrofons zvaniem"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Dzirdes aparāta mikrofons"</item>
+ <item msgid="8501466270452446450">"Šī tālruņa mikrofons"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Atlasīts"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Apkārtnes skaņas"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Pa kreisi"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Ieslēgta — ar sejas noteikšanu"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Gatavs"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Lietot"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Izslēgt"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Klusums"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Noklusējums"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automātiski"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Ikona labajā pusē"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Lai pievienotu elementus, turiet un velciet tos"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Lai pārkārtotu elementus, turiet un velciet tos"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Lai noņemtu vienumus, velciet tos šeit."</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Nepieciešami vismaz <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> elementi"</string>
<string name="qs_edit" msgid="5583565172803472437">"Rediģēt"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Citi"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"pārslēgt elementa lielumu"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"noņemt elementu"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"pievienotu elementu pēdējā pozīcijā"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Pārvietot elementu"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Pievienot elementu vēlamajā pozīcijā"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nezināma"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vai atiestatīt visus elementus?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Visiem ātro iestatījumu elementiem tiks atiestatīti sākotnējie iestatījumi"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index e546fb5..b8ed62f 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Стандарден микрофон за повици"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Микрофон на слушно помагало"</item>
+ <item msgid="8501466270452446450">"Микрофонот на овој телефон"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Избрано"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Опкружување"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Лево"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Додека споделувате апликација, сѐ што се прикажува или пушта на таа апликација е видливо за <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Затоа, бидете внимателни со работи како лозинки, детали за плаќање, пораки, фотографии и аудио и видео."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Сподели екран"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ја оневозможи опцијава"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"Не е поддржано од апликацијата"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Изберете апликација за споделување"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Да се емитува вашиот екран?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Емитувајте една апликација"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Вклучено - според лице"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Готово"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Примени"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Исклучи"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Безгласно"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Стандардно"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматски"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"Десна икона"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Задржете и влечете за да додадете плочки"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Задржете и влечете за да ги преуредите плочките"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Повлечете тука за да се отстрани"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Потребни ви се најмалку <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> плочки"</string>
<string name="qs_edit" msgid="5583565172803472437">"Измени"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"Друго"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"вклучување/исклучување на големината на плочката"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"отстранување на плочката"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"додајте плочка на последната позиција"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Преместување на плочката"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Додајте плочка на саканата позиција"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Непознато"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Да се ресетираат сите плочки?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Сите плочки на „Брзи поставки“ ќе се ресетираат на првичните поставки на уредот"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 17b1c3d..4b21fa2 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"കോളുകൾക്കുള്ള ഡിഫോൾട്ട് മൈക്രോഫോൺ"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"ശ്രവണ സഹായി മൈക്രോഫോൺ"</item>
+ <item msgid="8501466270452446450">"ഈ ഫോണിന്റെ മൈക്രോഫോൺ"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"തിരഞ്ഞെടുത്തു"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"സറൗണ്ടിംഗ്സ്"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ഇടത്"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"നിങ്ങളുടെ ആപ്പ് പങ്കിടുമ്പോൾ, ആ ആപ്പിൽ കാണിക്കുന്നതോ പ്ലേ ചെയ്യുന്നതോ ആയ എല്ലാ കാര്യങ്ങളും <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> എന്നതിന് ദൃശ്യമാകും. അതിനാൽ പാസ്വേഡുകൾ, പേയ്മെന്റ് വിശദാംശങ്ങൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ, ഓഡിയോ, വീഡിയോ എന്നിവ പോലുള്ള കാര്യങ്ങളിൽ ശ്രദ്ധ പുലർത്തുക."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"സ്ക്രീൻ പങ്കിടുക"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ഈ ഓപ്ഷൻ പ്രവർത്തനരഹിതമാക്കി"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"പങ്കിടാൻ ആപ്പ് തിരഞ്ഞെടുക്കുക"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"നിങ്ങളുടെ സ്ക്രീൻ കാസ്റ്റ് ചെയ്യണോ?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"ഒരു ആപ്പ് കാസ്റ്റ് ചെയ്യുക"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"ഓണാണ് - ഫേസ് ബേസ്ഡ്"</string>
<string name="inline_done_button" msgid="6043094985588909584">"പൂർത്തിയായി"</string>
<string name="inline_ok_button" msgid="603075490581280343">"ബാധകമാക്കുക"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"ഓഫാക്കുക"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"നിശബ്ദം"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ഡിഫോൾട്ട്"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"സ്വയമേവ"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"വലതുവശത്തെ ചിഹ്നം"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"ടൈലുകൾ ചേർക്കാൻ അമർത്തിപ്പിടിച്ച് വലിച്ചിടുക"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"ടൈലുകൾ പുനഃക്രമീകരിക്കാൻ അമർത്തിപ്പിടിച്ച് വലിച്ചിടുക"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"നീക്കംചെയ്യുന്നതിന് ഇവിടെ വലിച്ചിടുക"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"നിങ്ങൾക്ക് ചുരുങ്ങിയത് <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> ടൈലുകളെങ്കിലും വേണം"</string>
<string name="qs_edit" msgid="5583565172803472437">"എഡിറ്റ് ചെയ്യുക"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"മറ്റുള്ളവ"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ടൈലിന്റെ വലുപ്പം മാറ്റുക"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ടൈൽ നീക്കം ചെയ്യുക"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"അവസാന ഭാഗത്ത് ടൈൽ ചേർക്കുക"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ടൈൽ നീക്കുക"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"ഇഷ്ടമുള്ള ഭാഗത്ത് ടൈൽ ചേർക്കുക"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"അജ്ഞാതം"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"എല്ലാ ടൈലുകളും റീസെറ്റ് ചെയ്യണോ?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"എല്ലാ ദ്രുത ക്രമീകരണ ടൈലുകളും ഉപകരണത്തിന്റെ ഒറിജിനൽ ക്രമീകരണത്തിലേക്ക് റീസെറ്റ് ചെയ്യും"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index ba7baf4..abdf331 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Дуудлагад ашиглах өгөгдмөл микрофон"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Сонсголын төхөөрөмжийн микрофон"</item>
+ <item msgid="8501466270452446450">"Энэ утасны микрофон"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Сонгосон"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Орчин тойрон"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Зүүн"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Асаалттай - Царайнд суурилсан"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Болсон"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Ашиглах"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Унтраах"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Чимээгүй"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Өгөгдмөл"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Автомат"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Баруун дүрс тэмдэг"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Хавтан нэмэхийн тулд дараад чирэх"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Хавтангуудыг дахин цэгцлэхийн тулд дараад чирнэ үү"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Устгахын тулд энд зөөнө үү"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Танд хамгийн багадаа <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> хавтан шаардлагатай"</string>
<string name="qs_edit" msgid="5583565172803472437">"Засах"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Бусад"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"хавтангийн хэмжээг асаах/унтраах"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"хавтанг хасна уу"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"хавтанг сүүлийн байрлалд нэмэх"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Хавтанг зөөх"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Хавтанг хүссэн байрлалд нэмэх"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Тодорхойгүй"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Бүх хавтанг шинэчлэх үү?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Шуурхай тохиргооны бүх хавтан төхөөрөмжийн эх тохиргоо руу шинэчлэгдэнэ"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index d6d8e1c..bc80b33 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"कॉलसाठी डीफॉल्ट मायक्रोफोन"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"श्रवणयंत्र मायक्रोफोन"</item>
+ <item msgid="8501466270452446450">"या फोनचा मायक्रोफोन"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"निवडला आहे"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"जवळपासचे"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"डावे"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"तुम्ही अॅप शेअर करता, तेव्हा त्या अॅपमध्ये दाखवल्या किंवा प्ले होणाऱ्या कोणत्याही गोष्टी <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> साठी दृश्यमान असतात. त्यामुळे पासवर्ड, पेमेंट तपशील, मेसेज, फोटो आणि ऑडिओ व व्हिडिओ यांसारख्या गोष्टींबाबत सावधगिरी बाळगा."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"स्क्रीन शेअर करा"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> हा पर्याय बंद केला आहे"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"ॲपद्वारे सपोर्ट नाही"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"शेअर करण्यासाठी अॅप निवडा"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"तुमची स्क्रीन कास्ट करायची आहे का?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"एक अॅप कास्ट करा"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"सुरू - चेहऱ्यावर आधारित"</string>
<string name="inline_done_button" msgid="6043094985588909584">"पूर्ण झाले"</string>
<string name="inline_ok_button" msgid="603075490581280343">"लागू करा"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"बंद करा"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"सायलंट"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"डीफॉल्ट"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ऑटोमॅटिक"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"उजवे आयकन"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"टाइल जोडण्यासाठी धरून ठेवून ड्रॅग करा"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"टाइलची पुनर्रचना करण्यासाठी धरून ठेवून ड्रॅग करा"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"काढण्यासाठी येथे ड्रॅग करा"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"तुम्हाला किमान <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> टाइलची गरज आहे"</string>
<string name="qs_edit" msgid="5583565172803472437">"संपादित करा"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"अन्य"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"टाइलचा आकार टॉगल करा"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"टाइल काढून टाका"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"टाइल शेवटच्या स्थानावर जोडा"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"टाइल हलवा"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"हव्या असलेल्या स्थानावर टाइल जोडा"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"अज्ञात"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"सर्व टाइल रीसेट करायच्या?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"सर्व क्विक सेटिंग्ज टाइल डिव्हाइसच्या मूळ सेटिंग्जवर रीसेट केल्या जातील"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 2aa5068..14c7197 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik untuk menggandingkan peranti baharu"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Tidak dapat mengemaskinikan pratetapan"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Pratetapan"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Mikrofon lalai untuk panggilan"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Mikrofon alat bantu pendengaran"</item>
+ <item msgid="8501466270452446450">"Mikrofon telefon ini"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Dipilih"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Persekitaran"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Kiri"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Apabila anda berkongsi apl, apa-apa sahaja kandungan yang dipaparkan atau dimainkan dalam apl tersebut boleh dilihat oleh <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Oleh hal yang demikian, berhati-hati dengan perkara seperti kata laluan, butiran pembayaran, mesej, foto dan audio serta video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Kongsi skrin"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> telah melumpuhkan pilihan ini"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"Tidak disokong oleh apl"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Pilih apl untuk dikongsi"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Hantar skrin anda?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Hantar satu apl"</string>
@@ -982,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"Ikon kanan"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Tahan dan seret untuk menambahkan jubin"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Tahan dan seret untuk mengatur semula jubin"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Seret ke sini untuk mengalih keluar"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Anda memerlukan sekurang-kurangnya <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> jubin"</string>
<string name="qs_edit" msgid="5583565172803472437">"Edit"</string>
@@ -1002,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"Lain-lain"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"togol saiz jubin"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"alih keluar jubin"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"tambahkan jubin pada kedudukan terakhir"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Alihkan jubin"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Tambahkan jubin pada kedudukan yang dikehendaki"</string>
@@ -1577,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Tidak diketahui"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Tetapkan semula semua jubin?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Semua jubin Tetapan Pantas akan ditetapkan semula kepada tetapan asal peranti"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 70f8259..9849dd9 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"ခေါ်ဆိုမှုများအတွက် မူရင်းမိုက်ခရိုဖုန်း"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"နားကြားကိရိယာ မိုက်ခရိုဖုန်း"</item>
+ <item msgid="8501466270452446450">"ဤဖုန်း၏ မိုက်ခရိုဖုန်း"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"ရွေးထားသည်"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"ဝန်းကျင်အသံ"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ဘယ်"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"ဖွင့် - မျက်နှာအခြေခံ"</string>
<string name="inline_done_button" msgid="6043094985588909584">"ပြီးပြီ"</string>
<string name="inline_ok_button" msgid="603075490581280343">"အသုံးပြုရန်"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"ပိတ်ရန်"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"အသံပိတ်ရန်"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"မူလ"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"အလိုအလျောက်"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"လက်ယာသင်္ကေတ"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"အကွက်များထည့်ရန် ဖိဆွဲပါ"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"အကွက်ငယ်များ ပြန်စီစဉ်ရန် ဖိပြီးဆွဲပါ"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"ဖယ်ရှားရန် ဤနေရာသို့ဖိဆွဲပါ"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"အနည်းဆုံး <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> ကွက် ရှိရမည်"</string>
<string name="qs_edit" msgid="5583565172803472437">"တည်းဖြတ်ရန်"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"အခြား"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"အကွက်ငယ်၏ အရွယ်အစားကို ပြောင်းရန်"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"အကွက်ငယ်ကို ဖယ်ရှားရန်"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"နောက်ဆုံးနေရာတွင် အကွက်ငယ် ထည့်ရန်"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"အကွက်ငယ်ကို ရွှေ့ရန်"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"ဆန္ဒရှိရာ နေရာတွင် အကွက်ငယ် ထည့်ရန်"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"အမျိုးအမည်မသိ"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"အကွက်ငယ်အားလုံးကို ပြင်ဆင်သတ်မှတ်မလား။"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"အမြန်ဆက်တင်များ အကွက်ငယ်အားလုံးကို စက်ပစ္စည်း၏ မူရင်းဆက်တင်များသို့ ပြင်ဆင်သတ်မှတ်ပါမည်"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>၊ <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 82aeb65..62c018b 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klikk for å koble til en ny enhet"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Kunne ikke oppdatere forhåndsinnstillingen"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Forhåndsinnstilling"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Standardmikrofonen for anrop"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Mikrofonen i høreapparatet"</item>
+ <item msgid="8501466270452446450">"Mikrofonen i denne telefonen"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Valgt"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Omgivelser"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Venstre"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"På – ansiktsbasert"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Ferdig"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Bruk"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Slå av"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Lydløs"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Standard"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatisk"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Høyre-ikon"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Hold og dra for å legge til brikker"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Hold og dra for å flytte på rutene"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Dra hit for å fjerne"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Du trenger minst <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> infobrikker"</string>
<string name="qs_edit" msgid="5583565172803472437">"Endre"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Annet"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"bytt størrelse på brikken"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"fjerne infobrikken"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"legge til en brikke på den siste posisjonen"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Flytt infobrikken"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Legg til brikken på ønsket posisjon"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Ukjent"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vil du tilbakestille alle brikkene?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alle brikker for hurtiginnstillinger tilbakestilles til enhetens opprinnelige innstillinger"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 78164a2..c101638 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"कलका लागि प्रयोग गरिने डिफल्ट माइक्रोफोन"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"श्रवण यन्त्रको माइक्रोफोन"</item>
+ <item msgid="8501466270452446450">"यो फोनको माइक्रोफोन"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"चयन गरिएको छ"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"वरपरका आवाज"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"बायाँ"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"अन छ - अनुहारमा आधारित"</string>
<string name="inline_done_button" msgid="6043094985588909584">"सम्पन्न भयो"</string>
<string name="inline_ok_button" msgid="603075490581280343">"लागू गर्नुहोस्"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"अफ गर्नुहोस्"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"साइलेन्ट"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"डिफल्ट"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"स्वचालित"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"दायाँतिरको आइकन"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"टाइलहरू थप्न होल्ड गरी ड्र्याग गर्नुहोस्"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"टाइलहरू पुनः क्रमबद्ध गर्न होल्ड गरी ड्र्याग गर्नुहोस्"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"हटाउनका लागि यहाँ तान्नुहोस्"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"तपाईंलाई कम्तीमा <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> वटा टाइल चाहिन्छ"</string>
<string name="qs_edit" msgid="5583565172803472437">"सम्पादन गर्नुहोस्"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"अन्य"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"टाइलको आकार टगल गर्नुहोस्"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"टाइल हटाउनुहोस्"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"अन्तिम स्थानमा टाइल हाल्नुहोस्"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"टाइल सार्नुहोस्"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"आफूले चाहेको स्थानमा टाइल हाल्नुहोस्"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"अज्ञात"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"सबै टाइलहरू रिसेट गर्ने हो?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"द्रुत सेटिङका सबै टाइलहरू रिसेट गरी डिभाइसका मूल सेटिङ लागू गरिने छन्"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index fe6f348..82d29de6 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik om nieuw apparaat te koppelen"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Kan voorinstelling niet updaten"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Voorinstelling"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Standaardmicrofoon voor gesprekken"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Microfoon voor hoortoestel"</item>
+ <item msgid="8501466270452446450">"Microfoon van deze telefoon"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Geselecteerd"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Omgevingsgeluid"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Links"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Aan: op basis van gezicht"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Klaar"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Toepassen"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Uitzetten"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Stil"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Standaard"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatisch"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Icoon rechts"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Houd een tegel ingedrukt en sleep om die toe te voegen"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Houd een tegel ingedrukt en sleep om die te verplaatsen"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Sleep hier naartoe om te verwijderen"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Je hebt minimaal <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> tegels nodig"</string>
<string name="qs_edit" msgid="5583565172803472437">"Bewerken"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Overig"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"het formaat van de tegel schakelen"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"tegel verwijderen"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"tegel toevoegen op de laatste positie"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Tegel verplaatsen"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Tegel toevoegen op gewenste positie"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Onbekend"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Alle tegels resetten?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alle tegels voor Snelle instellingen worden teruggezet naar de oorspronkelijke instellingen van het apparaat"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index fa16f28..a93508f 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"କଲ ପାଇଁ ଡିଫଲ୍ଟ ମାଇକ୍ରୋଫୋନ"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"ଶ୍ରବଣ ଯନ୍ତ୍ରର ମାଇକ୍ରୋଫୋନ"</item>
+ <item msgid="8501466270452446450">"ଏହି ଫୋନର ମାଇକ୍ରୋଫୋନ"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"ଚୟନ କରାଯାଇଛି"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"ପରିପାର୍ଶ୍ୱ"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ବାମ"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"ଆପଣ ଏକ ଆପ ସେୟାର କରିବା ସମୟରେ, ସେହି ଆପରେ ଦେଖାଯାଉଥିବା କିମ୍ବା ପ୍ଲେ ହେଉଥିବା ସବୁକିଛି <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>କୁ ଦେଖାଯାଏ। ତେଣୁ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ମେସେଜ, ଫଟୋ ଏବଂ ଅଡିଓ ଓ ଭିଡିଓ ପରି ବିଷୟଗୁଡ଼ିକ ପ୍ରତି ସତର୍କ ରୁହନ୍ତୁ।"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"ସ୍କ୍ରିନ ସେୟାର କରନ୍ତୁ"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଏହି ବିକଳ୍ପକୁ ଅକ୍ଷମ କରିଛି"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"ଆପରେ ସପୋର୍ଟ କରୁନାହିଁ"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"ସେୟାର କରିବାକୁ ଆପ ବାଛନ୍ତୁ"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"ଆପଣଙ୍କ ସ୍କ୍ରିନକୁ କାଷ୍ଟ କରିବେ?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"ଗୋଟିଏ ଆପକୁ କାଷ୍ଟ କରନ୍ତୁ"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"ଚାଲୁ ଅଛି - ଫେସ-ଆଧାରିତ"</string>
<string name="inline_done_button" msgid="6043094985588909584">"ହୋଇଗଲା"</string>
<string name="inline_ok_button" msgid="603075490581280343">"ଲାଗୁ କରନ୍ତୁ"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"ନୀରବ"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ଡିଫଲ୍ଟ"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ସ୍ୱଚାଳିତ"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"ଡାହାଣ ଆଇକନ୍"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"ଟାଇଲ୍ ଯୋଗ କରିବା ପାଇଁ ଦାବିଧରି ଡ୍ରାଗ କରନ୍ତୁ"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"ଟାଇଲ ପୁଣି ସଜାଇବାକୁ ଦାବିଧରି ଟାଣନ୍ତୁ"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"ବାହାର କରିବାକୁ ଏଠାକୁ ଡ୍ରାଗ୍ କରନ୍ତୁ"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"ଆପଣଙ୍କର ଅତିକମ୍ରେ <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>ଟି ଟାଇଲ୍ ଆବଶ୍ୟକ"</string>
<string name="qs_edit" msgid="5583565172803472437">"ଏଡିଟ କରନ୍ତୁ"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"ଅନ୍ୟ"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ଟାଇଲର ସାଇଜକୁ ଟୋଗଲ କରନ୍ତୁ"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ଟାଇଲ୍ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"ଶେଷ ପୋଜିସନରେ ଟାଇଲ ଯୋଗ କରିବା"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ଟାଇଲ୍ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"ଇଚ୍ଛିତ ପୋଜିସନରେ ଟାଇଲ ଯୋଗ କରନ୍ତୁ"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ଅଜଣା"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"ସମସ୍ତ ଟାଇଲକୁ ରିସେଟ କରିବେ?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ସମସ୍ତ କୁଇକ ସେଟିଂସ ଟାଇଲ ଡିଭାଇସର ମୂଳ ସେଟିଂସରେ ରିସେଟ ହୋଇଯିବ"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/tiles_states_strings.xml b/packages/SystemUI/res/values-or/tiles_states_strings.xml
index 37d3c95..ac4d3b3 100644
--- a/packages/SystemUI/res/values-or/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-or/tiles_states_strings.xml
@@ -56,9 +56,11 @@
<item msgid="5376619709702103243">"ବନ୍ଦ ଅଛି"</item>
<item msgid="4875147066469902392">"ଚାଲୁ ଅଛି"</item>
</string-array>
- <!-- no translation found for tile_states_modes_dnd:0 (6509540227356524582) -->
- <!-- no translation found for tile_states_modes_dnd:1 (8589336868985358191) -->
- <!-- no translation found for tile_states_modes_dnd:2 (726072717827778234) -->
+ <string-array name="tile_states_modes_dnd">
+ <item msgid="6509540227356524582">"ଅନୁପଲବ୍ଧ"</item>
+ <item msgid="8589336868985358191">"ବନ୍ଦ ଅଛି"</item>
+ <item msgid="726072717827778234">"ଚାଲୁ ଅଛି"</item>
+ </string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"ଉପଲବ୍ଧ ନାହିଁ"</item>
<item msgid="5044688398303285224">"ବନ୍ଦ ଅଛି"</item>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 98d56e3..0e23730 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"ਕਾਲਾਂ ਲਈ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਮਾਈਕ੍ਰੋਫ਼ੋਨ"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"ਸੁਣਨ ਦੇ ਸਾਧਨ ਦਾ ਮਾਈਕ੍ਰੋਫ਼ੋਨ"</item>
+ <item msgid="8501466270452446450">"ਇਸ ਫ਼ੋਨ ਦਾ ਮਾਈਕ੍ਰੋਫ਼ੋਨ"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"ਚੁਣਿਆ ਗਿਆ"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"ਆਲੇ-ਦੁਆਲੇ"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ਖੱਬੇ"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"ਕਿਸੇ ਐਪ ਨੂੰ ਸਾਂਝਾ ਕਰਨ ਦੌਰਾਨ, ਉਸ ਐਪ \'ਤੇ ਦਿਖ ਰਹੀ ਜਾਂ ਚਲਾਈ ਗਈ ਹਰੇਕ ਚੀਜ਼ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ਨੂੰ ਦਿਖਣਯੋਗ ਹੁੰਦੀ ਹੈ। ਇਸ ਲਈ ਪਾਸਵਰਡਾਂ, ਭੁਗਤਾਨ ਵੇਰਵਿਆਂ, ਸੁਨੇਹਿਆਂ, ਫ਼ੋਟੋਆਂ ਅਤੇ ਆਡੀਓ ਅਤੇ ਵੀਡੀਓ ਵਰਗੀਆਂ ਚੀਜ਼ਾਂ ਵਾਸਤੇ ਸਾਵਧਾਨ ਰਹੋ।"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"ਸਕ੍ਰੀਨ ਸਾਂਝੀ ਕਰੋ"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੇ ਇਸ ਵਿਕਲਪ ਨੂੰ ਬੰਦ ਕਰ ਦਿੱਤਾ ਹੈ"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"ਐਪ ਵੱਲੋਂ ਸਮਰਥਿਤ ਨਹੀਂ"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"ਸਾਂਝਾ ਕਰਨ ਲਈ ਐਪ ਚੁਣੋ"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"ਕੀ ਸਕ੍ਰੀਨ ਨੂੰ ਕਾਸਟ ਕਰਨਾ ਹੈ?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"ਇੱਕ ਐਪ ਨੂੰ ਕਾਸਟ ਕਰੋ"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"ਚਾਲੂ ਹੈ - ਚਿਹਰਾ-ਆਧਾਰਿਤ"</string>
<string name="inline_done_button" msgid="6043094985588909584">"ਹੋ ਗਿਆ"</string>
<string name="inline_ok_button" msgid="603075490581280343">"ਲਾਗੂ ਕਰੋ"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"ਬੰਦ ਕਰੋ"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"ਸ਼ਾਂਤ"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ਸਵੈਚਲਿਤ"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"ਸੱਜਾ ਪ੍ਰਤੀਕ"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"ਟਾਇਲਾਂ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਫੜ੍ਹ ਕੇ ਘਸੀਟੋ"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"ਟਾਇਲਾਂ ਨੂੰ ਮੁੜ-ਵਿਵਸਥਿਤ ਕਰਨ ਲਈ ਫੜ੍ਹ ਕੇ ਘਸੀਟੋ"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"ਹਟਾਉਣ ਲਈ ਇੱਥੇ ਘਸੀਟੋ"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"ਤੁਹਾਨੂੰ ਘੱਟੋ-ਘੱਟ <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> ਟਾਇਲਾਂ ਦੀ ਲੋੜ ਪਵੇਗੀ"</string>
<string name="qs_edit" msgid="5583565172803472437">"ਸੰਪਾਦਨ ਕਰੋ"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"ਹੋਰ"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ਟਾਇਲ ਦੇ ਆਕਾਰ ਨੂੰ ਟੌਗਲ ਕਰੋ"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ਟਾਇਲ ਹਟਾਓ"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"ਪਿਛਲੀ ਸਥਿਤੀ \'ਤੇ ਟਾਇਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ਟਾਇਲ ਨੂੰ ਲਿਜਾਓ"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"ਮਨਪਸੰਦ ਸਥਿਤੀ \'ਤੇ ਟਾਇਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ਅਗਿਆਤ"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"ਕੀ ਸਾਰੀਆਂ ਟਾਇਲਾਂ ਨੂੰ ਰੀਸੈੱਟ ਕਰਨਾ ਹੈ?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ਸਾਰੀਆਂ ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਟਾਇਲਾਂ ਡੀਵਾਈਸ ਦੀਆਂ ਮੂਲ ਸੈਟਿੰਗਾਂ \'ਤੇ ਰੀਸੈੱਟ ਹੋ ਜਾਣਗੀਆਂ"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index cdf30a9..ed96417 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknij, aby sparować nowe urządzenie"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Nie udało się zaktualizować gotowego ustawienia"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Gotowe ustawienie"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Domyślny mikrofon do połączeń"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Mikrofon aparatu słuchowego"</item>
+ <item msgid="8501466270452446450">"Mikrofon tego telefonu"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Wybrano"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Otoczenie"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Po lewej"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Włączono – na podstawie twarzy"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Gotowe"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Zastosuj"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Wyłącz"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Ciche"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Domyślne"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatycznie"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Prawa ikona"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Aby dodać kafelki, przytrzymaj je i przeciągnij"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Aby przestawić kafelki, przytrzymaj je i przeciągnij"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Przeciągnij tutaj, by usunąć"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Minimalna liczba kafelków to <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
<string name="qs_edit" msgid="5583565172803472437">"Edytuj"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Inne"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"przełącz rozmiar kafelka"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"usunąć kartę"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"dodaj kafelek do ostatniej pozycji"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Przenieś kartę"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Dodaj kafelek do wybranej pozycji"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nieznane"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Zresetować wszystkie kafelki?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Wszystkie kafelki Szybkich ustawień zostaną zresetowane do oryginalnych ustawień urządzenia"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/tiles_states_strings.xml b/packages/SystemUI/res/values-pl/tiles_states_strings.xml
index abc1867..ebd89d2 100644
--- a/packages/SystemUI/res/values-pl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pl/tiles_states_strings.xml
@@ -56,9 +56,11 @@
<item msgid="5376619709702103243">"Wyłączone"</item>
<item msgid="4875147066469902392">"Włączone"</item>
</string-array>
- <!-- no translation found for tile_states_modes_dnd:0 (6509540227356524582) -->
- <!-- no translation found for tile_states_modes_dnd:1 (8589336868985358191) -->
- <!-- no translation found for tile_states_modes_dnd:2 (726072717827778234) -->
+ <string-array name="tile_states_modes_dnd">
+ <item msgid="6509540227356524582">"Niedostępny"</item>
+ <item msgid="8589336868985358191">"Wyłączony"</item>
+ <item msgid="726072717827778234">"Włączony"</item>
+ </string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"Niedostępny"</item>
<item msgid="5044688398303285224">"Wyłączona"</item>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index d9bbaf0..ab06ef8 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para parear o novo dispositivo"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Não foi possível atualizar a predefinição"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Predefinição"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Microfone padrão para ligações"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Microfone para aparelhos auditivos"</item>
+ <item msgid="8501466270452446450">"O microfone deste smartphone"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selecionado"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Som ambiente"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Lado esquerdo"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Ativada (reconhecimento facial)"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Concluído"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Aplicar"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Desativar"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silenciosas"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Padrão"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Ícone à direita"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Mantenha pressionado e arraste para adicionar blocos"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Para reorganizar, toque no bloco sem soltar e arraste"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Arraste aqui para remover"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"É preciso haver pelo menos <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> blocos"</string>
<string name="qs_edit" msgid="5583565172803472437">"Editar"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Outros"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"alternar o tamanho do bloco"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remover o bloco"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"adicionar o bloco à última posição"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover bloco"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Adicionar o bloco à posição desejada"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconhecidos"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Redefinir todos os blocos?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Todos os blocos \"Configurações rápidas\" serão redefinidos para as configurações originais do dispositivo"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
index 30e45fe..28ea47f 100644
--- a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
@@ -56,9 +56,11 @@
<item msgid="5376619709702103243">"Desativado"</item>
<item msgid="4875147066469902392">"Ativado"</item>
</string-array>
- <!-- no translation found for tile_states_modes_dnd:0 (6509540227356524582) -->
- <!-- no translation found for tile_states_modes_dnd:1 (8589336868985358191) -->
- <!-- no translation found for tile_states_modes_dnd:2 (726072717827778234) -->
+ <string-array name="tile_states_modes_dnd">
+ <item msgid="6509540227356524582">"Indisponível"</item>
+ <item msgid="8589336868985358191">"Desativado"</item>
+ <item msgid="726072717827778234">"Ativado"</item>
+ </string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"Indisponível"</item>
<item msgid="5044688398303285224">"Apagada"</item>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 913f5b3..94dbc44 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para sincronizar um novo dispositivo"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Não foi possível atualizar a predefinição"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Predefinição"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Microfone predefinido para chamadas"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Microfone do aparelho auditivo"</item>
+ <item msgid="8501466270452446450">"Microfone deste telemóvel"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selecionado"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ambiente"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Esquerda"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Quando está a partilhar uma app, tudo o que é mostrado ou reproduzido nessa app é visível para a app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Por isso, tenha cuidado com, por exemplo, palavras-passe, detalhes de pagamento, mensagens, fotos, áudio e vídeo."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Partilhar ecrã"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> desativou esta opção"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"Não compatível com a app"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Escolha uma app para partilhar"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Transmitir o ecrã?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Transmitir uma app"</string>
@@ -982,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"Ícone direito"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Toque sem soltar e arraste para reorganizar os mosaicos"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Toque sem soltar e arraste para reorganizar os mosaicos"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Arrastar para aqui para remover"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Necessita de, pelo menos, <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> cartões"</string>
<string name="qs_edit" msgid="5583565172803472437">"Editar"</string>
@@ -1002,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"Outro"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ativar/desativar o tamanho do mosaico"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remover o cartão"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"adicionar o mosaico à última posição"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover cartão"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Adicionar mosaico à posição pretendida"</string>
@@ -1577,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconhecido"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Repor todos os mosaicos?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Todos os mosaicos de Definições rápidas vão ser repostos para as definições originais do dispositivo"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index d9bbaf0..ab06ef8 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para parear o novo dispositivo"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Não foi possível atualizar a predefinição"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Predefinição"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Microfone padrão para ligações"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Microfone para aparelhos auditivos"</item>
+ <item msgid="8501466270452446450">"O microfone deste smartphone"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selecionado"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Som ambiente"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Lado esquerdo"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Ativada (reconhecimento facial)"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Concluído"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Aplicar"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Desativar"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silenciosas"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Padrão"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Ícone à direita"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Mantenha pressionado e arraste para adicionar blocos"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Para reorganizar, toque no bloco sem soltar e arraste"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Arraste aqui para remover"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"É preciso haver pelo menos <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> blocos"</string>
<string name="qs_edit" msgid="5583565172803472437">"Editar"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Outros"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"alternar o tamanho do bloco"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remover o bloco"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"adicionar o bloco à última posição"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover bloco"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Adicionar o bloco à posição desejada"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconhecidos"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Redefinir todos os blocos?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Todos os blocos \"Configurações rápidas\" serão redefinidos para as configurações originais do dispositivo"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/tiles_states_strings.xml b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
index 30e45fe..28ea47f 100644
--- a/packages/SystemUI/res/values-pt/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
@@ -56,9 +56,11 @@
<item msgid="5376619709702103243">"Desativado"</item>
<item msgid="4875147066469902392">"Ativado"</item>
</string-array>
- <!-- no translation found for tile_states_modes_dnd:0 (6509540227356524582) -->
- <!-- no translation found for tile_states_modes_dnd:1 (8589336868985358191) -->
- <!-- no translation found for tile_states_modes_dnd:2 (726072717827778234) -->
+ <string-array name="tile_states_modes_dnd">
+ <item msgid="6509540227356524582">"Indisponível"</item>
+ <item msgid="8589336868985358191">"Desativado"</item>
+ <item msgid="726072717827778234">"Ativado"</item>
+ </string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"Indisponível"</item>
<item msgid="5044688398303285224">"Apagada"</item>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 906ee09..0d16f35 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Dă clic pentru a asocia un nou dispozitiv"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Nu s-a putut actualiza presetarea"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Presetare"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Microfon prestabilit pentru apeluri"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Microfonul aparatului auditiv"</item>
+ <item msgid="8501466270452446450">"Microfonul acestui telefon"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Selectat"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Împrejurimi"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Stânga"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Activată – În funcție de chip"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Gata"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Aplică"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Dezactivează"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silențios"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Prestabilite"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automat"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Pictograma din dreapta"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Ține apăsat și trage pentru a adăuga carduri"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Ține apăsat și trage pentru a rearanja cardurile"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Trage aici pentru a elimina"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Ai nevoie de cel puțin <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> carduri"</string>
<string name="qs_edit" msgid="5583565172803472437">"Editează"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Altele"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"comută dimensiunea cardului"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"elimină cardul"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"adaugă cardul în ultima poziție"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mută cardul"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Adaugă cardul în poziția dorită"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Necunoscută"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Resetezi toate cardurile?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Toate cardurile Setări rapide se vor reseta la setările inițiale ale dispozitivului"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index ee9d755..442b16e 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Микрофон по умолчанию для вызовов"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Микрофон слухового аппарата"</item>
+ <item msgid="8501466270452446450">"Встроенный микрофон"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Выбрано"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Окружающие звуки"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Левый"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"При показе приложения все, что в нем происходит, будет видно в приложении \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\". Поэтому будьте осторожны с паролями, сведениями о способах оплаты, сообщениями, фотографиями, аудио- и видеозаписями."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Показать экран"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" отключило эту возможность"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"Приложение не поддерживает эту функцию"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Выбор приложения для демонстрации"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Начать трансляцию экрана?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Транслировать одно приложение"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Включить (на основе распознавания лиц)"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Готово"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Применить"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Отключить"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Без звука"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"По умолчанию"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматически"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"Значок \"Вправо\""</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Чтобы добавить элементы, перетащите их."</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Чтобы изменить порядок элементов, перетащите их."</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Чтобы удалить, перетащите сюда"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Должно остаться не менее <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> элементов"</string>
<string name="qs_edit" msgid="5583565172803472437">"Изменить"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"Другое"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"изменить размер параметра"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"удалить панель"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"добавить параметр в конец"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Переместить панель"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Выбрать, куда добавить параметр"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Неизвестно"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Сбросить все параметры?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Для всех параметров быстрых настроек будут восстановлены значения по умолчанию."</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 583d884..074ef93 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"ඇමතුම් සඳහා පෙරනිමි මයික්රෆෝනය"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"ශ්රවණාධාර මයික්රෆෝනය"</item>
+ <item msgid="8501466270452446450">"මෙම දුරකථනයේ මයික්රෆෝනය"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"තෝරන ලදි"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"වටපිටාව"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"වම"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"ඔබ යෙදුමක් බෙදා ගන්නා විට, එම යෙදුමේ පෙන්වන හෝ වාදනය කරන ඕනෑම දෙයක් <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> වෙත දෘශ්යමාන වේ. ඒ නිසා මුරපද, ගෙවීම් විස්තර, පණිවිඩ, ඡායාරූප, සහ ශ්රව්ය සහ දෘශ්ය වැනි දේවල් පිළිබඳ ප්රවේශම් වන්න."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"තිරය බෙදා ගන්න"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> මෙම විකල්පය අබල කර ඇත"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"යෙදුම මඟින් සහාය නොදක්වයි"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"බෙදා ගැනීමට යෙදුම තෝරන්න"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"ඔබේ තිරය විකාශය කරන්න ද?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"එක් යෙදුමක් විකාශය කරන්න"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"ක්රියාත්මකයි - මුහුණ-පදනම්ව"</string>
<string name="inline_done_button" msgid="6043094985588909584">"නිමයි"</string>
<string name="inline_ok_button" msgid="603075490581280343">"යොදන්න"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"ක්රියාවිරහිත කරන්න"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"නිහඬ"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"පෙරනිමි"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ස්වයංක්රිය"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"දකුණු නිරූපකය"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"ටයිල් එක් කිරීමට අල්ලාගෙන සිට අදින්න"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"ටයිල් නැවත සකස් කිරීමට අල්ලාගෙන සිට අදින්න"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"ඉවත් කිරීමට මෙතැනට අදින්න"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"ඔබ අවම වශයෙන් ටයිල් <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> ක් අවශ්ය වෙයි"</string>
<string name="qs_edit" msgid="5583565172803472437">"සංස්කරණය"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"වෙනත්"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ටයිල් එකේ ප්රමාණය මාරු කරන්න"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ටයිල් ඉවත් කරන්න"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"ටයිල් එක අවසාන ස්ථානයට එක් කරන්න"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ටයිල් ගෙන යන්න"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"අපේක්ෂිත ස්ථානයට ටයිල් එක එක් කරන්න"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"නොදනී"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"සියලු ටයිල් නැවත සකසන්න ද?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"සියලු ඉක්මන් සැකසීම් ටයිල් උපාංගයේ මුල් සැකසීම් වෙත නැවත සකසනු ඇත"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/tiles_states_strings.xml b/packages/SystemUI/res/values-si/tiles_states_strings.xml
index 7eeaefd..1b5cf74 100644
--- a/packages/SystemUI/res/values-si/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-si/tiles_states_strings.xml
@@ -56,9 +56,11 @@
<item msgid="5376619709702103243">"අක්රියයි"</item>
<item msgid="4875147066469902392">"සක්රියයි"</item>
</string-array>
- <!-- no translation found for tile_states_modes_dnd:0 (6509540227356524582) -->
- <!-- no translation found for tile_states_modes_dnd:1 (8589336868985358191) -->
- <!-- no translation found for tile_states_modes_dnd:2 (726072717827778234) -->
+ <string-array name="tile_states_modes_dnd">
+ <item msgid="6509540227356524582">"නොමැත"</item>
+ <item msgid="8589336868985358191">"ක්රියාවිරහිතයි"</item>
+ <item msgid="726072717827778234">"ක්රියාත්මකයි"</item>
+ </string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"නොමැත"</item>
<item msgid="5044688398303285224">"අක්රියයි"</item>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 206e10c..ae82811 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknutím spárujete nové zariadenie"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Predvoľbu sa nepodarilo aktualizovať"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Predvoľba"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Predvolený mikrofón pre hovory"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Mikrofón načúvadla"</item>
+ <item msgid="8501466270452446450">"Mikrofón tohto telefónu"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Vybrané"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Okolie"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Vľavo"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Zapnuté – podľa tváre"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Hotovo"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Použiť"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Vypnúť"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Tiché"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Predvolené"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automaticky"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Pravá ikona"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Pridržaním a presunutím pridáte karty"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Karty môžete usporiadať pridržaním a presunutím"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Presunutím sem odstránite"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Minimálny počet vyžadovaných dlaždíc: <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
<string name="qs_edit" msgid="5583565172803472437">"Upraviť"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Ďalšie"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"prepnúť veľkosť karty"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"odstrániť kartu"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"pridáte kartu na poslednú pozíciu"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Presunúť kartu"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Pridať kartu na požadovanú pozíciu"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Neznáme"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Chcete resetovať všetky karty?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Všetky karty rýchlych nastavení sa resetujú na pôvodné nastavenia zariadenia"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 1c1ff03..c06b387 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite za seznanitev nove naprave"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Prednastavljenih vrednosti ni bilo mogoče posodobiti"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Prednastavljeno"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Privzeti mikrofon za klice"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Mikrofon slušnega aparata"</item>
+ <item msgid="8501466270452446450">"Mikrofon tega telefona"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Izbrano"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Okolica"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Levo"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Pri deljenju aplikacije je aplikaciji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vidno vse, kar je prikazano ali predvajano v tej aplikaciji. Zato bodite previdni z gesli, podatki za plačilo, sporočili, fotografijami ter z zvokom in videom."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Deli zaslon"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je onemogočila to možnost"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"Aplikacija ne podpira funkcije"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Izbira aplikacije za deljenje"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Želite predvajati vsebino zaslona?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Predvajanje ene aplikacije"</string>
@@ -982,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"Desna ikona"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Držite in povlecite, da dodate ploščice."</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Držite in povlecite, da prerazporedite ploščice."</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Če želite odstraniti, povlecite sem"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Imeti morate vsaj toliko ploščic: <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
<string name="qs_edit" msgid="5583565172803472437">"Uredi"</string>
@@ -1002,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"Drugo"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"preklop velikosti ploščice"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"odstranitev ploščice"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"dodajanje ploščice na zadnji položaj"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Premik ploščice"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Dodaj ploščico na želeno mesto"</string>
@@ -1577,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Neznano"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Želite ponastaviti vse ploščice?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Vse ploščice v hitrih nastavitvah bodo ponastavljene na prvotne nastavitve naprave."</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index c68e7a8..88f8695 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliko për të çiftuar një pajisje të re"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Paravendosja nuk mund të përditësohej"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Paravendosja"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Mikrofoni i parazgjedhur për telefonatat"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Mikrofoni i aparatit të dëgjimit"</item>
+ <item msgid="8501466270452446450">"Mikrofoni i këtij telefoni"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Zgjedhur"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ambienti rrethues"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Majtas"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Aktiv - Në bazë të fytyrës"</string>
<string name="inline_done_button" msgid="6043094985588909584">"U krye"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Zbato"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Çaktivizo"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Në heshtje"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"E parazgjedhur"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatike"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Ikona djathtas"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Mbaje të shtypur dhe zvarrit për të shtuar pllakëza"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Mbaje të shtypur dhe zvarrit për të risistemuar pllakëzat"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Zvarrit këtu për ta hequr"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Të duhen të paktën <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> pllakëza"</string>
<string name="qs_edit" msgid="5583565172803472437">"Redakto"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Të tjera"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ndrysho madhësinë e pllakëzës"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"hiq pllakëzën"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"shtuar pllakëzën në pozicionin e fundit"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Zhvendos pllakëzën"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Shto pllakëzën në pozicionin e dëshiruar"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nuk njihet"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Të rivendosen të gjitha pllakëzat?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Të gjitha pllakëzat e \"Cilësimeve të shpejta\" do të rivendosen te cilësimet origjinale të pajisjes"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 46d8352..6561de1 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Подразумевани микрофон за позиве"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Микрофон слушног апарата"</item>
+ <item msgid="8501466270452446450">"Микрофон овог телефона"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Изабрано"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Окружење"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Лево"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Када делите апликацију, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> види сав садржај који се приказује или пушта у њој. Зато пазите на лозинке, информације о плаћању, поруке, слике, аудио и видео садржај."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Дели екран"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је онемогућила ову опцију"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"Апликација то не подржава"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Одаберите апликацију за дељење"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Желите да пребаците екран?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Пребаци једну апликацију"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Укључено – на основу лица"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Готово"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Примени"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Искључи"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Нечујно"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Подразумевано"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Аутоматска"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"Десна икона"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Задржите и превуците да бисте додали плочице"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Задржите и превуците да бисте променили распоред плочица"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Превуците овде да бисте уклонили"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Минималан број плочица је <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
<string name="qs_edit" msgid="5583565172803472437">"Измени"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"Друго"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"укључивање или искључивање величине плочице"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"уклонили плочицу"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"додали плочицу на последњу позицију"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Преместите плочицу"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Додајте плочицу на жељену позицију"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Непознато"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Желите да ресетујете све плочице?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Све плочице Брзих подешавања ће се ресетовати на првобитна подешавања уређаја"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index ed0daf9..6b44208 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klicka för att parkoppla en ny enhet"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Det gick inte att uppdatera förinställningen"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Förinställning"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Standardmikrofon för samtal"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Hörapparatens mikrofon"</item>
+ <item msgid="8501466270452446450">"Telefonens mikrofon"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Markerad"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Omgivningsläge"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Vänster"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"På – ansiktsbaserad"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Klart"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Tillämpa"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Inaktivera"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Tyst"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Standard"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatiskt"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Höger ikon"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Lägg till rutor genom att trycka och dra"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Ordna om rutor genom att trycka och dra"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Ta bort genom att dra här"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Minst <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> rutor måste finnas kvar"</string>
<string name="qs_edit" msgid="5583565172803472437">"Redigera"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Annat"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"växla rutstorlek"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ta bort ruta"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"lägg till en ruta på den sista platsen"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Flytta ruta"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Lägg till en ruta på önskad plats"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Okänt"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vill du återställa alla rutor?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alla Snabbinställningsrutor återställs till enhetens ursprungliga inställningar"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index da390fb..9e0e67b 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Bofya ili uunganishe kifaa kipya"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Imeshindwa kusasisha mipangilio iliyowekwa mapema"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Mipangilio iliyowekwa mapema"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Maikrofoni chaguomsingi ya kupiga simu"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Maikrofoni ya visaidizi vya kusikia"</item>
+ <item msgid="8501466270452446450">"Maikrofoni ya simu hii"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Umechagua"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Mazingira"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Kushoto"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Imewashwa - Inayolenga nyuso"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Nimemaliza"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Tumia"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Zima"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Kimya"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Chaguomsingi"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Otomatiki"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Aikoni ya kulia"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Shikilia na uburute ili uongeze vigae"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Shikilia na uburute ili upange vigae upya"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Buruta hapa ili uondoe"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Unahitaji angalau vigae <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
<string name="qs_edit" msgid="5583565172803472437">"Badilisha"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Nyingine"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ubadilishe ukubwa wa kigae"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ondoa kigae"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"weka kigae kwenye nafasi ya mwisho"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Hamisha kigae"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Weka kigae kwenye nafasi unayopenda"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Visivyojulikana"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Ungependa kubadilisha vigae vyote?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Vigae vyote vya Mipangilio ya Haraka vitabadilishwa kuwa katika mipangilio halisi ya kifaa"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 0c7aa40..66baf1f 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"அழைப்புகளுக்கான இயல்பு மைக்ரோஃபோன்"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"செவித்துணைக் கருவி மைக்ரோஃபோன்"</item>
+ <item msgid="8501466270452446450">"இந்த மொபைலின் மைக்ரோஃபோன்"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"தேர்ந்தெடுக்கப்பட்டது"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"சுற்றுப்புறங்கள்"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"இடது"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"ஆன் - முகம் அடிப்படையிலானது"</string>
<string name="inline_done_button" msgid="6043094985588909584">"முடிந்தது"</string>
<string name="inline_ok_button" msgid="603075490581280343">"பயன்படுத்து"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"ஆஃப் செய்"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"சைலன்ட்"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"இயல்புநிலை"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"தானியங்கு"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"வலப்புற ஐகான்"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"கட்டங்களைச் சேர்க்க, அவற்றைப் பிடித்து இழுக்கவும்"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"கட்டங்களை மறுவரிசைப்படுத்த அவற்றைப் பிடித்து இழுக்கவும்"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"அகற்ற, இங்கே இழுக்கவும்"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"குறைந்தது <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> கட்டங்கள் தேவை"</string>
<string name="qs_edit" msgid="5583565172803472437">"மாற்று"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"மற்றவை"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"கட்டத்தின் அளவை நிலைமாற்றும்"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"கட்டத்தை அகற்றும்"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"கடைசி இடத்தில் கட்டத்தைச் சேர்க்கலாம்"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"கட்டத்தை நகர்த்து"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"விரும்பிய இடத்தில் கட்டத்தைச் சேர்க்கலாம்"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"தெரியவில்லை"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"அனைத்துக் கட்டங்களையும் மீட்டமைக்கவா?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"விரைவு அமைப்புகளின் கட்டங்கள் அனைத்தும் சாதனத்தின் அசல் அமைப்புகளுக்கு மீட்டமைக்கப்படும்"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 972c64a..d1bc7e5 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"కాల్స్ అందుకునే ఆటోమేటిక్ మైక్రోఫోన్"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"వినికిడి పరికర మైక్రోఫోన్"</item>
+ <item msgid="8501466270452446450">"ఈ ఫోన్ మైక్రోఫోన్"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"ఎంచుకోబడింది"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"పరిసరాలు"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ఎడమ వైపునకు"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"మీరు యాప్ను షేర్ చేసేటప్పుడు, సంబంధిత యాప్లో కనిపించేవి లేదా ప్లే అయ్యేవన్నీ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>కు కనిపిస్తాయి. కాబట్టి పాస్వర్డ్లు, పేమెంట్ వివరాలు, మెసేజ్లు, ఫోటోలు, ఆడియో, ఇంకా వీడియో వంటి విషయాల్లో జాగ్రత్త వహించండి."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"స్క్రీన్ను షేర్ చేయండి"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ఈ ఆప్షన్ను డిజేబుల్ చేసింది"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"యాప్ ద్వారా సపోర్ట్ చేయబడలేదు"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"షేర్ చేయడానికి యాప్ను ఎంచుకోండి"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"మీ స్క్రీన్ను ప్రసారం చేయాలా?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"ఒక యాప్ను ప్రసారం చేయండి"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"\'ముఖం ఆధారం\'ను - ఆన్ చేయండి"</string>
<string name="inline_done_button" msgid="6043094985588909584">"పూర్తయింది"</string>
<string name="inline_ok_button" msgid="603075490581280343">"అప్లయి చేయి"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"ఆఫ్ చేయండి"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"నిశ్శబ్దం"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ఆటోమేటిక్ సెట్టింగ్"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ఆటోమేటిక్"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"కుడివైపు ఉన్న చిహ్నం"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"టైల్స్ను జోడించడానికి పట్టుకుని, లాగండి"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"టైల్స్ను వేరే క్రమంలో అమర్చడానికి వాటిని పట్టుకుని, లాగండి"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"తీసివేయడానికి ఇక్కడికి లాగండి"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"మీ వద్ద కనీసం <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> టైల్లు ఉండాలి"</string>
<string name="qs_edit" msgid="5583565172803472437">"ఎడిట్ చేయండి"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"ఇతరం"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"టైల్ సైజ్ను టోగుల్ చేయండి"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"టైల్ను తీసివేయండి"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"చివరి పొజిషన్కు టైల్ను జోడించండి"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"టైల్ను తరలించండి"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"కావలసిన పొజిషన్కు టైల్ను జోడించండి"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"తెలియదు"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"టైల్స్ అన్ని రీసెట్ చేయాలా?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"అన్ని క్విక్ సెట్టింగ్ల టైల్స్, పరికరం తాలూకు ఒరిజినల్ సెట్టింగ్లకు రీసెట్ చేయబడతాయి"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index a4f1447..920207b 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"ไมโครโฟนเริ่มต้นสำหรับการโทร"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"ไมโครโฟนเครื่องช่วยฟัง"</item>
+ <item msgid="8501466270452446450">"ไมโครโฟนของโทรศัพท์เครื่องนี้"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"เลือกแล้ว"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"เสียงแวดล้อม"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ซ้าย"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"เมื่อกำลังแชร์แอป <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> จะมองเห็นทุกสิ่งที่แสดงหรือเล่นอยู่ในแอปดังกล่าว ดังนั้นโปรดระวังสิ่งต่างๆ อย่างเช่นรหัสผ่าน รายละเอียดการชำระเงิน ข้อความ รูปภาพ รวมถึงเสียงและวิดีโอ"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"แชร์หน้าจอ"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ปิดใช้ตัวเลือกนี้"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"แอปไม่รองรับ"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"เลือกแอปที่จะแชร์"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"แคสต์หน้าจอของคุณไหม"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"แคสต์แอปเดียว"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"เปิด - ตามใบหน้า"</string>
<string name="inline_done_button" msgid="6043094985588909584">"เสร็จสิ้น"</string>
<string name="inline_ok_button" msgid="603075490581280343">"ใช้"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"ปิด"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"ปิดเสียง"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ค่าเริ่มต้น"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"อัตโนมัติ"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"ไอคอนทางขวา"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"กดค้างแล้วลากเพื่อเพิ่มการ์ด"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"กดค้างแล้วลากเพื่อจัดเรียงการ์ดใหม่"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"ลากมาที่นี่เพื่อนำออก"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"คุณต้องมีการ์ดอย่างน้อย <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> รายการ"</string>
<string name="qs_edit" msgid="5583565172803472437">"แก้ไข"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"อื่นๆ"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"สลับขนาดของการ์ด"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"นำชิ้นส่วนออก"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"เพิ่มการ์ดไปยังตำแหน่งสุดท้าย"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ย้ายชิ้นส่วน"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"เพิ่มการ์ดไปยังตำแหน่งที่ต้องการ"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ไม่ทราบ"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"รีเซ็ตการ์ดทั้งหมดใช่ไหม"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"การ์ดการตั้งค่าด่วนทั้งหมดจะรีเซ็ตเป็นการตั้งค่าเดิมของอุปกรณ์"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/tiles_states_strings.xml b/packages/SystemUI/res/values-th/tiles_states_strings.xml
index b969056..677888b 100644
--- a/packages/SystemUI/res/values-th/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-th/tiles_states_strings.xml
@@ -56,9 +56,11 @@
<item msgid="5376619709702103243">"ปิด"</item>
<item msgid="4875147066469902392">"เปิด"</item>
</string-array>
- <!-- no translation found for tile_states_modes_dnd:0 (6509540227356524582) -->
- <!-- no translation found for tile_states_modes_dnd:1 (8589336868985358191) -->
- <!-- no translation found for tile_states_modes_dnd:2 (726072717827778234) -->
+ <string-array name="tile_states_modes_dnd">
+ <item msgid="6509540227356524582">"ไม่พร้อมใช้งาน"</item>
+ <item msgid="8589336868985358191">"ปิด"</item>
+ <item msgid="726072717827778234">"เปิด"</item>
+ </string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"ไม่พร้อมใช้งาน"</item>
<item msgid="5044688398303285224">"ปิด"</item>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 1f25175..3625e3a 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"I-click para magpares ng bagong device"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Hindi ma-update ang preset"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Default na mikropono para sa mga tawag"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Mikropono ng hearing aid"</item>
+ <item msgid="8501466270452446450">"Ang mikropono ng teleponong ito"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Napili"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Paligid"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Kaliwa"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kapag nagshe-share ka ng app, makikita ng <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ang kahit anong ipinapakita o pine-play sa app na iyon. Kaya mag-ingat sa mga bagay-bagay tulad ng mga password, detalye ng pagbabayad, mensahe, larawan, at audio at video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Ibahagi ang screen"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Na-disable ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang opsyong ito"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"Hindi sinusuportahan ng app"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Pumili ng app na ishe-share"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"I-cast ang iyong screen?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Mag-cast ng isang app"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Naka-on - Batay sa mukha"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Tapos na"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Ilapat"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"I-off"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Naka-silent"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Default"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Awtomatiko"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"Icon ng kanan"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Pindutin nang matagal at i-drag para magdagdag ng mga tile"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Pindutin nang matagal at i-drag para ayusin ulit ang tile"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"I-drag dito upang alisin"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Kailangan mo ng kahit <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> (na) tile"</string>
<string name="qs_edit" msgid="5583565172803472437">"I-edit"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"Iba pa"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"i-toggle ang laki ng tile"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"alisin ang tile"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"magdagdag ng tile sa huling posisyon"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Ilipat ang tile"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Magdagdag ng tile sa gustong posisyon"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Hindi Alam"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"I-reset ang lahat ng tile?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Magre-reset sa mga orihinal na setting ng device ang lahat ng tile ng Mga Mabilisang Setting"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 4748cc4d..f2d2ae8 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yeni cihaz eşlemek için tıklayın"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Hazır ayar güncellenemedi"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Hazır Ayar"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Aramalar için varsayılan mikrofon"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"İşitme cihazı mikrofonu"</item>
+ <item msgid="8501466270452446450">"Bu telefonun mikrofonu"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Seçili"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Çevredeki sesler"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Sol"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Açık - Yüze göre"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Bitti"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Uygula"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Kapat"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Sessiz"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Varsayılan"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Otomatik"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Sağ simge"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Kutu eklemek için basılı tutup sürükleyin"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Kutuları yeniden düzenlemek için basılı tutun ve sürükleyin"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Kaldırmak için buraya sürükleyin"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"En az <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> kutu gerekiyor"</string>
<string name="qs_edit" msgid="5583565172803472437">"Düzenle"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Diğer"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"kutu boyutunu değiştir"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"Kutuyu kaldırmak için"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"kutuyu son konuma ekleyin"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Kutuyu taşı"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"kutuyu istediğiniz konuma ekleyin"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Bilinmiyor"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Tüm ayar kutuları sıfırlansın mı?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Tüm Hızlı Ayarlar kutuları cihazın özgün ayarlarına sıfırlanır"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index d89467c..d9dc96b 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Мікрофон за умовчанням для дзвінків"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Мікрофон слухового апарата"</item>
+ <item msgid="8501466270452446450">"Мікрофон цього телефона"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Вибрано"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Звуки оточення"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Ліворуч"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Увімкнути (за обличчям)"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Готово"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Застосувати"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Вимкнути"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Без звуку"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"За умовчанням"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматично"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Значок праворуч"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Перетягніть потрібні елементи, щоб додати їх"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Щоб змінити порядок елементів, перетягуйте їх"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Перетягніть сюди, щоб видалити"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Мінімальна кількість фрагментів: <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
<string name="qs_edit" msgid="5583565172803472437">"Редагувати"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Інше"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"змінити розмір плитки"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"вилучити опцію"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"додати панель на останню позицію"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Перемістити опцію"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"додати панель на потрібну позицію"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Невідомо"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Скинути всі панелі?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Усі панелі швидких налаштувань буде скинуто до стандартних налаштувань пристрою"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/tiles_states_strings.xml b/packages/SystemUI/res/values-uk/tiles_states_strings.xml
index a31e858..f5b0f80 100644
--- a/packages/SystemUI/res/values-uk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-uk/tiles_states_strings.xml
@@ -56,9 +56,11 @@
<item msgid="5376619709702103243">"Вимкнено"</item>
<item msgid="4875147066469902392">"Увімкнено"</item>
</string-array>
- <!-- no translation found for tile_states_modes_dnd:0 (6509540227356524582) -->
- <!-- no translation found for tile_states_modes_dnd:1 (8589336868985358191) -->
- <!-- no translation found for tile_states_modes_dnd:2 (726072717827778234) -->
+ <string-array name="tile_states_modes_dnd">
+ <item msgid="6509540227356524582">"Недоступно"</item>
+ <item msgid="8589336868985358191">"Вимкнено"</item>
+ <item msgid="726072717827778234">"Увімкнено"</item>
+ </string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"Недоступно"</item>
<item msgid="5044688398303285224">"Вимкнено"</item>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 51950e0..0658c23 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"کالز کے لیے ڈیفالٹ مائیکروفون"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"سماعتی آلہ مائیکروفون"</item>
+ <item msgid="8501466270452446450">"اس فون کا مائیکروفون"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"منتخب کردہ"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"اطراف"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"دائیں"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"آن - چہرے پر مبنی"</string>
<string name="inline_done_button" msgid="6043094985588909584">"ہو گیا"</string>
<string name="inline_ok_button" msgid="603075490581280343">"لاگو کریں"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"آف کریں"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"خاموش"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ڈیفالٹ"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"خودکار"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"دائيں جانب کا آئيکن"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"ٹائلز شامل کرنے کے لئے پکڑ کر گھسیٹیں"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"ٹائلز کو دوبارہ ترتیب دینے کیلئے پکڑ کر گھسیٹیں"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"ہٹانے کیلئے یہاں گھسیٹیں؟"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"آپ کو کم از کم <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> ٹائلز کی ضرورت ہے"</string>
<string name="qs_edit" msgid="5583565172803472437">"ترمیم کریں"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"دیگر"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ٹائل کے سائز کو ٹوگل کریں"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ٹائل ہٹائیں"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"ٹائل کو آخری پوزیشن پر شامل کریں"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ٹائل منتقل کریں"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"ٹائل کو مطلوبہ پوزیشن پر شامل کریں"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"نامعلوم"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"سبھی ٹائلز ری سیٹ کریں؟"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"سبھی فوری ترتیبات کی ٹائلز آلہ کی اصل ترتیبات پر ری سیٹ ہو جائیں گی"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>، <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 8d750dd..3521d16 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yangi qurilmani ulash uchun bosing"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Andoza yangilanmadi"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Andoza"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Chaqiruvlar uchun asosiy mikrofon"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Eshitish moslamasi mikrofoni"</item>
+ <item msgid="8501466270452446450">"Bu telefonning mikrofoni"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Tanlangan"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Atrof-muhit"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Chap"</string>
@@ -586,8 +587,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Ilovani namoyish qilayotganingizda oʻsha ilova ichida koʻrsatilayotgan yoki ijro qilinayotganlar <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ga koʻrinadi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar, suratlar, audio va video chiqmasligi uchun ehtiyot boʻling."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Ekranni namoyish qilish"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> bu sozlamani faolsizlantirgan"</string>
- <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_not_supported (4860247304058870233) -->
- <skip />
+ <string name="media_projection_entry_app_permission_dialog_single_app_not_supported" msgid="4860247304058870233">"Ilova tomonidan dastaklanmaydi"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Ulashiladigan ilovani tanlash"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Ekraningiz uzatilsinmi?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Bitta ilovani uzatish"</string>
@@ -800,8 +800,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Yoqish - Yuz asosida"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Tayyor"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Tatbiq etish"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Faolsizlantirish"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Sokin"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Standart"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Avtomatik"</string>
@@ -983,6 +982,8 @@
<string name="right_icon" msgid="1103955040645237425">"O‘ngga belgisi"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Keraklisini ushlab torting"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Qayta tartiblash uchun ushlab torting"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"O‘chirish uchun bu yerga torting"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Kamida <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> ta katakcha lozim"</string>
<string name="qs_edit" msgid="5583565172803472437">"Tahrirlash"</string>
@@ -1003,6 +1004,10 @@
<string name="other" msgid="429768510980739978">"Boshqa"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"katak oʻlchamini almashtirish"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"katakchani olib tashlash"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"kartochkani oxirgi oʻringa qoʻshish"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Katakchani boshqa joyga olish"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Kartochkani kerakli oʻringa qoʻshish"</string>
@@ -1578,5 +1583,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Noaniq"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Barcha katakchalar asliga qaytarilsinmi?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Barcha Tezkor sozlamalar katakchalari qurilmaning asl sozlamalariga qaytariladi"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 300dea9..cf36d69 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -419,10 +419,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Nhấp để ghép nối thiết bị mới"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Không cập nhật được giá trị đặt trước"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Chế độ đặt sẵn"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Micrô mặc định cho cuộc gọi"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Micrô trên thiết bị trợ thính"</item>
+ <item msgid="8501466270452446450">"Micrô của điện thoại này"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Đã chọn"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Âm lượng xung quanh"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Trái"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Đang bật – Dựa trên khuôn mặt"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Xong"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Áp dụng"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Tắt"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Im lặng"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Mặc định"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Tự động"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"Biểu tượng bên phải"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Giữ và kéo để thêm ô"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Giữ và kéo để sắp xếp lại các ô"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Kéo vào đây để xóa"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Bạn cần ít nhất <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> ô"</string>
<string name="qs_edit" msgid="5583565172803472437">"Chỉnh sửa"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"Khác"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"bật hoặc tắt kích thước của ô"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"xóa ô"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"thêm ô vào vị trí cuối cùng"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Di chuyển ô"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Thêm ô vào vị trí mong muốn"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Không xác định"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Đặt lại mọi ô?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Mọi ô Cài đặt nhanh sẽ được đặt lại về chế độ cài đặt ban đầu của thiết bị"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index dacca69..e469e38 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -106,7 +106,7 @@
<string name="backlinks_include_link" msgid="4562093591148248158">"包括链接"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
<string name="backlinks_cross_profile_error" msgid="1355798585727802282">"无法添加来自其他个人资料的链接"</string>
- <string name="screenrecord_title" msgid="4257171601439507792">"屏幕录制器"</string>
+ <string name="screenrecord_title" msgid="4257171601439507792">"屏幕录制"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在处理屏幕录制视频"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持续显示屏幕录制会话通知"</string>
<string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"要录制屏幕吗?"</string>
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"通话的默认麦克风"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"助听器麦克风"</item>
+ <item msgid="8501466270452446450">"此手机的麦克风"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"已选择"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"周围声音"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"左侧"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"已开启 - 基于人脸"</string>
<string name="inline_done_button" msgid="6043094985588909584">"完成"</string>
<string name="inline_ok_button" msgid="603075490581280343">"应用"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"关闭"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"静音"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"默认"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"自动"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"向右图标"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"按住并拖动即可添加功能块"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"按住并拖动即可重新排列功能块"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"拖动到此处即可移除"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"您至少需要 <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> 个卡片"</string>
<string name="qs_edit" msgid="5583565172803472437">"编辑"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"其他"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"切换功能块大小"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"移除功能块"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"将功能块添加到最后一个位置"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"移动功能块"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"将功能块添加到所需位置"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"未知"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"要重置所有功能块吗?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"所有“快捷设置”功能块都将重置为设备的原始设置"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>,<xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
index 5980c31..b0fd9be 100644
--- a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
@@ -56,9 +56,11 @@
<item msgid="5376619709702103243">"已关闭"</item>
<item msgid="4875147066469902392">"已开启"</item>
</string-array>
- <!-- no translation found for tile_states_modes_dnd:0 (6509540227356524582) -->
- <!-- no translation found for tile_states_modes_dnd:1 (8589336868985358191) -->
- <!-- no translation found for tile_states_modes_dnd:2 (726072717827778234) -->
+ <string-array name="tile_states_modes_dnd">
+ <item msgid="6509540227356524582">"不可用"</item>
+ <item msgid="8589336868985358191">"关"</item>
+ <item msgid="726072717827778234">"开"</item>
+ </string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"不可用"</item>
<item msgid="5044688398303285224">"已关闭"</item>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index afc33d9..4a1291e 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"預設通話用麥克風"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"助聽器麥克風"</item>
+ <item msgid="8501466270452446450">"此手機的麥克風"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"揀咗"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"環境聲音"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"左"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"已開啟 - 根據面孔偵測"</string>
<string name="inline_done_button" msgid="6043094985588909584">"完成"</string>
<string name="inline_ok_button" msgid="603075490581280343">"套用"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"關閉"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"靜音"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"預設"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"自動"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"向右圖示"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"按住並拖曳即可新增圖塊"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"按住並拖曳即可重新排列圖塊"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"拖曳這裡即可移除"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"你需要有至少 <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> 個資訊方塊"</string>
<string name="qs_edit" msgid="5583565172803472437">"編輯"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"其他"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"切換圖塊大小"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"移除圖塊"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"加圖塊去上一個位置"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"移動圖塊"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"加圖塊去目標位置"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"不明"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"要重設所有圖塊嗎?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"所有「快速設定」圖塊將重設為裝置的原始設定"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>,<xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 3ea590a1..89f2018 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -419,10 +419,11 @@
<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>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"預設通話麥克風"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"助聽器麥克風"</item>
+ <item msgid="8501466270452446450">"這支手機的麥克風"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"已選取"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"環境"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"左"</string>
@@ -800,8 +801,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"已開啟 - 依臉部方向旋轉"</string>
<string name="inline_done_button" msgid="6043094985588909584">"完成"</string>
<string name="inline_ok_button" msgid="603075490581280343">"套用"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"關閉"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"靜音"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"預設"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"自動"</string>
@@ -983,6 +983,8 @@
<string name="right_icon" msgid="1103955040645237425">"向右圖示"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"按住並拖曳即可新增設定方塊"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"按住並拖曳即可重新排列設定方塊"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"拖曳到這裡即可移除"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"你至少必須要有 <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> 個設定方塊"</string>
<string name="qs_edit" msgid="5583565172803472437">"編輯"</string>
@@ -1003,6 +1005,10 @@
<string name="other" msgid="429768510980739978">"其他"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"切換設定方塊大小"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"移除圖塊"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"將設定方塊新增到最後一個位置"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"移動圖塊"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"將設定方塊新增到所需位置"</string>
@@ -1578,5 +1584,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"不明"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"要重設所有設定方塊嗎?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"所有快速設定方塊都會恢復裝置的原始設定"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>、<xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 767adbb..3bef836 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -421,10 +421,11 @@
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Chofoza ukuze ubhangqe idivayisi entsha"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"Ayikwazanga ukubuyekeza ukusetha ngaphambilini"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"Ukusetha ngaphambilini"</string>
- <!-- no translation found for hearing_devices_input_routing_label (730396728151232306) -->
- <skip />
- <!-- no translation found for hearing_device_input_routing_options:0 (4582190415045337003) -->
- <!-- no translation found for hearing_device_input_routing_options:1 (8501466270452446450) -->
+ <string name="hearing_devices_input_routing_label" msgid="730396728151232306">"Imakrofoni ezenzekelayo yocingo"</string>
+ <string-array name="hearing_device_input_routing_options">
+ <item msgid="4582190415045337003">"Imakrofoni yomshini wendlebe"</item>
+ <item msgid="8501466270452446450">"Imakrofoni yale foni"</item>
+ </string-array>
<string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"Okukhethiwe"</string>
<string name="hearing_devices_ambient_label" msgid="629440938614895797">"Izindawo ezizungezile"</string>
<string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Kwesokunxele"</string>
@@ -802,8 +803,7 @@
<string name="rotation_lock_camera_rotation_on" msgid="789434807790534274">"Vuliwe - Kususelwe kubuso"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Kwenziwe"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Faka"</string>
- <!-- no translation found for inline_turn_off_notifications (2653064779176881329) -->
- <skip />
+ <string name="inline_turn_off_notifications" msgid="2653064779176881329">"Vala"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Kuthulile"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Okuzenzekelayo"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Okuzenzekelayo"</string>
@@ -985,6 +985,8 @@
<string name="right_icon" msgid="1103955040645237425">"Isithonjana sangakwesokudla"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Bamba uphinde uhudule ukuze ungeze amathayela"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Bamba uphinde uhudule ukuze uphinde ulungise amathayela"</string>
+ <!-- no translation found for tap_to_position_tile (6282815817773342757) -->
+ <skip />
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Hudulela lapha ukuze ususe"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Udinga okungenani amathayela angu-<xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
<string name="qs_edit" msgid="5583565172803472437">"Hlela"</string>
@@ -1005,6 +1007,10 @@
<string name="other" msgid="429768510980739978">"Okunye"</string>
<string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"guqula usayizi wethayela"</string>
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"susa ithayela"</string>
+ <!-- no translation found for accessibility_qs_edit_toggle_placement_mode (3870429389210569610) -->
+ <skip />
+ <!-- no translation found for accessibility_qs_edit_toggle_selection (2201248304072372239) -->
+ <skip />
<string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"faka ithayela endaweni yokugcina"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Hambisa ithayela"</string>
<string name="accessibility_qs_edit_tile_start_add" msgid="8141710006899065161">"Faka ithayela endaweni oyifunayo"</string>
@@ -1580,5 +1586,7 @@
<string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Akwaziwa"</string>
<string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Qala kabusha onke amathayela?"</string>
<string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Ithayela Lamasethingi Asheshayo lizosetha kabusha libuyele kumasethingi okuqala edivayisi"</string>
+ <!-- no translation found for demote_explain_text (1600426458580544250) -->
+ <skip />
<string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 7c6a1b1..ff16e06 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -145,9 +145,9 @@
<color name="smart_reply_button_background">#ffffffff</color>
<color name="smart_reply_button_stroke">@*android:color/accent_device_default</color>
- <!-- Magic Action colors -->
- <color name="magic_action_button_text_color">@androidprv:color/materialColorOnSurface</color>
- <color name="magic_action_button_stroke_color">@androidprv:color/materialColorOnSurface</color>
+ <!-- Animated Action colors -->
+ <color name="animated_action_button_text_color">@androidprv:color/materialColorOnSurface</color>
+ <color name="animated_action_button_stroke_color">@androidprv:color/materialColorOnSurface</color>
<!-- Biometric dialog colors -->
<color name="biometric_dialog_gray">#ff757575</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 55e9402..4dfb8cd 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1160,16 +1160,16 @@
<dimen name="notification_2025_smart_reply_button_corner_radius">18dp</dimen>
<dimen name="notification_2025_smart_reply_button_min_height">48dp</dimen>
- <!-- Magic Action params. -->
+ <!-- Animated Action params. -->
<!-- Corner radius = half of min_height to create rounded sides. -->
- <dimen name="magic_action_button_corner_radius">16dp</dimen>
- <dimen name="magic_action_button_icon_size">20dp</dimen>
- <dimen name="magic_action_button_outline_stroke_width">1dp</dimen>
- <dimen name="magic_action_button_padding_horizontal">12dp</dimen>
- <dimen name="magic_action_button_inset_vertical">8dp</dimen>
- <dimen name="magic_action_button_drawable_padding">8dp</dimen>
- <dimen name="magic_action_button_touch_target_height">48dp</dimen>
- <dimen name="magic_action_button_font_size">12sp</dimen>
+ <dimen name="animated_action_button_corner_radius">16dp</dimen>
+ <dimen name="animated_action_button_icon_size">20dp</dimen>
+ <dimen name="animated_action_button_outline_stroke_width">1dp</dimen>
+ <dimen name="animated_action_button_padding_horizontal">12dp</dimen>
+ <dimen name="animated_action_button_inset_vertical">8dp</dimen>
+ <dimen name="animated_action_button_drawable_padding">8dp</dimen>
+ <dimen name="animated_action_button_touch_target_height">48dp</dimen>
+ <dimen name="animated_action_button_font_size">12sp</dimen>
<!-- A reasonable upper bound for the height of the smart reply button. The measuring code
needs to start with a guess for the maximum size. Currently two-line smart reply buttons
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index f2f1773..6318908 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -72,6 +72,7 @@
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.ZenModeController
import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
+import com.android.systemui.util.annotations.DeprecatedSysuiVisibleForTesting
import com.android.systemui.util.concurrency.DelayableExecutor
import java.util.Locale
import java.util.TimeZone
@@ -392,8 +393,9 @@
}
}
- @VisibleForTesting
- internal fun listenForDnd(scope: CoroutineScope): Job {
+ @DeprecatedSysuiVisibleForTesting
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ fun listenForDnd(scope: CoroutineScope): Job {
ModesUi.unsafeAssertInNewMode()
return scope.launch {
zenModeInteractor.dndMode.collect {
@@ -592,8 +594,9 @@
dozeAmount.value = doze
}
- @VisibleForTesting
- internal fun listenForDozeAmountTransition(scope: CoroutineScope): Job {
+ @DeprecatedSysuiVisibleForTesting
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ fun listenForDozeAmountTransition(scope: CoroutineScope): Job {
return scope.launch {
merge(
keyguardTransitionInteractor.transition(Edge.create(AOD, LOCKSCREEN)).map {
@@ -609,8 +612,9 @@
/**
* When keyguard is displayed again after being gone, the clock must be reset to full dozing.
*/
- @VisibleForTesting
- internal fun listenForAnyStateToAodTransition(scope: CoroutineScope): Job {
+ @DeprecatedSysuiVisibleForTesting
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ fun listenForAnyStateToAodTransition(scope: CoroutineScope): Job {
return scope.launch {
keyguardTransitionInteractor
.transition(Edge.create(to = AOD))
@@ -620,8 +624,9 @@
}
}
- @VisibleForTesting
- internal fun listenForAnyStateToLockscreenTransition(scope: CoroutineScope): Job {
+ @DeprecatedSysuiVisibleForTesting
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ fun listenForAnyStateToLockscreenTransition(scope: CoroutineScope): Job {
return scope.launch {
keyguardTransitionInteractor
.transition(Edge.create(to = LOCKSCREEN))
@@ -635,8 +640,9 @@
* When keyguard is displayed due to pulsing notifications when AOD is off, we should make sure
* clock is in dozing state instead of LS state
*/
- @VisibleForTesting
- internal fun listenForAnyStateToDozingTransition(scope: CoroutineScope): Job {
+ @DeprecatedSysuiVisibleForTesting
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ fun listenForAnyStateToDozingTransition(scope: CoroutineScope): Job {
return scope.launch {
keyguardTransitionInteractor
.transition(Edge.create(to = DOZING))
diff --git a/packages/SystemUI/src/com/android/keyguard/UserActivityNotifier.kt b/packages/SystemUI/src/com/android/keyguard/UserActivityNotifier.kt
index 9b1ddb7..76c032a 100644
--- a/packages/SystemUI/src/com/android/keyguard/UserActivityNotifier.kt
+++ b/packages/SystemUI/src/com/android/keyguard/UserActivityNotifier.kt
@@ -15,27 +15,30 @@
*/
package com.android.keyguard
+import android.annotation.SuppressLint
import android.os.PowerManager
import android.os.SystemClock
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.UiBackground
import java.util.concurrent.Executor
import javax.inject.Inject
/** Wrapper class for notifying the system about user activity in the background. */
+@SysUISingleton
class UserActivityNotifier
@Inject
constructor(
@UiBackground private val uiBgExecutor: Executor,
- private val powerManager: PowerManager
+ private val powerManager: PowerManager,
) {
- fun notifyUserActivity() {
- uiBgExecutor.execute {
- powerManager.userActivity(
- SystemClock.uptimeMillis(),
- PowerManager.USER_ACTIVITY_EVENT_OTHER,
- 0
- )
- }
+ @SuppressLint("MissingPermission")
+ @JvmOverloads
+ fun notifyUserActivity(
+ timeOfActivity: Long = SystemClock.uptimeMillis(),
+ event: Int = PowerManager.USER_ACTIVITY_EVENT_OTHER,
+ flags: Int = 0,
+ ) {
+ uiBgExecutor.execute { powerManager.userActivity(timeOfActivity, event, flags) }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationImpl.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationImpl.java
index 375137c..c6071a0 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationImpl.java
@@ -53,7 +53,6 @@
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.util.settings.SecureSettings;
-import com.android.systemui.utils.windowmanager.WindowManagerProvider;
import java.io.PrintWriter;
import java.util.concurrent.Executor;
@@ -97,19 +96,17 @@
private final WindowMagnifierCallback mWindowMagnifierCallback;
private final SysUiState mSysUiState;
private final SecureSettings mSecureSettings;
- private final WindowManagerProvider mWindowManagerProvider;
WindowMagnificationControllerSupplier(Context context, Handler handler,
WindowMagnifierCallback windowMagnifierCallback,
DisplayManager displayManager, SysUiState sysUiState,
- SecureSettings secureSettings, WindowManagerProvider windowManagerProvider) {
+ SecureSettings secureSettings) {
super(displayManager);
mContext = context;
mHandler = handler;
mWindowMagnifierCallback = windowMagnifierCallback;
mSysUiState = sysUiState;
mSecureSettings = secureSettings;
- mWindowManagerProvider = windowManagerProvider;
}
@Override
@@ -117,9 +114,8 @@
final Context windowContext = mContext.createWindowContext(display,
TYPE_ACCESSIBILITY_OVERLAY,
/* options */ null);
- final WindowManager windowManager = mWindowManagerProvider
- .getWindowManager(windowContext);
windowContext.setTheme(com.android.systemui.res.R.style.Theme_SystemUI);
+ final WindowManager windowManager = windowContext.getSystemService(WindowManager.class);
Supplier<SurfaceControlViewHost> scvhSupplier = () ->
new SurfaceControlViewHost(mContext,
@@ -150,20 +146,17 @@
private final Executor mExecutor;
private final DisplayManager mDisplayManager;
private final IWindowManager mIWindowManager;
- private final WindowManagerProvider mWindowManagerProvider;
FullscreenMagnificationControllerSupplier(Context context,
DisplayManager displayManager,
Handler handler,
- Executor executor, IWindowManager iWindowManager,
- WindowManagerProvider windowManagerProvider) {
+ Executor executor, IWindowManager iWindowManager) {
super(displayManager);
mContext = context;
mHandler = handler;
mExecutor = executor;
mDisplayManager = displayManager;
mIWindowManager = iWindowManager;
- mWindowManagerProvider = windowManagerProvider;
}
@Override
@@ -179,7 +172,7 @@
mExecutor,
mDisplayManager,
windowContext.getSystemService(AccessibilityManager.class),
- mWindowManagerProvider.getWindowManager(windowContext),
+ windowContext.getSystemService(WindowManager.class),
mIWindowManager,
scvhSupplier);
}
@@ -195,32 +188,28 @@
private final Context mContext;
private final MagnificationSettingsController.Callback mSettingsControllerCallback;
private final SecureSettings mSecureSettings;
- private final WindowManagerProvider mWindowManagerProvider;
SettingsSupplier(Context context,
MagnificationSettingsController.Callback settingsControllerCallback,
DisplayManager displayManager,
- SecureSettings secureSettings, WindowManagerProvider windowManagerProvider) {
+ SecureSettings secureSettings) {
super(displayManager);
mContext = context;
mSettingsControllerCallback = settingsControllerCallback;
mSecureSettings = secureSettings;
- mWindowManagerProvider = windowManagerProvider;
}
@Override
protected MagnificationSettingsController createInstance(Display display) {
final Context windowContext = mContext.createWindowContext(display,
TYPE_ACCESSIBILITY_OVERLAY, /* options */ null);
- final WindowManager windowManager = mWindowManagerProvider
- .getWindowManager(windowContext);
windowContext.setTheme(com.android.systemui.res.R.style.Theme_SystemUI);
+
return new MagnificationSettingsController(
windowContext,
new SfVsyncFrameCallbackProvider(),
mSettingsControllerCallback,
- mSecureSettings,
- windowManager);
+ mSecureSettings);
}
}
@@ -234,12 +223,10 @@
SysUiState sysUiState, LauncherProxyService launcherProxyService,
SecureSettings secureSettings, DisplayTracker displayTracker,
DisplayManager displayManager, AccessibilityLogger a11yLogger,
- IWindowManager iWindowManager, AccessibilityManager accessibilityManager,
- WindowManagerProvider windowManagerProvider) {
+ IWindowManager iWindowManager, AccessibilityManager accessibilityManager) {
this(context, mainHandler.getLooper(), executor, commandQueue,
modeSwitchesController, sysUiState, launcherProxyService, secureSettings,
- displayTracker, displayManager, a11yLogger, iWindowManager, accessibilityManager,
- windowManagerProvider);
+ displayTracker, displayManager, a11yLogger, iWindowManager, accessibilityManager);
}
@VisibleForTesting
@@ -249,8 +236,7 @@
SecureSettings secureSettings, DisplayTracker displayTracker,
DisplayManager displayManager, AccessibilityLogger a11yLogger,
IWindowManager iWindowManager,
- AccessibilityManager accessibilityManager,
- WindowManagerProvider windowManagerProvider) {
+ AccessibilityManager accessibilityManager) {
mHandler = new Handler(looper) {
@Override
public void handleMessage(@NonNull Message msg) {
@@ -269,13 +255,11 @@
mA11yLogger = a11yLogger;
mWindowMagnificationControllerSupplier = new WindowMagnificationControllerSupplier(context,
mHandler, mWindowMagnifierCallback,
- displayManager, sysUiState, secureSettings, windowManagerProvider);
+ displayManager, sysUiState, secureSettings);
mFullscreenMagnificationControllerSupplier = new FullscreenMagnificationControllerSupplier(
- context, displayManager, mHandler, mExecutor, iWindowManager,
- windowManagerProvider);
+ context, displayManager, mHandler, mExecutor, iWindowManager);
mMagnificationSettingsSupplier = new SettingsSupplier(context,
- mMagnificationSettingsControllerCallback, displayManager, secureSettings,
- windowManagerProvider);
+ mMagnificationSettingsControllerCallback, displayManager, secureSettings);
mModeSwitchesController.setClickListenerDelegate(
displayId -> mHandler.post(() -> {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
index 2d5dc8d..5af34f4 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
@@ -60,10 +60,8 @@
@UiContext Context context,
SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
@NonNull Callback settingsControllerCallback,
- SecureSettings secureSettings,
- WindowManager windowManager) {
- this(context, sfVsyncFrameProvider, settingsControllerCallback, secureSettings,
- windowManager, null);
+ SecureSettings secureSettings) {
+ this(context, sfVsyncFrameProvider, settingsControllerCallback, secureSettings, null);
}
@VisibleForTesting
@@ -72,7 +70,6 @@
SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
@NonNull Callback settingsControllerCallback,
SecureSettings secureSettings,
- WindowManager windowManager,
WindowMagnificationSettings windowMagnificationSettings) {
mContext = context.createWindowContext(
context.getDisplay(),
@@ -85,9 +82,10 @@
if (windowMagnificationSettings != null) {
mWindowMagnificationSettings = windowMagnificationSettings;
} else {
+ WindowManager wm = mContext.getSystemService(WindowManager.class);
mWindowMagnificationSettings = new WindowMagnificationSettings(mContext,
mWindowMagnificationSettingsCallback,
- sfVsyncFrameProvider, secureSettings, windowManager);
+ sfVsyncFrameProvider, secureSettings, wm);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
index 24b9551..7f46613 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
@@ -327,9 +327,7 @@
setupDeviceListView(dialog, hearingDeviceItemList);
setupPairNewDeviceButton(dialog);
setupPresetSpinner(dialog, activeHearingDevice);
- if (com.android.settingslib.flags.Flags.hearingDevicesInputRoutingControl()
- && com.android.systemui.Flags
- .hearingDevicesInputRoutingUiImprovement()) {
+ if (com.android.settingslib.flags.Flags.hearingDevicesInputRoutingControl()) {
setupInputRoutingSpinner(dialog, activeHearingDevice);
}
if (com.android.settingslib.flags.Flags.hearingDevicesAmbientVolumeControl()) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index b16c416..9064966 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -52,6 +52,7 @@
import android.os.Trace;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
+import android.provider.Settings;
import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
@@ -68,7 +69,9 @@
import com.android.internal.logging.InstanceId;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.UserActivityNotifier;
import com.android.systemui.Dumpable;
+import com.android.systemui.Flags;
import com.android.systemui.animation.ActivityTransitionAnimator;
import com.android.systemui.biometrics.dagger.BiometricsBackground;
import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor;
@@ -145,6 +148,7 @@
private final Execution mExecution;
private final FingerprintManager mFingerprintManager;
@NonNull private final LayoutInflater mInflater;
+ private final UserActivityNotifier mUserActivityNotifier;
private final WindowManager mWindowManager;
private final DelayableExecutor mFgExecutor;
@NonNull private final Executor mBiometricExecutor;
@@ -695,11 +699,13 @@
Lazy<DefaultUdfpsTouchOverlayViewModel> defaultUdfpsTouchOverlayViewModel,
@NonNull UdfpsOverlayInteractor udfpsOverlayInteractor,
@NonNull PowerInteractor powerInteractor,
- @Application CoroutineScope scope) {
+ @Application CoroutineScope scope,
+ UserActivityNotifier userActivityNotifier) {
mContext = context;
mExecution = execution;
mVibrator = vibrator;
mInflater = inflater;
+ mUserActivityNotifier = userActivityNotifier;
mIgnoreRefreshRate = mContext.getResources()
.getBoolean(R.bool.config_ignoreUdfpsVote);
// The fingerprint manager is queried for UDFPS before this class is constructed, so the
@@ -920,12 +926,21 @@
true /* isAod */);
};
- if (mScreenOn) {
+ if (isScreenOffUnlockEnabled() || mScreenOn) {
mAodInterruptRunnable.run();
mAodInterruptRunnable = null;
}
}
+ private boolean isScreenOffUnlockEnabled() {
+ return mContext.getResources().getBoolean(R.bool.config_screen_off_udfps_enabled)
+ && Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.SCREEN_OFF_UNLOCK_UDFPS_ENABLED,
+ 0,
+ mContext.getUserId()) != 0;
+ }
+
/**
* Add a callback for fingerUp and fingerDown events
*/
@@ -1035,8 +1050,13 @@
mLatencyTracker.onActionStart(ACTION_UDFPS_ILLUMINATE);
}
// Refresh screen timeout and boost process priority if possible.
- mPowerManager.userActivity(mSystemClock.uptimeMillis(),
- PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
+ if (Flags.bouncerUiRevamp()) {
+ mUserActivityNotifier.notifyUserActivity(mSystemClock.uptimeMillis(),
+ PowerManager.USER_ACTIVITY_EVENT_TOUCH);
+ } else {
+ mPowerManager.userActivity(mSystemClock.uptimeMillis(),
+ PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
+ }
if (!mOnFingerDown) {
playStartHaptic();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index 54c52b5..3b22e13 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -397,7 +397,7 @@
// Talkback directional guidance
udfpsGuidanceView.setOnHoverListener { _, event ->
launch {
- viewModel.onAnnounceAccessibilityHint(
+ viewModel.onUpdateAccessibilityHint(
event,
accessibilityManager.isTouchExplorationEnabled,
)
@@ -406,7 +406,9 @@
}
launch {
viewModel.accessibilityHint.collect { message ->
- if (message.isNotBlank()) view.announceForAccessibility(message)
+ if (message.isNotBlank()) {
+ udfpsGuidanceView.contentDescription = message
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index 0902d19..4e17a26 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -886,7 +886,7 @@
}
/** Sets the message used for UDFPS directional guidance */
- suspend fun onAnnounceAccessibilityHint(
+ suspend fun onUpdateAccessibilityHint(
event: MotionEvent,
touchExplorationEnabled: Boolean,
): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
index 7a60cce..6d58443 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
@@ -36,7 +36,6 @@
import com.android.systemui.res.R;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.utils.windowmanager.WindowManagerProvider;
import dagger.Lazy;
import dagger.Module;
@@ -86,9 +85,8 @@
*/
@Provides
@OverlayWindowContext
- static WindowManager provideWindowManager(@OverlayWindowContext Context context,
- WindowManagerProvider windowManagerProvider) {
- return windowManagerProvider.getWindowManager(context);
+ static WindowManager provideWindowManager(@OverlayWindowContext Context context) {
+ return context.getSystemService(WindowManager.class);
}
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingListener.kt b/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingListener.kt
index af8a5fa2..8bfec0a 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingListener.kt
@@ -21,8 +21,11 @@
import android.service.dreams.Flags.allowDreamWhenPostured
import com.android.app.tracing.coroutines.launchInTraced
import com.android.systemui.CoreStartable
+import com.android.systemui.common.domain.interactor.BatteryInteractor
+import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
import com.android.systemui.communal.posturing.domain.interactor.PosturingInteractor
import com.android.systemui.communal.posturing.shared.model.PosturedState
+import com.android.systemui.communal.shared.model.WhenToDream
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.log.dagger.CommunalTableLog
@@ -30,10 +33,14 @@
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
+import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
+import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@SysUISingleton
@@ -42,19 +49,36 @@
constructor(
private val commandRegistry: CommandRegistry,
private val dreamManager: DreamManager,
- private val interactor: PosturingInteractor,
+ private val posturingInteractor: PosturingInteractor,
+ communalSettingsInteractor: CommunalSettingsInteractor,
+ batteryInteractor: BatteryInteractor,
@Background private val bgScope: CoroutineScope,
@CommunalTableLog private val tableLogBuffer: TableLogBuffer,
) : CoreStartable {
private val command = DevicePosturingCommand()
+ // Only subscribe to posturing if applicable to avoid running the posturing CHRE nanoapp
+ // if posturing signal is not needed.
+ private val postured =
+ allOf(
+ batteryInteractor.isDevicePluggedIn,
+ communalSettingsInteractor.whenToDream.map { it == WhenToDream.WHILE_POSTURED },
+ )
+ .flatMapLatestConflated { shouldListen ->
+ if (shouldListen) {
+ posturingInteractor.postured
+ } else {
+ flowOf(false)
+ }
+ }
+
@SuppressLint("MissingPermission")
override fun start() {
if (!allowDreamWhenPostured()) {
return
}
- interactor.postured
+ postured
.distinctUntilChanged()
.logDiffsForTable(
tableLogBuffer = tableLogBuffer,
@@ -78,7 +102,7 @@
val state =
when (arg.lowercase()) {
- "true" -> PosturedState.Postured(confidence = 1f)
+ "true" -> PosturedState.Postured
"false" -> PosturedState.NotPostured
"clear" -> PosturedState.Unknown
else -> {
@@ -87,7 +111,7 @@
null
}
}
- state?.let { interactor.setValueForDebug(it) }
+ state?.let { posturingInteractor.setValueForDebug(it) }
}
override fun help(pw: PrintWriter) {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractor.kt
index 20bfabd..678a5e2 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalAutoOpenInteractor.kt
@@ -57,7 +57,15 @@
allOf(batteryInteractor.isDevicePluggedIn, dockManager.retrieveIsDocked())
}
WhenToStartHub.WHILE_CHARGING_AND_POSTURED -> {
- allOf(batteryInteractor.isDevicePluggedIn, posturingInteractor.postured)
+ // Only listen to posturing if applicable to avoid running the posturing
+ // CHRE nanoapp when not needed.
+ batteryInteractor.isDevicePluggedIn.flatMapLatestConflated { isCharging ->
+ if (isCharging) {
+ posturingInteractor.postured
+ } else {
+ flowOf(false)
+ }
+ }
}
WhenToStartHub.NEVER -> flowOf(false)
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/posturing/data/model/PositionState.kt b/packages/SystemUI/src/com/android/systemui/communal/posturing/data/model/PositionState.kt
new file mode 100644
index 0000000..21b8dd7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/posturing/data/model/PositionState.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.posturing.data.model
+
+import androidx.annotation.FloatRange
+
+data class PositionState(
+ val stationary: StationaryState = StationaryState.Unknown,
+ val orientation: OrientationState = OrientationState.Unknown,
+) {
+ sealed interface StationaryState {
+ @get:FloatRange(from = 0.0, to = 1.0) val confidence: Float
+
+ data object Unknown : StationaryState {
+ override val confidence: Float = 0f
+ }
+
+ data class Stationary(override val confidence: Float) : StationaryState
+
+ data class NotStationary(override val confidence: Float) : StationaryState
+ }
+
+ sealed interface OrientationState {
+ @get:FloatRange(from = 0.0, to = 1.0) val confidence: Float
+
+ data object Unknown : OrientationState {
+ override val confidence: Float = 0f
+ }
+
+ data class Postured(override val confidence: Float) : OrientationState
+
+ data class NotPostured(override val confidence: Float) : OrientationState
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/posturing/data/repository/NoOpPosturingRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/posturing/data/repository/NoOpPosturingRepository.kt
index c5f357f..d826685 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/posturing/data/repository/NoOpPosturingRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/posturing/data/repository/NoOpPosturingRepository.kt
@@ -16,7 +16,7 @@
package com.android.systemui.communal.posturing.data.repository
-import com.android.systemui.communal.posturing.shared.model.PosturedState
+import com.android.systemui.communal.posturing.data.model.PositionState
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -25,6 +25,6 @@
@SysUISingleton
class NoOpPosturingRepository @Inject constructor() : PosturingRepository {
- override val posturedState: Flow<PosturedState> =
- MutableStateFlow(PosturedState.Unknown).asStateFlow()
+ override val positionState: Flow<PositionState> =
+ MutableStateFlow(PositionState()).asStateFlow()
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/posturing/data/repository/PosturingRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/posturing/data/repository/PosturingRepository.kt
index dae1a47..4de0a1e2 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/posturing/data/repository/PosturingRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/posturing/data/repository/PosturingRepository.kt
@@ -16,7 +16,7 @@
package com.android.systemui.communal.posturing.data.repository
-import com.android.systemui.communal.posturing.shared.model.PosturedState
+import com.android.systemui.communal.posturing.data.model.PositionState
import kotlinx.coroutines.flow.Flow
/**
@@ -25,5 +25,5 @@
*/
interface PosturingRepository {
/** Whether the device is currently stationary and upright. */
- val posturedState: Flow<PosturedState>
+ val positionState: Flow<PositionState>
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractor.kt
index cd81dea..e487590 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractor.kt
@@ -16,26 +16,211 @@
package com.android.systemui.communal.posturing.domain.interactor
+import android.annotation.SuppressLint
+import android.hardware.Sensor
+import android.hardware.TriggerEvent
+import android.hardware.TriggerEventListener
+import android.service.dreams.Flags.allowDreamWhenPostured
+import com.android.systemui.communal.posturing.data.model.PositionState
import com.android.systemui.communal.posturing.data.repository.PosturingRepository
import com.android.systemui.communal.posturing.shared.model.PosturedState
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.Logger
+import com.android.systemui.log.dagger.CommunalLog
+import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
+import com.android.systemui.util.kotlin.slidingWindow
+import com.android.systemui.util.sensors.AsyncSensorManager
+import com.android.systemui.util.time.SystemClock
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filterNot
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
@SysUISingleton
-class PosturingInteractor @Inject constructor(repository: PosturingRepository) {
- private val debugPostured = MutableStateFlow<PosturedState>(PosturedState.Unknown)
+class PosturingInteractor
+@Inject
+constructor(
+ repository: PosturingRepository,
+ private val asyncSensorManager: AsyncSensorManager,
+ @Application private val applicationScope: CoroutineScope,
+ @Background private val bgDispatcher: CoroutineDispatcher,
+ @CommunalLog private val logBuffer: LogBuffer,
+ clock: SystemClock,
+) {
+ private val logger = Logger(logBuffer, TAG)
- val postured: Flow<Boolean> =
- combine(repository.posturedState, debugPostured) { postured, debugValue ->
- debugValue.asBoolean() ?: postured.asBoolean() ?: false
- }
+ private val debugPostured = MutableStateFlow<PosturedState>(PosturedState.Unknown)
fun setValueForDebug(value: PosturedState) {
debugPostured.value = value
}
+
+ /**
+ * Detects whether or not the device is stationary, applying a sliding window smoothing
+ * algorithm.
+ */
+ private val stationarySmoothed: Flow<Boolean> =
+ merge(
+ observeTriggerSensor(Sensor.TYPE_PICK_UP_GESTURE)
+ // If pickup detected, avoid triggering posturing at all within the sliding
+ // window by emitting a negative infinity value.
+ .map { Float.NEGATIVE_INFINITY }
+ .onEach { logger.i("pickup gesture detected") },
+ observeTriggerSensor(Sensor.TYPE_SIGNIFICANT_MOTION)
+ // If motion detected, avoid triggering posturing at all within the sliding
+ // window by emitting a negative infinity value.
+ .map { Float.NEGATIVE_INFINITY }
+ .onEach { logger.i("significant motion detected") },
+ repository.positionState
+ .map { it.stationary }
+ .filterNot { it is PositionState.StationaryState.Unknown }
+ .map { stationaryState ->
+ if (stationaryState is PositionState.StationaryState.Stationary) {
+ stationaryState.confidence
+ } else {
+ // If not stationary, then we should effectively disable posturing by
+ // emitting the lowest possible confidence.
+ Float.NEGATIVE_INFINITY
+ }
+ },
+ )
+ .slidingWindow(SLIDING_WINDOW_DURATION, clock)
+ .filterNot { it.isEmpty() }
+ .map { window ->
+ val avgStationaryConfidence = window.average()
+ logger.i({ "stationary confidence: $double1 | window: $str1" }) {
+ str1 = window.formatWindowForDebugging()
+ double1 = avgStationaryConfidence
+ }
+ avgStationaryConfidence > CONFIDENCE_THRESHOLD
+ }
+
+ /**
+ * Detects whether or not the device is in an upright orientation, applying a sliding window
+ * smoothing algorithm.
+ */
+ private val orientationSmoothed: Flow<Boolean> =
+ repository.positionState
+ .map { it.orientation }
+ .filterNot { it is PositionState.OrientationState.Unknown }
+ .map { orientationState ->
+ if (orientationState is PositionState.OrientationState.Postured) {
+ orientationState.confidence
+ } else {
+ // If not postured, then we should effectively disable posturing by
+ // emitting the lowest possible confidence.
+ Float.NEGATIVE_INFINITY
+ }
+ }
+ .slidingWindow(SLIDING_WINDOW_DURATION, clock)
+ .filterNot { it.isEmpty() }
+ .map { window ->
+ val avgOrientationConfidence = window.average()
+ logger.i({ "orientation confidence: $double1 | window: $str1" }) {
+ str1 = window.formatWindowForDebugging()
+ double1 = avgOrientationConfidence
+ }
+ avgOrientationConfidence > CONFIDENCE_THRESHOLD
+ }
+
+ /**
+ * Posturing is composed of the device being stationary and in the correct orientation. If both
+ * conditions are met, then consider it postured.
+ */
+ private val posturedSmoothed: Flow<PosturedState> =
+ allOf(stationarySmoothed, orientationSmoothed)
+ .map { postured ->
+ if (postured) {
+ PosturedState.Postured
+ } else {
+ PosturedState.NotPostured
+ }
+ }
+ .flowOn(bgDispatcher)
+ .stateIn(
+ scope = applicationScope,
+ // Avoid losing the smoothing history if the user plug/unplugs rapidly.
+ started =
+ SharingStarted.WhileSubscribed(
+ stopTimeoutMillis = STOP_TIMEOUT_AFTER_UNSUBSCRIBE.inWholeMilliseconds,
+ replayExpirationMillis = 0,
+ ),
+ initialValue = PosturedState.Unknown,
+ )
+
+ /**
+ * Whether the device is postured.
+ *
+ * NOTE: Due to smoothing, this signal may be delayed to ensure we have a stable reading before
+ * being considered postured.
+ */
+ val postured: Flow<Boolean> by lazy {
+ if (allowDreamWhenPostured()) {
+ combine(posturedSmoothed, debugPostured) { postured, debugValue ->
+ debugValue.asBoolean() ?: postured.asBoolean() ?: false
+ }
+ } else {
+ MutableStateFlow(false)
+ }
+ }
+
+ /**
+ * Helper for observing a trigger sensor, which automatically unregisters itself after it
+ * executes once.
+ */
+ private fun observeTriggerSensor(type: Int): Flow<Unit> = conflatedCallbackFlow {
+ val sensor = asyncSensorManager.getDefaultSensor(type)
+ val isRegistered = AtomicBoolean(false)
+
+ fun registerCallbackInternal(callback: TriggerEventListener) {
+ if (isRegistered.compareAndSet(false, true)) {
+ asyncSensorManager.requestTriggerSensor(callback, sensor)
+ }
+ }
+
+ val callback =
+ object : TriggerEventListener() {
+ override fun onTrigger(event: TriggerEvent) {
+ trySend(Unit)
+ if (isRegistered.getAndSet(false)) {
+ registerCallbackInternal(this)
+ }
+ }
+ }
+
+ if (sensor != null) {
+ registerCallbackInternal(callback)
+ }
+
+ awaitClose {
+ if (isRegistered.getAndSet(false)) {
+ asyncSensorManager.cancelTriggerSensor(callback, sensor)
+ }
+ }
+ }
+
+ companion object {
+ const val TAG = "PosturingInteractor"
+ val SLIDING_WINDOW_DURATION = 10.seconds
+ const val CONFIDENCE_THRESHOLD = 0.8f
+ val STOP_TIMEOUT_AFTER_UNSUBSCRIBE = 5.seconds
+ }
}
fun PosturedState.asBoolean(): Boolean? {
@@ -45,3 +230,8 @@
PosturedState.Unknown -> null
}
}
+
+@SuppressLint("DefaultLocale")
+fun List<Float>.formatWindowForDebugging(): String {
+ return joinToString(prefix = "[", postfix = "]") { String.format("%.2f", it) }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/posturing/shared/model/PosturedState.kt b/packages/SystemUI/src/com/android/systemui/communal/posturing/shared/model/PosturedState.kt
index 431ca67..c71cf14 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/posturing/shared/model/PosturedState.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/posturing/shared/model/PosturedState.kt
@@ -18,7 +18,7 @@
sealed interface PosturedState {
/** Represents postured state */
- data class Postured(val confidence: Float) : PosturedState
+ data object Postured : PosturedState
/** Represents unknown/uninitialized state */
data object Unknown : PosturedState
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceSupplier.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceSupplier.kt
index ed77e6f..b86c23b 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceSupplier.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceSupplier.kt
@@ -62,6 +62,10 @@
userTracker.removeCallback(this)
}
+ override fun alertUnstableService(unstableService: String?) {
+ // Unused. Do nothing.
+ }
+
override fun onBeforeUserSwitching(newUser: Int) {
userAboutToSwitch = true
listener?.onServiceChanged()
diff --git a/packages/SystemUI/src/com/android/systemui/cursorposition/data/model/CursorPosition.kt b/packages/SystemUI/src/com/android/systemui/cursorposition/data/model/CursorPosition.kt
new file mode 100644
index 0000000..65174cc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/cursorposition/data/model/CursorPosition.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.cursorposition.data.model
+
+/**
+ * Represents the position of cursor hotspot on the screen. Hotspot is the specific pixel that
+ * signifies the location of the pointer's interaction with the user interface. By default, hotspot
+ * of a cursor is the tip of arrow.
+ *
+ * @property x The x-coordinate of the cursor hotspot, relative to the top-left corner of the
+ * screen.
+ * @property y The y-coordinate of the cursor hotspot, relative to the top-left corner of the
+ * screen.
+ * @property displayId The display on which the cursor is located.
+ */
+data class CursorPosition(val x: Float, val y: Float, val displayId: Int)
diff --git a/packages/SystemUI/src/com/android/systemui/cursorposition/data/repository/MultiDisplayCursorPositionRepository.kt b/packages/SystemUI/src/com/android/systemui/cursorposition/data/repository/MultiDisplayCursorPositionRepository.kt
new file mode 100644
index 0000000..37f4a4c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/cursorposition/data/repository/MultiDisplayCursorPositionRepository.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.cursorposition.data.repository
+
+import com.android.app.displaylib.PerDisplayRepository
+import com.android.systemui.cursorposition.data.model.CursorPosition
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.display.data.repository.DisplayRepository
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asFlow
+import kotlinx.coroutines.flow.emitAll
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapMerge
+import kotlinx.coroutines.flow.mapNotNull
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
+
+/** Repository for cursor position of multi displays. */
+interface MultiDisplayCursorPositionRepository {
+ val cursorPositions: Flow<CursorPosition?>
+}
+
+/**
+ * Implementation of [MultiDisplayCursorPositionRepository] that aggregates cursor position updates
+ * from multiple displays.
+ *
+ * This class uses a [DisplayRepository] to track added displays and a [PerDisplayRepository] to
+ * manage [SingleDisplayCursorPositionRepository] instances for each display. [PerDisplayRepository]
+ * would destroy the instance if the display is removed. This class combines the cursor position
+ * from all displays into a single cursorPositions StateFlow.
+ */
+@SysUISingleton
+class MultiDisplayCursorPositionRepositoryImpl
+@Inject
+constructor(
+ private val displayRepository: DisplayRepository,
+ @Background private val backgroundScope: CoroutineScope,
+ private val cursorRepositories: PerDisplayRepository<SingleDisplayCursorPositionRepository>,
+) : MultiDisplayCursorPositionRepository {
+
+ private val allDisplaysCursorPositions: Flow<CursorPosition> =
+ displayRepository.displayAdditionEvent
+ .mapNotNull { c -> c?.displayId }
+ .onStart { emitAll(displayRepository.displayIds.value.asFlow()) }
+ .flatMapMerge {
+ val repo = cursorRepositories[it]
+ repo?.cursorPositions ?: emptyFlow()
+ }
+
+ override val cursorPositions: StateFlow<CursorPosition?> =
+ allDisplaysCursorPositions.stateIn(backgroundScope, SharingStarted.WhileSubscribed(), null)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/cursorposition/data/repository/SingleDisplayCursorPositionRepository.kt b/packages/SystemUI/src/com/android/systemui/cursorposition/data/repository/SingleDisplayCursorPositionRepository.kt
new file mode 100644
index 0000000..f532fb2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/cursorposition/data/repository/SingleDisplayCursorPositionRepository.kt
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.cursorposition.data.repository
+
+import android.os.Handler
+import android.os.Looper
+import android.view.Choreographer
+import android.view.InputDevice.SOURCE_MOUSE
+import android.view.InputDevice.SOURCE_TOUCHPAD
+import android.view.MotionEvent
+import com.android.app.displaylib.PerDisplayInstanceProviderWithTeardown
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.cursorposition.data.model.CursorPosition
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.shared.system.InputChannelCompat
+import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver
+import com.android.systemui.shared.system.InputMonitorCompat
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import javax.inject.Inject
+import kotlinx.coroutines.android.asCoroutineDispatcher
+import kotlinx.coroutines.channels.ProducerScope
+import kotlinx.coroutines.channels.SendChannel
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOn
+
+/** Repository for cursor position in single display. */
+interface SingleDisplayCursorPositionRepository {
+ /** Flow of [CursorPosition] for the display. */
+ val cursorPositions: Flow<CursorPosition>
+
+ /** Destroys the repository. */
+ fun destroy()
+}
+
+/**
+ * Implementation of [SingleDisplayCursorPositionRepository].
+ *
+ * @param displayId the display id
+ * @param backgroundHandler the background handler
+ * @param listenerBuilder the builder for [InputChannelCompat.InputEventListener]
+ * @param inputMonitorBuilder the builder for [InputMonitorCompat]
+ */
+class SingleDisplayCursorPositionRepositoryImpl
+@AssistedInject
+constructor(
+ @Assisted displayId: Int,
+ @Background private val backgroundHandler: Handler,
+ @Assisted
+ private val listenerBuilder: InputEventListenerBuilder = defaultInputEventListenerBuilder,
+ @Assisted private val inputMonitorBuilder: InputMonitorBuilder = defaultInputMonitorBuilder,
+) : SingleDisplayCursorPositionRepository {
+
+ private var scope: ProducerScope<CursorPosition>? = null
+
+ private fun createInputMonitorCallbackFlow(displayId: Int): Flow<CursorPosition> =
+ conflatedCallbackFlow {
+ val inputMonitor: InputMonitorCompat = inputMonitorBuilder.build(TAG, displayId)
+ val inputReceiver: InputEventReceiver =
+ inputMonitor.getInputReceiver(
+ Looper.myLooper(),
+ Choreographer.getInstance(),
+ listenerBuilder.build(this),
+ )
+ scope = this
+ awaitClose {
+ inputMonitor.dispose()
+ inputReceiver.dispose()
+ }
+ }
+ // Use backgroundHandler as dispatcher because it has a looper (unlike
+ // "backgroundDispatcher" which does not have a looper) and input receiver could use
+ // its background looper and choreographer
+ .flowOn(backgroundHandler.asCoroutineDispatcher())
+
+ override val cursorPositions: Flow<CursorPosition> = createInputMonitorCallbackFlow(displayId)
+
+ override fun destroy() {
+ scope?.close()
+ }
+
+ @AssistedFactory
+ interface Factory {
+ /**
+ * Creates a new instance of [SingleDisplayCursorPositionRepositoryImpl] for a given
+ * [displayId].
+ */
+ fun create(
+ displayId: Int,
+ listenerBuilder: InputEventListenerBuilder = defaultInputEventListenerBuilder,
+ inputMonitorBuilder: InputMonitorBuilder = defaultInputMonitorBuilder,
+ ): SingleDisplayCursorPositionRepositoryImpl
+ }
+
+ companion object {
+ private const val TAG = "CursorPositionPerDisplayRepositoryImpl"
+
+ private val defaultInputMonitorBuilder = InputMonitorBuilder { name, displayId ->
+ InputMonitorCompat(name, displayId)
+ }
+
+ val defaultInputEventListenerBuilder = InputEventListenerBuilder { channel ->
+ InputChannelCompat.InputEventListener { event ->
+ if (
+ event is MotionEvent &&
+ (event.source == SOURCE_MOUSE || event.source == SOURCE_TOUCHPAD)
+ ) {
+ val cursorEvent = CursorPosition(event.x, event.y, event.displayId)
+ channel.trySendWithFailureLogging(cursorEvent, TAG)
+ }
+ }
+ }
+ }
+}
+
+fun interface InputEventListenerBuilder {
+ fun build(channel: SendChannel<CursorPosition>): InputChannelCompat.InputEventListener
+}
+
+fun interface InputMonitorBuilder {
+ fun build(name: String, displayId: Int): InputMonitorCompat
+}
+
+@SysUISingleton
+class SingleDisplayCursorPositionRepositoryFactory
+@Inject
+constructor(private val factory: SingleDisplayCursorPositionRepositoryImpl.Factory) :
+ PerDisplayInstanceProviderWithTeardown<SingleDisplayCursorPositionRepository> {
+ override fun createInstance(displayId: Int): SingleDisplayCursorPositionRepository {
+ return factory.create(displayId)
+ }
+
+ override fun destroyInstance(instance: SingleDisplayCursorPositionRepository) {
+ instance.destroy()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractor.kt
index 54f3d79..a871fb6 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractor.kt
@@ -16,10 +16,12 @@
package com.android.systemui.deviceentry.domain.interactor
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
@@ -31,13 +33,19 @@
constructor(
deviceEntrySourceInteractor: DeviceEntrySourceInteractor,
deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+ keyguardInteractor: KeyguardInteractor,
) {
+ private val successfulEntryFromDeviceEntryIcon: Flow<Unit> =
+ deviceEntrySourceInteractor.attemptEnterDeviceFromDeviceEntryIcon
+ .map { keyguardInteractor.isKeyguardDismissible.value }
+ .filter { it } // only emit events if the keyguard is dismissible
+ // map to Unit
+ .map {}
+
private val showUnlockRippleFromDeviceEntryIcon: Flow<BiometricUnlockSource> =
deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { isUdfpsSupported ->
if (isUdfpsSupported) {
- deviceEntrySourceInteractor.deviceEntryFromDeviceEntryIcon.map {
- BiometricUnlockSource.FINGERPRINT_SENSOR
- }
+ successfulEntryFromDeviceEntryIcon.map { BiometricUnlockSource.FINGERPRINT_SENSOR }
} else {
emptyFlow()
}
@@ -46,8 +54,5 @@
private val showUnlockRippleFromBiometricUnlock: Flow<BiometricUnlockSource> =
deviceEntrySourceInteractor.deviceEntryFromBiometricSource
val showUnlockRipple: Flow<BiometricUnlockSource> =
- merge(
- showUnlockRippleFromDeviceEntryIcon,
- showUnlockRippleFromBiometricUnlock,
- )
+ merge(showUnlockRippleFromDeviceEntryIcon, showUnlockRippleFromBiometricUnlock)
}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt
index 0993683..452cc43 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt
@@ -16,12 +16,14 @@
package com.android.systemui.deviceentry.domain.interactor
import com.android.keyguard.logging.BiometricUnlockLogger
+import com.android.systemui.Flags
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.util.kotlin.FlowDumperImpl
@@ -54,6 +56,7 @@
keyEventInteractor: KeyEventInteractor,
private val logger: BiometricUnlockLogger,
powerInteractor: PowerInteractor,
+ keyguardInteractor: KeyguardInteractor,
private val systemClock: SystemClock,
dumpManager: DumpManager,
) : FlowDumperImpl(dumpManager) {
@@ -80,12 +83,7 @@
emit(recentPowerButtonPressThresholdMs * -1L - 1L)
}
- /**
- * Indicates when success haptics should play when the device is entered. This always occurs on
- * successful fingerprint authentications. It also occurs on successful face authentication but
- * only if the lockscreen is bypassed.
- */
- val playSuccessHapticOnDeviceEntry: Flow<Unit> =
+ private val playSuccessHapticOnDeviceEntryFromBiometricSource: Flow<Unit> =
deviceEntrySourceInteractor.deviceEntryFromBiometricSource
.sample(
combine(
@@ -108,7 +106,31 @@
}
// map to Unit
.map {}
- .dumpWhileCollecting("playSuccessHaptic")
+
+ private val playSuccessHapticOnDeviceEntryFromDeviceEntryIcon: Flow<Unit> =
+ deviceEntrySourceInteractor.attemptEnterDeviceFromDeviceEntryIcon
+ .map { keyguardInteractor.isKeyguardDismissible.value }
+ .filter { it } // only play if the keyguard is dismissible
+ // map to Unit
+ .map {}
+
+ /**
+ * Indicates when success haptics should play when the device is entered. When entering via a
+ * biometric sources, this always occurs on successful fingerprint authentications. It also
+ * occurs on successful face authentication but only if the lockscreen is bypassed.
+ */
+ val playSuccessHapticOnDeviceEntry: Flow<Unit> =
+ if (Flags.msdlFeedback()) {
+ merge(
+ playSuccessHapticOnDeviceEntryFromBiometricSource,
+ playSuccessHapticOnDeviceEntryFromDeviceEntryIcon,
+ )
+ .dumpWhileCollecting("playSuccessHaptic")
+ } else {
+ playSuccessHapticOnDeviceEntryFromBiometricSource.dumpWhileCollecting(
+ "playSuccessHaptic"
+ )
+ }
private val playErrorHapticForBiometricFailure: Flow<Unit> =
merge(
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractor.kt
index 5de2ed2..19a15fc 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractor.kt
@@ -254,15 +254,12 @@
}
.dumpWhileCollecting("deviceEntryFromBiometricSource")
- private val attemptEnterDeviceFromDeviceEntryIcon: MutableSharedFlow<Unit> = MutableSharedFlow()
- val deviceEntryFromDeviceEntryIcon: Flow<Unit> =
- attemptEnterDeviceFromDeviceEntryIcon
- .sample(keyguardInteractor.isKeyguardDismissible)
- .filter { it } // only send events if the keyguard is dismissible
- .map {} // map to Unit
+ private val _attemptEnterDeviceFromDeviceEntryIcon: MutableSharedFlow<Unit> =
+ MutableSharedFlow()
+ val attemptEnterDeviceFromDeviceEntryIcon = _attemptEnterDeviceFromDeviceEntryIcon
suspend fun attemptEnterDeviceFromDeviceEntryIcon() {
- attemptEnterDeviceFromDeviceEntryIcon.emit(Unit)
+ _attemptEnterDeviceFromDeviceEntryIcon.emit(Unit)
}
private fun biometricModeIntToObject(@WakeAndUnlockMode value: Int): BiometricUnlockMode {
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/ui/view/UdfpsAccessibilityOverlay.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/view/UdfpsAccessibilityOverlay.kt
index 7be3230..9c3b9b2 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/ui/view/UdfpsAccessibilityOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/view/UdfpsAccessibilityOverlay.kt
@@ -20,4 +20,8 @@
import android.view.View
/** Overlay to handle under-fingerprint sensor accessibility events. */
-class UdfpsAccessibilityOverlay(context: Context?) : View(context)
+class UdfpsAccessibilityOverlay(context: Context?) : View(context) {
+ init {
+ accessibilityLiveRegion = ACCESSIBILITY_LIVE_REGION_ASSERTIVE
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/UdfpsAccessibilityOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/UdfpsAccessibilityOverlayViewModel.kt
index fa849bf..1849bf2 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/UdfpsAccessibilityOverlayViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/UdfpsAccessibilityOverlayViewModel.kt
@@ -56,7 +56,7 @@
event.getPointerId(0),
event,
overlayParams, /* rotateToPortrait */
- false
+ false,
)
if (
@@ -64,7 +64,7 @@
event.getPointerId(0),
event,
overlayParams,
- /* rotateTouchToPortrait */ false
+ /* rotateTouchToPortrait */ false,
)
) {
// view only receives motionEvents when [visible] which requires touchExplorationEnabled
@@ -75,10 +75,10 @@
scaledTouch.x,
scaledTouch.y,
overlayParams,
- /* touchRotatedToPortrait */ false
+ /* touchRotatedToPortrait */ false,
)
if (announceStr != null) {
- v.announceForAccessibility(announceStr)
+ v.contentDescription = announceStr
}
}
// always let the motion events go through to underlying views
diff --git a/packages/SystemUI/src/com/android/systemui/display/dagger/PerDisplayCommonModule.kt b/packages/SystemUI/src/com/android/systemui/display/dagger/PerDisplayCommonModule.kt
new file mode 100644
index 0000000..6fb3727
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/dagger/PerDisplayCommonModule.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.display.dagger
+
+import android.content.Context
+import android.view.Display
+import com.android.app.displaylib.DisplayRepository
+import com.android.systemui.coroutines.newTracingContext
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent.DisplayAware
+import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent.DisplayId
+import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent.PerDisplaySingleton
+import dagger.Module
+import dagger.Provides
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+
+/** Module providing common dependencies for per-display singletons. */
+@Module
+class PerDisplayCommonModule {
+
+ @Provides
+ @PerDisplaySingleton
+ fun provideDisplay(@DisplayId displayId: Int, displayRepository: DisplayRepository): Display {
+ return displayRepository.getDisplay(displayId)
+ ?: error("Couldn't get the display with id=$displayId")
+ }
+
+ @Provides
+ @PerDisplaySingleton
+ @DisplayAware
+ fun provideDisplayContext(
+ display: Display,
+ @Application context: Context,
+ ): Context {
+ return context.createDisplayContext(display)
+ }
+
+ @Provides
+ @PerDisplaySingleton
+ @DisplayAware
+ fun provideDisplayCoroutineScope(
+ @Background backgroundDispatcher: CoroutineDispatcher,
+ @DisplayId displayId: Int,
+ ): CoroutineScope {
+ return CoroutineScope(
+ backgroundDispatcher + newTracingContext("DisplayScope(id=$displayId)")
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/display/dagger/SystemUIDisplaySubcomponent.kt b/packages/SystemUI/src/com/android/systemui/display/dagger/SystemUIDisplaySubcomponent.kt
new file mode 100644
index 0000000..f878aa1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/dagger/SystemUIDisplaySubcomponent.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.display.dagger
+
+import dagger.BindsInstance
+import dagger.Subcomponent
+import javax.inject.Qualifier
+import javax.inject.Scope
+import kotlinx.coroutines.CoroutineScope
+
+/**
+ * Subcomponent for SysUI classes that should be instantiated once per display.
+ *
+ * All display specific classes should be provided with the @DisplayAware annotation. Once the
+ * display is removed, [displayCoroutineScope] gets cancelled. This means that if classes have some
+ * teardown step it should be executed when the scope is cancelled. Also note that the scope is
+ * cancelled in the background, so any teardown logic should be threadsafe. Cancelling on the main
+ * thread is not feasible as it would cause jank.
+ */
+@Subcomponent(modules = [PerDisplayCommonModule::class])
+interface SystemUIDisplaySubcomponent {
+
+ @DisplayAware val displayCoroutineScope: CoroutineScope
+
+ @Subcomponent.Factory
+ interface Factory {
+ fun create(@BindsInstance @DisplayId displayId: Int): SystemUIDisplaySubcomponent
+ }
+
+ /** Scope annotation for singletons associated to a display. */
+ @MustBeDocumented
+ @Retention(AnnotationRetention.RUNTIME)
+ @Scope
+ annotation class PerDisplaySingleton
+
+ /** Qualifier used to represent that the object is provided/bound with the proper display. */
+ @Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class DisplayAware
+
+ /** Annotates the display id inside the subcomponent. */
+ @Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class DisplayId
+}
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayComponentRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayComponentRepository.kt
new file mode 100644
index 0000000..a2d3b35
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayComponentRepository.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.display.data.repository
+
+import com.android.app.displaylib.PerDisplayInstanceProviderWithTeardown
+import com.android.app.displaylib.PerDisplayInstanceRepositoryImpl
+import com.android.app.displaylib.PerDisplayRepository
+import com.android.app.tracing.traceSection
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent
+import dagger.Module
+import dagger.Provides
+import javax.inject.Inject
+import kotlinx.coroutines.cancel
+
+@SysUISingleton
+class DisplayComponentInstanceProvider
+@Inject
+constructor(private val componentFactory: SystemUIDisplaySubcomponent.Factory) :
+ PerDisplayInstanceProviderWithTeardown<SystemUIDisplaySubcomponent> {
+ override fun createInstance(displayId: Int): SystemUIDisplaySubcomponent? =
+ runCatching { componentFactory.create(displayId) }.getOrNull()
+
+ override fun destroyInstance(instance: SystemUIDisplaySubcomponent) {
+ traceSection("Destroying a display component instance") {
+ instance.displayCoroutineScope.cancel("Cancelling scope associated to the display.")
+ }
+ }
+}
+
+@Module
+object DisplayComponentRepository {
+ @SysUISingleton
+ @Provides
+ fun provideDisplayComponentRepository(
+ repositoryFactory: PerDisplayInstanceRepositoryImpl.Factory<SystemUIDisplaySubcomponent>,
+ instanceProvider: DisplayComponentInstanceProvider,
+ ): PerDisplayRepository<SystemUIDisplaySubcomponent> {
+ return repositoryFactory.create(
+ debugName = "DisplayComponentInstanceProvider",
+ instanceProvider,
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
index aaaaace..792d328 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
@@ -31,7 +31,6 @@
import com.android.systemui.res.R
import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
-import com.android.systemui.utils.windowmanager.WindowManagerUtils
import com.google.common.collect.HashBasedTable
import com.google.common.collect.Table
import java.io.PrintWriter
@@ -111,7 +110,7 @@
return null
}
@SuppressLint("NonInjectedService") // Need to manually get the service
- val windowManager = WindowManagerUtils.getWindowManager(context)
+ val windowManager = context.getSystemService(WindowManager::class.java)
val layoutInflater = LayoutInflater.from(context)
DisplayWindowProperties(displayId, windowType, context, windowManager, layoutInflater)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCustomizationModeRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCustomizationModeRepository.kt
new file mode 100644
index 0000000..2f16b9f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCustomizationModeRepository.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.keyboard.shortcut.data.repository
+
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.combine
+
+class ShortcutHelperCustomizationModeRepository
+@Inject
+constructor(shortcutHelperStateRepository: ShortcutHelperStateRepository) {
+ private val _isCustomizationModeEnabled = MutableStateFlow(false)
+ val isCustomizationModeEnabled =
+ combine(_isCustomizationModeEnabled, shortcutHelperStateRepository.state) {
+ isCustomizationModeEnabled,
+ shortcutHelperState ->
+ isCustomizationModeEnabled && shortcutHelperState is ShortcutHelperState.Active
+ }
+
+ fun toggleCustomizationMode(isCustomizing: Boolean) {
+ _isCustomizationModeEnabled.value = isCustomizing
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/UserVisibleAppsRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/UserVisibleAppsRepository.kt
new file mode 100644
index 0000000..5a4ee16
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/UserVisibleAppsRepository.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.keyboard.shortcut.data.repository
+
+import android.content.Context
+import android.content.pm.LauncherActivityInfo
+import android.content.pm.LauncherApps
+import android.os.Handler
+import android.os.UserHandle
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+@SysUISingleton
+class UserVisibleAppsRepository
+@Inject
+constructor(
+ private val userTracker: UserTracker,
+ @Background private val bgExecutor: Executor,
+ @Background private val bgHandler: Handler,
+ private val launcherApps: LauncherApps,
+) {
+
+ val userVisibleApps: Flow<List<LauncherActivityInfo>>
+ get() = conflatedCallbackFlow {
+ val packageChangeCallback: LauncherApps.Callback =
+ object : LauncherApps.Callback() {
+ override fun onPackageAdded(packageName: String, userHandle: UserHandle) {
+ trySendWithFailureLogging(
+ element = retrieveLauncherApps(),
+ loggingTag = TAG,
+ elementDescription = ON_PACKAGE_ADDED,
+ )
+ }
+
+ override fun onPackageChanged(packageName: String, userHandle: UserHandle) {
+ trySendWithFailureLogging(
+ element = retrieveLauncherApps(),
+ loggingTag = TAG,
+ elementDescription = ON_PACKAGE_CHANGED,
+ )
+ }
+
+ override fun onPackageRemoved(packageName: String, userHandle: UserHandle) {
+ trySendWithFailureLogging(
+ element = retrieveLauncherApps(),
+ loggingTag = TAG,
+ elementDescription = ON_PACKAGE_REMOVED,
+ )
+ }
+
+ override fun onPackagesAvailable(
+ packages: Array<out String>,
+ userHandle: UserHandle,
+ replacing: Boolean,
+ ) {
+ trySendWithFailureLogging(
+ element = retrieveLauncherApps(),
+ loggingTag = TAG,
+ elementDescription = ON_PACKAGES_AVAILABLE,
+ )
+ }
+
+ override fun onPackagesUnavailable(
+ packages: Array<out String>,
+ userHandle: UserHandle,
+ replacing: Boolean,
+ ) {
+ trySendWithFailureLogging(
+ element = retrieveLauncherApps(),
+ loggingTag = TAG,
+ elementDescription = ON_PACKAGES_UNAVAILABLE,
+ )
+ }
+ }
+
+ val userChangeCallback =
+ object : UserTracker.Callback {
+ override fun onUserChanged(newUser: Int, userContext: Context) {
+ trySendWithFailureLogging(
+ element = retrieveLauncherApps(),
+ loggingTag = TAG,
+ elementDescription = ON_USER_CHANGED,
+ )
+ }
+ }
+
+ userTracker.addCallback(userChangeCallback, bgExecutor)
+ launcherApps.registerCallback(packageChangeCallback, bgHandler)
+
+ trySendWithFailureLogging(
+ element = retrieveLauncherApps(),
+ loggingTag = TAG,
+ elementDescription = INITIAL_VALUE,
+ )
+
+ awaitClose {
+ userTracker.removeCallback(userChangeCallback)
+ launcherApps.unregisterCallback(packageChangeCallback)
+ }
+ }
+
+ private fun retrieveLauncherApps(): List<LauncherActivityInfo> {
+ return launcherApps.getActivityList(/* packageName= */ null, userTracker.userHandle)
+ }
+
+ private companion object {
+ const val TAG = "UserVisibleAppsRepository"
+ const val ON_PACKAGE_ADDED = "onPackageAdded"
+ const val ON_PACKAGE_CHANGED = "onPackageChanged"
+ const val ON_PACKAGE_REMOVED = "onPackageRemoved"
+ const val ON_PACKAGES_AVAILABLE = "onPackagesAvailable"
+ const val ON_PACKAGES_UNAVAILABLE = "onPackagesUnavailable"
+ const val ON_USER_CHANGED = "onUserChanged"
+ const val INITIAL_VALUE = "InitialValue"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCustomizationModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCustomizationModeInteractor.kt
new file mode 100644
index 0000000..2cec991
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCustomizationModeInteractor.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.keyboard.shortcut.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperCustomizationModeRepository
+import javax.inject.Inject
+
+@SysUISingleton
+class ShortcutHelperCustomizationModeInteractor
+@Inject
+constructor(private val customizationModeRepository: ShortcutHelperCustomizationModeRepository) {
+ val customizationMode = customizationModeRepository.isCustomizationModeEnabled
+
+ fun toggleCustomizationMode(isCustomizing: Boolean) {
+ customizationModeRepository.toggleCustomizationMode(isCustomizing)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt
index ea36a10..81efaac 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt
@@ -85,9 +85,12 @@
shortcutsUiState = shortcutsUiState,
onKeyboardSettingsClicked = { onKeyboardSettingsClicked(dialog) },
onSearchQueryChanged = { shortcutHelperViewModel.onSearchQueryChanged(it) },
- onCustomizationRequested = {
+ onShortcutCustomizationRequested = {
shortcutCustomizationDialogStarter.onShortcutCustomizationRequested(it)
},
+ onCustomizationModeToggled = { isCustomizing ->
+ shortcutHelperViewModel.toggleCustomizationMode(isCustomizing)
+ },
)
dialog.setOnDismissListener { shortcutHelperViewModel.onViewClosed() }
dialog.setTitle(stringResource(R.string.shortcut_helper_title))
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
index b0e5545..72b984e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
@@ -138,7 +138,8 @@
modifier: Modifier = Modifier,
shortcutsUiState: ShortcutsUiState,
useSinglePane: @Composable () -> Boolean = { shouldUseSinglePane() },
- onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
+ onShortcutCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
+ onCustomizationModeToggled: (Boolean) -> Unit = {},
) {
when (shortcutsUiState) {
is ShortcutsUiState.Active -> {
@@ -146,9 +147,10 @@
shortcutsUiState,
useSinglePane,
onSearchQueryChanged,
+ onCustomizationModeToggled,
modifier,
onKeyboardSettingsClicked,
- onCustomizationRequested,
+ onShortcutCustomizationRequested,
)
}
@@ -163,9 +165,10 @@
shortcutsUiState: ShortcutsUiState.Active,
useSinglePane: @Composable () -> Boolean,
onSearchQueryChanged: (String) -> Unit,
+ onCustomizationModeToggled: (Boolean) -> Unit,
modifier: Modifier,
onKeyboardSettingsClicked: () -> Unit,
- onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
+ onShortcutCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
) {
var selectedCategoryType by
remember(shortcutsUiState.defaultSelectedCategory) {
@@ -185,14 +188,16 @@
ShortcutHelperTwoPane(
shortcutsUiState.searchQuery,
onSearchQueryChanged,
- modifier,
shortcutsUiState.shortcutCategories,
selectedCategoryType,
onCategorySelected = { selectedCategoryType = it },
onKeyboardSettingsClicked,
shortcutsUiState.isShortcutCustomizerFlagEnabled,
- onCustomizationRequested,
shortcutsUiState.shouldShowResetButton,
+ shortcutsUiState.isCustomizationModeEnabled,
+ onCustomizationModeToggled,
+ modifier,
+ onShortcutCustomizationRequested,
)
}
}
@@ -376,17 +381,18 @@
private fun ShortcutHelperTwoPane(
searchQuery: String,
onSearchQueryChanged: (String) -> Unit,
- modifier: Modifier = Modifier,
categories: List<ShortcutCategoryUi>,
selectedCategoryType: ShortcutCategoryType?,
onCategorySelected: (ShortcutCategoryType?) -> Unit,
onKeyboardSettingsClicked: () -> Unit,
isShortcutCustomizerFlagEnabled: Boolean,
- onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
shouldShowResetButton: Boolean,
+ isCustomizationModeEnabled: Boolean,
+ onCustomizationModeToggled: (isCustomizing: Boolean) -> Unit,
+ modifier: Modifier = Modifier,
+ onShortcutCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
) {
val selectedCategory = categories.fastFirstOrNull { it.type == selectedCategoryType }
- var isCustomizing by remember { mutableStateOf(false) }
Column(modifier = modifier.fillMaxSize().padding(horizontal = 24.dp)) {
Row(
@@ -397,14 +403,18 @@
// Keep title centered whether customize button is visible or not.
Spacer(modifier = Modifier.weight(1f))
Box(modifier = Modifier.width(412.dp), contentAlignment = Alignment.Center) {
- TitleBar(isCustomizing)
+ TitleBar(isCustomizationModeEnabled)
}
if (isShortcutCustomizerFlagEnabled) {
CustomizationButtonsContainer(
modifier = Modifier.weight(1f),
- isCustomizing = isCustomizing,
- onToggleCustomizationMode = { isCustomizing = !isCustomizing },
- onReset = { onCustomizationRequested(ShortcutCustomizationRequestInfo.Reset) },
+ isCustomizing = isCustomizationModeEnabled,
+ onToggleCustomizationMode = {
+ onCustomizationModeToggled(!isCustomizationModeEnabled)
+ },
+ onReset = {
+ onShortcutCustomizationRequested(ShortcutCustomizationRequestInfo.Reset)
+ },
shouldShowResetButton = shouldShowResetButton,
)
} else {
@@ -426,8 +436,8 @@
searchQuery,
Modifier.fillMaxSize().padding(top = 8.dp).semantics { isTraversalGroup = true },
selectedCategory,
- isCustomizing = isCustomizing,
- onCustomizationRequested = onCustomizationRequested,
+ isCustomizing = isCustomizationModeEnabled,
+ onShortcutCustomizationRequested = onShortcutCustomizationRequested,
)
}
}
@@ -496,7 +506,7 @@
modifier: Modifier,
category: ShortcutCategoryUi?,
isCustomizing: Boolean,
- onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
+ onShortcutCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
) {
val listState = rememberLazyListState()
LaunchedEffect(key1 = category) { if (category != null) listState.animateScrollToItem(0) }
@@ -510,16 +520,20 @@
searchQuery = searchQuery,
subCategory = subcategory,
isCustomizing = isCustomizing and category.type.includeInCustomization,
- onCustomizationRequested = { requestInfo ->
+ onShortcutCustomizationRequested = { requestInfo ->
when (requestInfo) {
is ShortcutCustomizationRequestInfo.SingleShortcutCustomization.Add ->
- onCustomizationRequested(requestInfo.copy(categoryType = category.type))
+ onShortcutCustomizationRequested(
+ requestInfo.copy(categoryType = category.type)
+ )
is ShortcutCustomizationRequestInfo.SingleShortcutCustomization.Delete ->
- onCustomizationRequested(requestInfo.copy(categoryType = category.type))
+ onShortcutCustomizationRequested(
+ requestInfo.copy(categoryType = category.type)
+ )
ShortcutCustomizationRequestInfo.Reset ->
- onCustomizationRequested(requestInfo)
+ onShortcutCustomizationRequested(requestInfo)
}
},
)
@@ -551,7 +565,7 @@
searchQuery: String,
subCategory: ShortcutSubCategory,
isCustomizing: Boolean,
- onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit,
+ onShortcutCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit,
) {
Surface(
modifier = Modifier.fillMaxWidth(),
@@ -573,20 +587,20 @@
searchQuery = searchQuery,
shortcut = shortcut,
isCustomizing = isCustomizing && shortcut.isCustomizable,
- onCustomizationRequested = { requestInfo ->
+ onShortcutCustomizationRequested = { requestInfo ->
when (requestInfo) {
is ShortcutCustomizationRequestInfo.SingleShortcutCustomization.Add ->
- onCustomizationRequested(
+ onShortcutCustomizationRequested(
requestInfo.copy(subCategoryLabel = subCategory.label)
)
is ShortcutCustomizationRequestInfo.SingleShortcutCustomization.Delete ->
- onCustomizationRequested(
+ onShortcutCustomizationRequested(
requestInfo.copy(subCategoryLabel = subCategory.label)
)
ShortcutCustomizationRequestInfo.Reset ->
- onCustomizationRequested(requestInfo)
+ onShortcutCustomizationRequested(requestInfo)
}
},
)
@@ -610,7 +624,7 @@
searchQuery: String,
shortcut: ShortcutModel,
isCustomizing: Boolean = false,
- onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
+ onShortcutCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
) {
val interactionSource = remember { MutableInteractionSource() }
val isFocused by interactionSource.collectIsFocusedAsState()
@@ -650,7 +664,7 @@
shortcut = shortcut,
isCustomizing = isCustomizing,
onAddShortcutRequested = {
- onCustomizationRequested(
+ onShortcutCustomizationRequested(
ShortcutCustomizationRequestInfo.SingleShortcutCustomization.Add(
label = shortcut.label,
shortcutCommand = shortcut.commands.first(),
@@ -658,7 +672,7 @@
)
},
onDeleteShortcutRequested = {
- onCustomizationRequested(
+ onShortcutCustomizationRequested(
ShortcutCustomizationRequestInfo.SingleShortcutCustomization.Delete(
label = shortcut.label,
shortcutCommand = shortcut.commands.first(),
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutsUiState.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutsUiState.kt
index 52ab157..b474ae6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutsUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutsUiState.kt
@@ -26,6 +26,7 @@
val defaultSelectedCategory: ShortcutCategoryType?,
val isShortcutCustomizerFlagEnabled: Boolean = false,
val shouldShowResetButton: Boolean = false,
+ val isCustomizationModeEnabled: Boolean = false,
) : ShortcutsUiState
data object Inactive : ShortcutsUiState
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
index f11205f..5937308 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
@@ -21,7 +21,6 @@
import android.content.pm.PackageManager.NameNotFoundException
import android.util.Log
import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Accessibility
import androidx.compose.material.icons.filled.AccessibilityNew
import androidx.compose.material.icons.filled.Android
import androidx.compose.material.icons.filled.Apps
@@ -32,6 +31,7 @@
import com.android.systemui.Flags.keyboardShortcutHelperShortcutCustomizer
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperCategoriesInteractor
+import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperCustomizationModeInteractor
import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperStateInteractor
import com.android.systemui.keyboard.shortcut.shared.model.Shortcut
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
@@ -65,6 +65,7 @@
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val stateInteractor: ShortcutHelperStateInteractor,
categoriesInteractor: ShortcutHelperCategoriesInteractor,
+ private val customizationModeInteractor: ShortcutHelperCustomizationModeInteractor,
) {
private val searchQuery = MutableStateFlow("")
@@ -77,7 +78,11 @@
.flowOn(backgroundDispatcher)
val shortcutsUiState =
- combine(searchQuery, categoriesInteractor.shortcutCategories) { query, categories ->
+ combine(
+ searchQuery,
+ categoriesInteractor.shortcutCategories,
+ customizationModeInteractor.customizationMode,
+ ) { query, categories, isCustomizationModeEnabled ->
if (categories.isEmpty()) {
ShortcutsUiState.Inactive
} else {
@@ -94,6 +99,7 @@
isShortcutCustomizerFlagEnabled =
keyboardShortcutHelperShortcutCustomizer(),
shouldShowResetButton = shouldShowResetButton(shortcutCategoriesUi),
+ isCustomizationModeEnabled = isCustomizationModeEnabled,
)
}
}
@@ -243,6 +249,7 @@
fun onViewClosed() {
stateInteractor.onViewClosed()
resetSearchQuery()
+ resetCustomizationMode()
}
fun onViewOpened() {
@@ -253,7 +260,15 @@
searchQuery.value = query
}
+ fun toggleCustomizationMode(isCustomizing: Boolean) {
+ customizationModeInteractor.toggleCustomizationMode(isCustomizing)
+ }
+
private fun resetSearchQuery() {
searchQuery.value = ""
}
+
+ private fun resetCustomizationMode() {
+ customizationModeInteractor.toggleCustomizationMode(false)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
index fc79c7f..50ebbe4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
@@ -32,7 +32,7 @@
import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.ShadeDisplayAware
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.StateFlow
@@ -45,7 +45,7 @@
constructor(
private val keyguardBlueprintRepository: KeyguardBlueprintRepository,
@Application private val applicationScope: CoroutineScope,
- shadeInteractor: ShadeInteractor,
+ shadeModeInteractor: ShadeModeInteractor,
@ShadeDisplayAware private val configurationInteractor: ConfigurationInteractor,
private val fingerprintPropertyInteractor: FingerprintPropertyInteractor,
private val smartspaceSection: SmartspaceSection,
@@ -61,7 +61,7 @@
/** Current BlueprintId */
val blueprintId =
- shadeInteractor.isShadeLayoutWide.map { isShadeLayoutWide ->
+ shadeModeInteractor.isShadeLayoutWide.map { isShadeLayoutWide ->
val useSplitShade = isShadeLayoutWide && !SceneContainerFlag.isEnabled
when {
useSplitShade -> SplitShadeKeyguardBlueprint.ID
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
index 1ea47ec..0dd7821 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
@@ -29,6 +29,7 @@
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.Flags
import com.android.systemui.common.ui.view.TouchHandlingView
import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryBackgroundViewModel
@@ -39,6 +40,8 @@
import com.android.systemui.res.R
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.util.kotlin.DisposableHandles
+import com.google.android.msdl.data.model.MSDLToken
+import com.google.android.msdl.domain.MSDLPlayer
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DisposableHandle
@@ -64,6 +67,7 @@
bgViewModel: DeviceEntryBackgroundViewModel,
falsingManager: FalsingManager,
vibratorHelper: VibratorHelper,
+ msdlPlayer: MSDLPlayer,
overrideColor: Color? = null,
): DisposableHandle {
val disposables = DisposableHandles()
@@ -88,7 +92,9 @@
)
return
}
- vibratorHelper.performHapticFeedback(view, HapticFeedbackConstants.CONFIRM)
+ if (!Flags.msdlFeedback()) {
+ vibratorHelper.performHapticFeedback(view, HapticFeedbackConstants.CONFIRM)
+ }
applicationScope.launch {
view.clearFocus()
view.clearAccessibilityFocus()
@@ -165,10 +171,23 @@
view.accessibilityHintType = hint
if (hint != DeviceEntryIconView.AccessibilityHintType.NONE) {
view.setOnClickListener {
- vibratorHelper.performHapticFeedback(
- view,
- HapticFeedbackConstants.CONFIRM,
- )
+ if (Flags.msdlFeedback()) {
+ val token =
+ if (
+ hint ==
+ DeviceEntryIconView.AccessibilityHintType.ENTER
+ ) {
+ MSDLToken.UNLOCK
+ } else {
+ MSDLToken.LONG_PRESS
+ }
+ msdlPlayer.playToken(token)
+ } else {
+ vibratorHelper.performHapticFeedback(
+ view,
+ HapticFeedbackConstants.CONFIRM,
+ )
+ }
applicationScope.launch {
view.clearFocus()
view.clearAccessibilityFocus()
@@ -180,6 +199,16 @@
}
}
}
+
+ if (Flags.msdlFeedback()) {
+ launch("$TAG#viewModel.isPrimaryBouncerShowing") {
+ viewModel.deviceDidNotEnterFromDeviceEntryIcon.collect {
+ // If we did not enter from the icon, we did not play device entry
+ // haptics. Therefore, we play the token for long-press instead.
+ msdlPlayer.playToken(MSDLToken.LONG_PRESS)
+ }
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt
index 220846d..50ef21b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt
@@ -26,6 +26,7 @@
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.Flags
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.common.ui.binder.IconViewBinder
import com.android.systemui.common.ui.binder.TextViewBinder
@@ -59,7 +60,9 @@
viewModel.isVisible.distinctUntilChanged().collect { isVisible ->
view.animateVisibility(visible = isVisible)
if (isVisible) {
- vibratorHelper.vibrate(KeyguardBottomAreaVibrations.Activated)
+ if (!Flags.msdlFeedback()) {
+ vibratorHelper.vibrate(KeyguardBottomAreaVibrations.Activated)
+ }
val textView = view.requireViewById(R.id.text) as TextView
view.setOnTouchListener(
KeyguardSettingsButtonOnTouchListener(viewModel = viewModel)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index d749e3c..e758768 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -73,7 +73,7 @@
import com.android.systemui.plugins.clocks.WeatherData
import com.android.systemui.res.R
import com.android.systemui.scene.shared.flag.SceneContainerFlag
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
import com.android.systemui.shared.clocks.ClockRegistry
import com.android.systemui.shared.clocks.shared.model.ClockPreviewConstants
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
@@ -113,7 +113,7 @@
private val udfpsOverlayInteractor: UdfpsOverlayInteractor,
private val indicationController: KeyguardIndicationController,
@Assisted bundle: Bundle,
- private val shadeInteractor: ShadeInteractor,
+ private val shadeModeInteractor: ShadeModeInteractor,
private val secureSettings: SecureSettings,
private val defaultShortcutsSection: DefaultShortcutsSection,
private val keyguardQuickAffordanceViewBinder: KeyguardQuickAffordanceViewBinder,
@@ -415,10 +415,7 @@
setUpClock(previewContext, rootView)
if (com.android.systemui.shared.Flags.clockReactiveSmartspaceLayout()) {
setUpSmartspace(previewContext, keyguardRootView)
- KeyguardPreviewSmartspaceViewBinder.bind(
- keyguardRootView,
- smartspaceViewModel,
- )
+ KeyguardPreviewSmartspaceViewBinder.bind(keyguardRootView, smartspaceViewModel)
}
KeyguardPreviewClockViewBinder.bind(
keyguardRootView,
@@ -591,7 +588,7 @@
private fun getPreviewShadeLayoutWide(display: Display): Boolean {
return if (display.displayId == 0) {
- shadeInteractor.isShadeLayoutWide.value
+ shadeModeInteractor.isShadeLayoutWide.value
} else {
// For the unfolded preview in a folded screen; it's landscape by default
// For the folded preview in an unfolded screen; it's portrait by default
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
index e268050..f717431 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
@@ -34,7 +34,7 @@
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.res.R
import com.android.systemui.shade.ShadeDisplayAware
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.AlwaysOnDisplayNotificationIconViewStore
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.StatusBarIconViewBindingFailureTracker
@@ -56,7 +56,7 @@
private val nicAodIconViewStore: AlwaysOnDisplayNotificationIconViewStore,
private val systemBarUtilsState: SystemBarUtilsState,
private val rootViewModel: KeyguardRootViewModel,
- private val shadeInteractor: ShadeInteractor,
+ private val shadeModeInteractor: ShadeModeInteractor,
) : KeyguardSection() {
private var nicBindingDisposable: DisposableHandle? = null
@@ -99,7 +99,7 @@
context.resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal)
val height = context.resources.getDimensionPixelSize(R.dimen.notification_shelf_height)
val isVisible = rootViewModel.isNotifIconContainerVisible.value
- val isShadeLayoutWide = shadeInteractor.isShadeLayoutWide.value
+ val isShadeLayoutWide = shadeModeInteractor.isShadeLayoutWide.value
constraintSet.apply {
if (PromotedNotificationUiAod.isEnabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodPromotedNotificationSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodPromotedNotificationSection.kt
index 2110c40..efdc5ab 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodPromotedNotificationSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodPromotedNotificationSection.kt
@@ -28,7 +28,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.res.R
import com.android.systemui.shade.ShadeDisplayAware
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
import com.android.systemui.statusbar.notification.promoted.AODPromotedNotification
import com.android.systemui.statusbar.notification.promoted.PromotedNotificationLogger
import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiAod
@@ -40,7 +40,7 @@
constructor(
@ShadeDisplayAware private val context: Context,
private val viewModelFactory: AODPromotedNotificationViewModel.Factory,
- private val shadeInteractor: ShadeInteractor,
+ private val shadeModeInteractor: ShadeModeInteractor,
private val logger: PromotedNotificationLogger,
) : KeyguardSection() {
var view: ComposeView? = null
@@ -90,7 +90,7 @@
context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_start_icons)
constraintSet.apply {
- val isShadeLayoutWide = shadeInteractor.isShadeLayoutWide.value
+ val isShadeLayoutWide = shadeModeInteractor.isShadeLayoutWide.value
if (isShadeLayoutWide) {
// When in split shade, align with top of smart space:
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
index 9c8f04b..754b3d7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
@@ -47,6 +47,7 @@
import com.android.systemui.shade.NotificationPanelView
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.VibratorHelper
+import com.google.android.msdl.domain.MSDLPlayer
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -69,6 +70,7 @@
private val deviceEntryBackgroundViewModel: Lazy<DeviceEntryBackgroundViewModel>,
private val falsingManager: Lazy<FalsingManager>,
private val vibratorHelper: Lazy<VibratorHelper>,
+ private val msdlPlayer: Lazy<MSDLPlayer>,
@LongPressTouchLog private val logBuffer: LogBuffer,
@KeyguardBlueprintLog blueprintLogBuffer: LogBuffer,
) : KeyguardSection() {
@@ -101,6 +103,7 @@
deviceEntryBackgroundViewModel.get(),
falsingManager.get(),
vibratorHelper.get(),
+ msdlPlayer.get(),
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index 9b4bd67..729edcf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -44,6 +44,7 @@
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filterNot
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
@@ -253,6 +254,13 @@
val isLongPressEnabled: Flow<Boolean> = isInteractive
+ val deviceDidNotEnterFromDeviceEntryIcon =
+ deviceEntrySourceInteractor.attemptEnterDeviceFromDeviceEntryIcon
+ .map { keyguardInteractor.isKeyguardDismissible.value }
+ .filterNot { it } // only emit events if the keyguard is not dismissible
+ // map to Unit
+ .map {}
+
suspend fun onUserInteraction() {
if (SceneContainerFlag.isEnabled) {
deviceEntryInteractor.attemptDeviceEntry()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
index f8425c1..5cc34e7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
@@ -22,7 +22,7 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.KeyguardSmartspaceInteractor
import com.android.systemui.res.R
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -40,7 +40,7 @@
smartspaceController: LockscreenSmartspaceController,
keyguardClockViewModel: KeyguardClockViewModel,
smartspaceInteractor: KeyguardSmartspaceInteractor,
- shadeInteractor: ShadeInteractor,
+ shadeModeInteractor: ShadeModeInteractor,
) {
/** Whether the smartspace section is available in the build. */
val isSmartspaceEnabled: Boolean = smartspaceController.isEnabled
@@ -91,7 +91,7 @@
/* trigger clock and smartspace constraints change when smartspace appears */
val bcSmartspaceVisibility: StateFlow<Int> = smartspaceInteractor.bcSmartspaceVisibility
- val isShadeLayoutWide: StateFlow<Boolean> = shadeInteractor.isShadeLayoutWide
+ val isShadeLayoutWide: StateFlow<Boolean> = shadeModeInteractor.isShadeLayoutWide
companion object {
fun getDateWeatherStartMargin(context: Context): Int {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt
index 2cd5016..d053dd2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt
@@ -248,7 +248,7 @@
// Update loading state with actual active value
mediaFilterRepository.selectedUserEntries.value[lastActiveId]?.let {
mediaFilterRepository.addMediaDataLoadingState(
- MediaDataLoadingModel.Loaded(lastActiveId, immediately)
+ MediaDataLoadingModel.Loaded(lastActiveId)
)
mediaLogger.logMediaLoaded(lastActiveId, it.active, "expiring reactivated id")
listeners.forEach { listener ->
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaDataLoadingModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaDataLoadingModel.kt
index c8a02fa..323e5cb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaDataLoadingModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaDataLoadingModel.kt
@@ -26,13 +26,10 @@
/** Media data has been loaded. */
data class Loaded(
override val instanceId: InstanceId,
- val immediatelyUpdateUi: Boolean = true,
val receivedSmartspaceCardLatency: Int = 0,
val isSsReactivated: Boolean = false,
) : MediaDataLoadingModel()
/** Media data has been removed. */
- data class Removed(
- override val instanceId: InstanceId,
- ) : MediaDataLoadingModel()
+ data class Removed(override val instanceId: InstanceId) : MediaDataLoadingModel()
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
index 71b3223..800220e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
@@ -68,7 +68,7 @@
import com.android.systemui.media.controls.ui.view.MediaScrollView
import com.android.systemui.media.controls.ui.view.MediaViewHolder
import com.android.systemui.media.controls.ui.viewmodel.MediaCarouselViewModel
-import com.android.systemui.media.controls.ui.viewmodel.MediaCommonViewModel
+import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel
import com.android.systemui.media.controls.util.MediaUiEventLogger
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
@@ -324,8 +324,8 @@
private var widthInSceneContainerPx = 0
private var heightInSceneContainerPx = 0
- private val controllerById = mutableMapOf<String, MediaViewController>()
- private val commonViewModels = mutableListOf<MediaCommonViewModel>()
+ private val controllerById = mutableMapOf<InstanceId, MediaViewController>()
+ private val controlViewModels = mutableListOf<MediaControlViewModel>()
private val isOnGone =
keyguardTransitionInteractor
@@ -566,10 +566,10 @@
private fun listenForMediaItemsChanges(scope: CoroutineScope): Job {
return scope.launch {
mediaCarouselViewModel.mediaItems.collectLatest {
- val diffUtilCallback = MediaViewModelCallback(commonViewModels, it)
+ val diffUtilCallback = MediaViewModelCallback(controlViewModels, it)
val listUpdateCallback =
MediaViewModelListUpdateCallback(
- old = commonViewModels,
+ old = controlViewModels,
new = it,
onAdded = this@MediaCarouselController::onAdded,
onUpdated = this@MediaCarouselController::onUpdated,
@@ -590,7 +590,7 @@
}
private fun onAdded(
- commonViewModel: MediaCommonViewModel,
+ controlViewModel: MediaControlViewModel,
position: Int,
configChanged: Boolean = false,
) {
@@ -601,64 +601,52 @@
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
)
- when (commonViewModel) {
- is MediaCommonViewModel.MediaControl -> {
- val viewHolder = MediaViewHolder.create(LayoutInflater.from(context), mediaContent)
- viewController.widthInSceneContainerPx = widthInSceneContainerPx
- viewController.heightInSceneContainerPx = heightInSceneContainerPx
- viewController.attachPlayer(viewHolder)
- viewController.mediaViewHolder?.player?.layoutParams = lp
- if (configChanged) {
- commonViewModel.controlViewModel.onMediaConfigChanged()
- }
- MediaControlViewBinder.bind(
- viewHolder,
- commonViewModel.controlViewModel,
- viewController,
- falsingManager,
- backgroundDispatcher,
- mainDispatcher,
- )
- mediaContent.addView(viewHolder.player, position)
- controllerById[commonViewModel.instanceId.toString()] = viewController
- }
+ val viewHolder = MediaViewHolder.create(LayoutInflater.from(context), mediaContent)
+ viewController.widthInSceneContainerPx = widthInSceneContainerPx
+ viewController.heightInSceneContainerPx = heightInSceneContainerPx
+ viewController.attachPlayer(viewHolder)
+ viewController.mediaViewHolder?.player?.layoutParams = lp
+ if (configChanged) {
+ controlViewModel.onMediaConfigChanged()
}
+ MediaControlViewBinder.bind(
+ viewHolder,
+ controlViewModel,
+ viewController,
+ falsingManager,
+ backgroundDispatcher,
+ mainDispatcher,
+ )
+ mediaContent.addView(viewHolder.player, position)
+ controllerById[controlViewModel.instanceId] = viewController
viewController.setListening(mediaCarouselScrollHandler.visibleToUser && currentlyExpanded)
updateViewControllerToState(viewController, noAnimation = true)
updatePageIndicator()
- if (
- commonViewModel is MediaCommonViewModel.MediaControl && commonViewModel.isMediaFromRec
- ) {
- mediaCarouselScrollHandler.scrollToPlayer(
- mediaCarouselScrollHandler.visibleMediaIndex,
- destIndex = 0,
- )
- }
mediaCarouselScrollHandler.onPlayersChanged()
mediaFrame.requiresRemeasuring = true
- commonViewModel.onAdded(commonViewModel)
+ controlViewModel.onAdded(controlViewModel)
}
- private fun onUpdated(commonViewModel: MediaCommonViewModel, position: Int) {
- commonViewModel.onUpdated(commonViewModel)
+ private fun onUpdated(controlViewModel: MediaControlViewModel, position: Int) {
+ controlViewModel.onUpdated(controlViewModel)
updatePageIndicator()
mediaCarouselScrollHandler.onPlayersChanged()
}
- private fun onRemoved(commonViewModel: MediaCommonViewModel) {
- val id = (commonViewModel as MediaCommonViewModel.MediaControl).instanceId.toString()
+ private fun onRemoved(controlViewModel: MediaControlViewModel) {
+ val id = controlViewModel.instanceId
controllerById.remove(id)?.let {
mediaCarouselScrollHandler.onPrePlayerRemoved(it.mediaViewHolder!!.player)
mediaContent.removeView(it.mediaViewHolder!!.player)
it.onDestroy()
mediaCarouselScrollHandler.onPlayersChanged()
updatePageIndicator()
- commonViewModel.onRemoved(true)
+ controlViewModel.onRemoved(true)
}
}
- private fun onMoved(commonViewModel: MediaCommonViewModel, from: Int, to: Int) {
- val id = (commonViewModel as MediaCommonViewModel.MediaControl).instanceId.toString()
+ private fun onMoved(controlViewModel: MediaControlViewModel, from: Int, to: Int) {
+ val id = controlViewModel.instanceId
controllerById[id]?.let {
mediaContent.removeViewAt(from)
mediaContent.addView(it.mediaViewHolder!!.player, to)
@@ -667,19 +655,12 @@
mediaCarouselScrollHandler.onPlayersChanged()
}
- private fun setNewViewModelsList(viewModels: List<MediaCommonViewModel>) {
- commonViewModels.clear()
- commonViewModels.addAll(viewModels)
+ private fun setNewViewModelsList(viewModels: List<MediaControlViewModel>) {
+ controlViewModels.clear()
+ controlViewModels.addAll(viewModels)
// Ensure we only show the needed UMOs in media carousel.
- val viewIds =
- viewModels
- .map { mediaCommonViewModel ->
- (mediaCommonViewModel as MediaCommonViewModel.MediaControl)
- .instanceId
- .toString()
- }
- .toHashSet()
+ val viewIds = viewModels.map { controlViewModel -> controlViewModel.instanceId }.toHashSet()
controllerById
.filter { !viewIds.contains(it.key) }
.forEach {
@@ -976,9 +957,8 @@
ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator))
if (recreateMedia) {
mediaContent.removeAllViews()
- commonViewModels.forEachIndexed { index, viewModel ->
- val mediaControlViewModel = (viewModel as MediaCommonViewModel.MediaControl)
- controllerById[mediaControlViewModel.instanceId.toString()]?.onDestroy()
+ controlViewModels.forEachIndexed { index, viewModel ->
+ controllerById[viewModel.instanceId]?.onDestroy()
onAdded(viewModel, index, configChanged = true)
}
}
@@ -1309,7 +1289,7 @@
println("dataKeys: ${MediaPlayerData.dataKeys()}")
println("orderedPlayerSortKeys: ${MediaPlayerData.playerKeys()}")
println("visiblePlayerSortKeys: ${MediaPlayerData.visiblePlayerKeys()}")
- println("commonViewModels: $commonViewModels")
+ println("controlViewModels: $controlViewModels")
println("smartspaceMediaData: ${MediaPlayerData.smartspaceMediaData}")
println("shouldPrioritizeSs: ${MediaPlayerData.shouldPrioritizeSs}")
println("current size: $currentCarouselWidth x $currentCarouselHeight")
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelCallback.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelCallback.kt
index 2fc44ad..ad2d462 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelCallback.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelCallback.kt
@@ -17,12 +17,12 @@
package com.android.systemui.media.controls.ui.util
import androidx.recyclerview.widget.DiffUtil
-import com.android.systemui.media.controls.ui.viewmodel.MediaCommonViewModel
+import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel
/** A [DiffUtil.Callback] to calculate difference between old and new media view-model list. */
class MediaViewModelCallback(
- private val old: List<MediaCommonViewModel>,
- private val new: List<MediaCommonViewModel>,
+ private val old: List<MediaControlViewModel>,
+ private val new: List<MediaControlViewModel>,
) : DiffUtil.Callback() {
override fun getOldListSize(): Int {
@@ -36,27 +36,12 @@
override fun areItemsTheSame(oldIndex: Int, newIndex: Int): Boolean {
val oldItem = old[oldIndex]
val newItem = new[newIndex]
- return if (
- oldItem is MediaCommonViewModel.MediaControl &&
- newItem is MediaCommonViewModel.MediaControl
- ) {
- oldItem.instanceId == newItem.instanceId
- } else {
- false
- }
+ return oldItem.instanceId == newItem.instanceId
}
override fun areContentsTheSame(oldIndex: Int, newIndex: Int): Boolean {
val oldItem = old[oldIndex]
val newItem = new[newIndex]
- return if (
- oldItem is MediaCommonViewModel.MediaControl &&
- newItem is MediaCommonViewModel.MediaControl
- ) {
- oldItem.immediatelyUpdateUi == newItem.immediatelyUpdateUi &&
- oldItem.updateTime == newItem.updateTime
- } else {
- false
- }
+ return oldItem.updateTime == newItem.updateTime
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelListUpdateCallback.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelListUpdateCallback.kt
index 6022b7b..1db8c58 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelListUpdateCallback.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelListUpdateCallback.kt
@@ -17,17 +17,17 @@
package com.android.systemui.media.controls.ui.util
import androidx.recyclerview.widget.ListUpdateCallback
-import com.android.systemui.media.controls.ui.viewmodel.MediaCommonViewModel
+import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel
import kotlin.math.min
/** A [ListUpdateCallback] to apply media events needed to reach the new state. */
class MediaViewModelListUpdateCallback(
- private val old: List<MediaCommonViewModel>,
- private val new: List<MediaCommonViewModel>,
- private val onAdded: (MediaCommonViewModel, Int) -> Unit,
- private val onUpdated: (MediaCommonViewModel, Int) -> Unit,
- private val onRemoved: (MediaCommonViewModel) -> Unit,
- private val onMoved: (MediaCommonViewModel, Int, Int) -> Unit,
+ private val old: List<MediaControlViewModel>,
+ private val new: List<MediaControlViewModel>,
+ private val onAdded: (MediaControlViewModel, Int) -> Unit,
+ private val onUpdated: (MediaControlViewModel, Int) -> Unit,
+ private val onRemoved: (MediaControlViewModel) -> Unit,
+ private val onMoved: (MediaControlViewModel, Int, Int) -> Unit,
) : ListUpdateCallback {
override fun onInserted(position: Int, count: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt
index dfaee44..54d3151 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt
@@ -56,7 +56,7 @@
val hasAnyMediaOrRecommendations: StateFlow<Boolean> = interactor.hasAnyMediaOrRecommendation
val hasActiveMediaOrRecommendations: StateFlow<Boolean> =
interactor.hasActiveMediaOrRecommendation
- val mediaItems: StateFlow<List<MediaCommonViewModel>> =
+ val mediaItems: StateFlow<List<MediaControlViewModel>> =
interactor.currentMedia
.map { sortedItems ->
val mediaList = buildList {
@@ -91,8 +91,7 @@
var updateHostVisibility: () -> Unit = {}
- private val mediaControlByInstanceId =
- mutableMapOf<InstanceId, MediaCommonViewModel.MediaControl>()
+ private val mediaControlByInstanceId = mutableMapOf<InstanceId, MediaControlViewModel>()
private var modelsPendingRemoval: MutableSet<MediaCommonModel> = mutableSetOf()
@@ -108,18 +107,16 @@
interactor.reorderMedia()
}
- private fun toViewModel(
- commonModel: MediaCommonModel.MediaControl
- ): MediaCommonViewModel.MediaControl {
+ private fun toViewModel(commonModel: MediaCommonModel.MediaControl): MediaControlViewModel {
val instanceId = commonModel.mediaLoadedModel.instanceId
- return mediaControlByInstanceId[instanceId]?.copy(
- immediatelyUpdateUi = commonModel.mediaLoadedModel.immediatelyUpdateUi,
- updateTime = commonModel.updateTime,
- )
- ?: MediaCommonViewModel.MediaControl(
+ return mediaControlByInstanceId[instanceId]?.copy(updateTime = commonModel.updateTime)
+ ?: MediaControlViewModel(
+ applicationContext = applicationContext,
+ backgroundDispatcher = backgroundDispatcher,
+ backgroundExecutor = backgroundExecutor,
+ interactor = controlInteractorFactory.create(instanceId),
+ logger = logger,
instanceId = instanceId,
- immediatelyUpdateUi = commonModel.mediaLoadedModel.immediatelyUpdateUi,
- controlViewModel = createMediaControlViewModel(instanceId),
onAdded = {
mediaLogger.logMediaCardAdded(instanceId)
onMediaControlAddedOrUpdated(it, commonModel)
@@ -130,31 +127,20 @@
mediaLogger.logMediaCardRemoved(instanceId)
},
onUpdated = { onMediaControlAddedOrUpdated(it, commonModel) },
- isMediaFromRec = commonModel.isMediaFromRec,
updateTime = commonModel.updateTime,
)
.also { mediaControlByInstanceId[instanceId] = it }
}
- private fun createMediaControlViewModel(instanceId: InstanceId): MediaControlViewModel {
- return MediaControlViewModel(
- applicationContext = applicationContext,
- backgroundDispatcher = backgroundDispatcher,
- backgroundExecutor = backgroundExecutor,
- interactor = controlInteractorFactory.create(instanceId),
- logger = logger,
- )
- }
-
private fun onMediaControlAddedOrUpdated(
- commonViewModel: MediaCommonViewModel,
+ controlViewModel: MediaControlViewModel,
commonModel: MediaCommonModel.MediaControl,
) {
if (commonModel.canBeRemoved && !Utils.useMediaResumption(applicationContext)) {
// This media control is due for removal as it is now paused + timed out, and resumption
// setting is off.
if (isReorderingAllowed()) {
- commonViewModel.onRemoved(true)
+ controlViewModel.onRemoved(true)
} else {
modelsPendingRemoval.add(commonModel)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCommonViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCommonViewModel.kt
deleted file mode 100644
index d493d57..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCommonViewModel.kt
+++ /dev/null
@@ -1,38 +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.media.controls.ui.viewmodel
-
-import com.android.internal.logging.InstanceId
-
-/** Models media view model UI state. */
-sealed class MediaCommonViewModel {
-
- abstract val onAdded: (MediaCommonViewModel) -> Unit
- abstract val onRemoved: (Boolean) -> Unit
- abstract val onUpdated: (MediaCommonViewModel) -> Unit
-
- data class MediaControl(
- val instanceId: InstanceId,
- val immediatelyUpdateUi: Boolean,
- val controlViewModel: MediaControlViewModel,
- override val onAdded: (MediaCommonViewModel) -> Unit,
- override val onRemoved: (Boolean) -> Unit,
- override val onUpdated: (MediaCommonViewModel) -> Unit,
- val isMediaFromRec: Boolean = false,
- val updateTime: Long = 0,
- ) : MediaCommonViewModel()
-}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt
index 015274a..31cfb84 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt
@@ -45,12 +45,17 @@
import kotlinx.coroutines.flow.map
/** Models UI state and handles user input for a media control. */
-class MediaControlViewModel(
+data class MediaControlViewModel(
@Application private val applicationContext: Context,
@Background private val backgroundDispatcher: CoroutineDispatcher,
@Background private val backgroundExecutor: Executor,
private val interactor: MediaControlInteractor,
private val logger: MediaUiEventLogger,
+ val instanceId: InstanceId,
+ val onAdded: (MediaControlViewModel) -> Unit,
+ val onRemoved: (Boolean) -> Unit,
+ val onUpdated: (MediaControlViewModel) -> Unit,
+ val updateTime: Long = 0,
) {
val player: Flow<MediaPlayerViewModel?> =
interactor.mediaControl
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterBase.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterBase.java
index ac1672d..e3990d2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterBase.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterBase.java
@@ -237,8 +237,7 @@
clickListener = v -> onItemClick(v, device);
}
} else {
- deviceStatusIcon = getDeviceStatusIcon(device,
- device.hasOngoingSession());
+ deviceStatusIcon = getDeviceStatusIcon(device);
clickListener = getClickListenerBasedOnSelectionBehavior(device);
}
deviceDisabled = clickListener == null;
@@ -302,12 +301,8 @@
}
@Nullable
- private Drawable getDeviceStatusIcon(MediaDevice device, boolean hasOngoingSession) {
- if (hasOngoingSession) {
- return mContext.getDrawable(R.drawable.ic_sound_bars_anim);
- } else {
- return Api34Impl.getDeviceStatusIconBasedOnSelectionBehavior(device, mContext);
- }
+ private Drawable getDeviceStatusIcon(MediaDevice device) {
+ return Api34Impl.getDeviceStatusIconBasedOnSelectionBehavior(device, mContext);
}
protected void onExpandGroupButtonClicked() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java
index 6ab4a52..7ab6b3c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java
@@ -231,7 +231,7 @@
updateFullItemClickListener(clickListener);
updateContentAlpha(deviceDisabled);
updateSubtitle(subtitle);
- updateDeviceStatusIcon(deviceStatusIcon);
+ updateDeviceStatusIcon(deviceStatusIcon, ongoingSessionStatus, connectionState);
updateItemBackground(connectionState);
}
@@ -523,11 +523,20 @@
mStatusIcon.setAlpha(alphaValue);
}
- private void updateDeviceStatusIcon(@Nullable Drawable deviceStatusIcon) {
- if (deviceStatusIcon == null) {
+ private void updateDeviceStatusIcon(@Nullable Drawable deviceStatusIcon,
+ @Nullable OngoingSessionStatus ongoingSessionStatus,
+ ConnectionState connectionState) {
+ boolean showOngoingSession =
+ ongoingSessionStatus != null && connectionState == ConnectionState.DISCONNECTED;
+ if (deviceStatusIcon == null && !showOngoingSession) {
mStatusIcon.setVisibility(View.GONE);
} else {
- mStatusIcon.setImageDrawable(deviceStatusIcon);
+ if (showOngoingSession) {
+ mStatusIcon.setImageDrawable(
+ mContext.getDrawable(R.drawable.ic_sound_bars_anim));
+ } else {
+ mStatusIcon.setImageDrawable(deviceStatusIcon);
+ }
mStatusIcon.setImageTintList(ColorStateList.valueOf(
mController.getColorSchemeLegacy().getColorItemContent()));
if (deviceStatusIcon instanceof AnimatedVectorDrawable) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
index d0c6a3e..bf1f971c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
@@ -580,7 +580,23 @@
synchronized (mMediaDevicesLock) {
if (!mLocalMediaManager.isPreferenceRouteListingExist()) {
attachRangeInfo(devices);
- Collections.sort(devices, Comparator.naturalOrder());
+ if (Flags.enableOutputSwitcherDeviceGrouping()) {
+ List<MediaDevice> selectedDevices = new ArrayList<>();
+ Set<String> selectedDeviceIds =
+ getSelectedMediaDevice().stream()
+ .map(MediaDevice::getId)
+ .collect(Collectors.toSet());
+ for (MediaDevice device : devices) {
+ if (selectedDeviceIds.contains(device.getId())) {
+ selectedDevices.add(device);
+ }
+ }
+ devices.removeAll(selectedDevices);
+ Collections.sort(devices, Comparator.naturalOrder());
+ devices.addAll(0, selectedDevices);
+ } else {
+ Collections.sort(devices, Comparator.naturalOrder());
+ }
}
if (Flags.fixOutputMediaItemListIndexOutOfBoundsException()) {
// For the first time building list, to make sure the top device is the connected
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/Media.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/Media.kt
index d6d1851..063ff15 100644
--- a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/Media.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/Media.kt
@@ -267,7 +267,11 @@
}
if (behavior.isCarouselDismissible) {
- SwipeToDismiss(content = { PagerContent() }, onDismissed = onDismissed)
+ SwipeToDismiss(
+ content = { PagerContent() },
+ isSwipingEnabled = isSwipingEnabled,
+ onDismissed = onDismissed,
+ )
} else {
val overscrollEffect = rememberOffsetOverscrollEffect()
SwipeToReveal(
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/SwipeToDismiss.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/SwipeToDismiss.kt
index b80bf41..f044257 100644
--- a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/SwipeToDismiss.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/SwipeToDismiss.kt
@@ -17,99 +17,187 @@
package com.android.systemui.media.remedia.ui.compose
import androidx.compose.animation.core.Animatable
-import androidx.compose.foundation.OverscrollEffect
+import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.absoluteOffset
+import androidx.compose.foundation.overscroll
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
-import androidx.compose.ui.input.nestedscroll.NestedScrollSource
-import androidx.compose.ui.input.nestedscroll.nestedScroll
-import androidx.compose.ui.layout.onSizeChanged
+import androidx.compose.ui.input.pointer.PointerType
+import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.IntOffset
-import androidx.compose.ui.unit.Velocity
+import androidx.compose.ui.util.fastCoerceIn
import androidx.compose.ui.util.fastRoundToInt
+import com.android.compose.gesture.NestedDraggable
+import com.android.compose.gesture.effect.rememberOffsetOverscrollEffect
+import com.android.compose.gesture.nestedDraggable
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
/** Swipe to dismiss that supports nested scrolling. */
@Composable
fun SwipeToDismiss(
- content: @Composable (overscrollEffect: OverscrollEffect?) -> Unit,
+ content: @Composable () -> Unit,
+ isSwipingEnabled: Boolean,
onDismissed: () -> Unit,
modifier: Modifier = Modifier,
) {
- val scope = rememberCoroutineScope()
- val offsetAnimatable = remember { Animatable(0f) }
+ val overscrollEffect = rememberOffsetOverscrollEffect()
- // This is the width of the revealed content UI box. It's not a state because it's not
- // observed in any composition and is an object with a value to avoid the extra cost
- // associated with boxing and unboxing an int.
- val revealedContentBoxWidth = remember {
+ // This is the width of the content UI box. It's not a state because it's not observed in any
+ // composition and is an object with a value to avoid the extra cost associated with boxing and
+ // unboxing an int.
+ val contentBoxWidth = remember {
object {
var value = 0
}
}
- val nestedScrollConnection = remember {
- object : NestedScrollConnection {
- override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
- return if (offsetAnimatable.value > 0f && available.x < 0f) {
- scope.launch { offsetAnimatable.snapTo(offsetAnimatable.value + available.x) }
- Offset(available.x, 0f)
- } else if (offsetAnimatable.value < 0f && available.x > 0f) {
- scope.launch { offsetAnimatable.snapTo(offsetAnimatable.value + available.x) }
- Offset(available.x, 0f)
- } else {
- Offset.Zero
- }
- }
-
- override fun onPostScroll(
- consumed: Offset,
- available: Offset,
- source: NestedScrollSource,
- ): Offset {
- return if (available.x > 0f) {
- scope.launch { offsetAnimatable.snapTo(offsetAnimatable.value + available.x) }
- Offset(available.x, 0f)
- } else if (available.x < 0f) {
- scope.launch { offsetAnimatable.snapTo(offsetAnimatable.value + available.x) }
- Offset(available.x, 0f)
- } else {
- Offset.Zero
- }
- }
-
- override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
- scope.launch {
- offsetAnimatable.animateTo(
- if (offsetAnimatable.value >= revealedContentBoxWidth.value / 2f) {
- revealedContentBoxWidth.value * 2f
- } else if (offsetAnimatable.value <= -revealedContentBoxWidth.value / 2f) {
- -revealedContentBoxWidth.value * 2f
- } else {
- 0f
- }
- )
- if (offsetAnimatable.value != 0f) {
- onDismissed()
- }
- }
- return super.onPostFling(consumed, available)
- }
- }
- }
+ // In order to support the drag to dismiss, infrastructure has to be put in place where a
+ // NestedDraggable helps by consuming the unconsumed drags and flings and applying the offset.
+ //
+ // This is the NestedDraggalbe controller.
+ val dragController =
+ rememberDismissibleContentDragController(
+ maxBound = { contentBoxWidth.value.toFloat() },
+ onDismissed = onDismissed,
+ )
Box(
modifier =
modifier
- .onSizeChanged { revealedContentBoxWidth.value = it.width }
- .nestedScroll(nestedScrollConnection)
- .offset { IntOffset(x = offsetAnimatable.value.fastRoundToInt(), y = 0) }
+ .layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ contentBoxWidth.value = placeable.measuredWidth
+ layout(placeable.measuredWidth, placeable.measuredHeight) {
+ placeable.place(0, 0)
+ }
+ }
+ .nestedDraggable(
+ enabled = isSwipingEnabled,
+ draggable =
+ remember {
+ object : NestedDraggable {
+ override fun onDragStarted(
+ position: Offset,
+ sign: Float,
+ pointersDown: Int,
+ pointerType: PointerType?,
+ ): NestedDraggable.Controller {
+ return dragController
+ }
+
+ override fun shouldConsumeNestedPostScroll(sign: Float): Boolean {
+ return dragController.shouldConsumePostScrolls(sign)
+ }
+
+ override fun shouldConsumeNestedPreScroll(sign: Float): Boolean {
+ return dragController.shouldConsumePreScrolls(sign)
+ }
+ }
+ },
+ orientation = Orientation.Horizontal,
+ )
+ .overscroll(overscrollEffect)
+ .absoluteOffset { IntOffset(dragController.offset.fastRoundToInt(), y = 0) }
) {
- content(null)
+ content()
+ }
+}
+
+@Composable
+private fun rememberDismissibleContentDragController(
+ maxBound: () -> Float,
+ onDismissed: () -> Unit,
+): DismissibleContentDragController {
+ val scope = rememberCoroutineScope()
+ return remember {
+ DismissibleContentDragController(
+ scope = scope,
+ maxBound = maxBound,
+ onDismissed = onDismissed,
+ )
+ }
+}
+
+private class DismissibleContentDragController(
+ private val scope: CoroutineScope,
+ private val maxBound: () -> Float,
+ private val onDismissed: () -> Unit,
+) : NestedDraggable.Controller {
+ private val offsetAnimatable = Animatable(0f)
+ private var lastTarget = 0f
+ private var range = 0f..1f
+ private var shouldConsumePreScrolls by mutableStateOf(false)
+
+ override val autoStopNestedDrags: Boolean
+ get() = true
+
+ val offset: Float
+ get() = offsetAnimatable.value
+
+ fun shouldConsumePreScrolls(sign: Float): Boolean {
+ if (!shouldConsumePreScrolls) return false
+
+ if (lastTarget > 0f && sign < 0f) {
+ range = 0f..maxBound()
+ return true
+ }
+
+ if (lastTarget < 0f && sign > 0f) {
+ range = -maxBound()..0f
+ return true
+ }
+
+ return false
+ }
+
+ fun shouldConsumePostScrolls(sign: Float): Boolean {
+ val max = maxBound()
+ if (sign > 0f && lastTarget < max) {
+ range = 0f..maxBound()
+ return true
+ }
+
+ if (sign < 0f && lastTarget > -max) {
+ range = -maxBound()..0f
+ return true
+ }
+
+ return false
+ }
+
+ override fun onDrag(delta: Float): Float {
+ val previousTarget = lastTarget
+ lastTarget = (lastTarget + delta).fastCoerceIn(range.start, range.endInclusive)
+ val newTarget = lastTarget
+ scope.launch { offsetAnimatable.snapTo(newTarget) }
+ return lastTarget - previousTarget
+ }
+
+ override suspend fun onDragStopped(velocity: Float, awaitFling: suspend () -> Unit): Float {
+ val rangeMiddle = range.start + (range.endInclusive - range.start) / 2f
+ lastTarget =
+ when {
+ lastTarget >= rangeMiddle -> range.endInclusive
+ else -> range.start
+ }
+
+ shouldConsumePreScrolls = lastTarget != 0f
+ val newTarget = lastTarget
+
+ scope.launch {
+ offsetAnimatable.animateTo(newTarget)
+ if (newTarget != 0f) {
+ onDismissed()
+ }
+ }
+ return velocity
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/SwipeToReveal.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/SwipeToReveal.kt
index 770762c..1d7b79d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/SwipeToReveal.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/SwipeToReveal.kt
@@ -22,7 +22,6 @@
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.absoluteOffset
-import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.overscroll
import androidx.compose.foundation.withoutVisualEffect
import androidx.compose.runtime.Composable
@@ -82,7 +81,7 @@
// overscroll visual effect.
//
// This is the NestedDraggalbe controller.
- val revealedContentDragController = rememberRevealedContentDragController {
+ val revealedContentDragController = rememberDismissibleContentDragController {
revealedContentBoxWidth.value.toFloat()
}
@@ -186,7 +185,7 @@
}
@Composable
-private fun rememberRevealedContentDragController(
+private fun rememberDismissibleContentDragController(
maxBound: () -> Float
): RevealedContentDragController {
val scope = rememberCoroutineScope()
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index efed260..3f1401c 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -239,6 +239,7 @@
@Override
public void onDisplayAddSystemDecorations(int displayId) {
CommandQueue.Callbacks.super.onDisplayAddSystemDecorations(displayId);
+ mEdgeBackGestureHandler.onDisplayAddSystemDecorations(displayId);
if (mLauncherProxyService.getProxy() == null) {
return;
}
@@ -253,6 +254,7 @@
@Override
public void onDisplayRemoved(int displayId) {
CommandQueue.Callbacks.super.onDisplayRemoved(displayId);
+ mEdgeBackGestureHandler.onDisplayRemoveSystemDecorations(displayId);
if (mLauncherProxyService.getProxy() == null) {
return;
}
@@ -267,6 +269,7 @@
@Override
public void onDisplayRemoveSystemDecorations(int displayId) {
CommandQueue.Callbacks.super.onDisplayRemoveSystemDecorations(displayId);
+ mEdgeBackGestureHandler.onDisplayRemoveSystemDecorations(displayId);
if (mLauncherProxyService.getProxy() == null) {
return;
}
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 6cda192..b74135a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -22,6 +22,7 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
import static com.android.systemui.Flags.edgebackGestureHandlerGetRunningTasksBackground;
+import static com.android.window.flags.Flags.enableMultidisplayTrackpadBackGesture;
import static com.android.systemui.Flags.predictiveBackDelayWmTransition;
import static com.android.systemui.classifier.Classifier.BACK_GESTURE;
import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadThreeFingerSwipe;
@@ -115,6 +116,8 @@
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
@@ -279,8 +282,7 @@
private boolean mIsTrackpadThreeFingerSwipe;
private boolean mIsButtonForcedVisible;
- private InputMonitorCompat mInputMonitor;
- private InputChannelCompat.InputEventReceiver mInputEventReceiver;
+ private final Map<Integer, InputMonitorResource> mInputMonitorResources = new HashMap<>();
private NavigationEdgeBackPlugin mEdgeBackPlugin;
private BackAnimation mBackAnimation;
@@ -665,14 +667,44 @@
mIsNavBarShownTransiently = isTransient;
}
- private void disposeInputChannel() {
- if (mInputEventReceiver != null) {
- mInputEventReceiver.dispose();
- mInputEventReceiver = null;
+ /**
+ * Called when a new display gets connected
+ *
+ * @param displayId The id associated with the connected display.
+ */
+ public void onDisplayAddSystemDecorations(int displayId) {
+ if (enableMultidisplayTrackpadBackGesture() && mIsEnabled) {
+ mUiThreadContext.runWithScissors(() -> {
+ removeAndDisposeInputMonitorResource(displayId);
+ mInputMonitorResources.put(displayId, new InputMonitorResource(displayId));
+ });
}
- if (mInputMonitor != null) {
- mInputMonitor.dispose();
- mInputMonitor = null;
+ }
+
+ /**
+ * Called when a display gets disconnected
+ *
+ * @param displayId The id associated with the disconnected display.
+ */
+ public void onDisplayRemoveSystemDecorations(int displayId) {
+ if (enableMultidisplayTrackpadBackGesture()) {
+ mUiThreadContext.runWithScissors(() -> removeAndDisposeInputMonitorResource(displayId));
+ }
+ }
+
+ private void removeAndDisposeInputMonitorResource(int displayId) {
+ InputMonitorResource inputMonitor = mInputMonitorResources.remove(displayId);
+ if (inputMonitor != null) {
+ inputMonitor.dispose();
+ }
+ }
+
+ private void disposeInputChannels() {
+ Iterator<Map.Entry<Integer, InputMonitorResource>> iterator =
+ mInputMonitorResources.entrySet().iterator();
+ while (iterator.hasNext()) {
+ iterator.next().getValue().dispose();
+ iterator.remove();
}
}
@@ -691,7 +723,7 @@
return;
}
mIsEnabled = isEnabled;
- disposeInputChannel();
+ disposeInputChannels();
if (mEdgeBackPlugin != null) {
mEdgeBackPlugin.onDestroy();
@@ -746,9 +778,8 @@
}
// Register input event receiver
- mInputMonitor = new InputMonitorCompat("edge-swipe", mDisplayId);
- mInputEventReceiver = mInputMonitor.getInputReceiver(mUiThreadContext.getLooper(),
- mUiThreadContext.getChoreographer(), this::onInputEvent);
+ mInputMonitorResources.put(mDisplayId, new InputMonitorResource(mDisplayId));
+ //TODO(b/382774299): Register input monitor on connected displays (if any)
// Add a nav bar panel window
resetEdgeBackPlugin();
@@ -950,9 +981,10 @@
return true;
}
- private boolean isValidTrackpadBackGesture(boolean isTrackpadEvent) {
- if (!isTrackpadEvent) {
- return false;
+ private boolean isValidTrackpadBackGesture(int displayId) {
+ if (enableMultidisplayTrackpadBackGesture() && displayId != mDisplayId) {
+ //TODO(b/382774299): Handle exclude regions on connected displays
+ return true;
}
// for trackpad gestures, unless the whole screen is excluded region, 3-finger swipe
// gestures are allowed even if the cursor is in the excluded region.
@@ -969,14 +1001,15 @@
private boolean isWithinTouchRegion(MotionEvent ev) {
// If the point is inside the PiP or Nav bar overlay excluded bounds, then ignore the back
- // gesture
+ // gesture. Also ignore (for now) if it's not on the main display.
+ // TODO(b/382130680): Implement back gesture handling on connected displays
int x = (int) ev.getX();
int y = (int) ev.getY();
final boolean isInsidePip = mIsInPip && mPipExcludedBounds.contains(x, y);
final boolean isInDesktopExcludeRegion = desktopExcludeRegionContains(x, y)
&& isEdgeResizePermitted(ev);
if (isInsidePip || isInDesktopExcludeRegion
- || mNavBarOverlayExcludedBounds.contains(x, y)) {
+ || mNavBarOverlayExcludedBounds.contains(x, y) || ev.getDisplayId() != mDisplayId) {
return false;
}
@@ -1076,7 +1109,11 @@
// Verify if this is in within the touch region and we aren't in immersive mode, and
// either the bouncer is showing or the notification panel is hidden
- mInputEventReceiver.setBatchingEnabled(false);
+ InputMonitorResource inputMonitorResource =
+ mInputMonitorResources.get(ev.getDisplayId());
+ if (inputMonitorResource != null) {
+ inputMonitorResource.mInputEventReceiver.setBatchingEnabled(false);
+ }
if (mIsTrackpadThreeFingerSwipe) {
// Since trackpad gestures don't have zones, this will be determined later by the
// direction of the gesture. {@code mIsOnLeftEdge} is set to false to begin with.
@@ -1099,7 +1136,7 @@
boolean trackpadGesturesEnabled =
(mSysUiFlags & SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED) == 0;
mAllowGesture = isBackAllowedCommon && trackpadGesturesEnabled
- && isValidTrackpadBackGesture(true /* isTrackpadEvent */);
+ && isValidTrackpadBackGesture(ev.getDisplayId());
} else {
mAllowGesture = isBackAllowedCommon && !mUsingThreeButtonNav && isWithinInsets
&& isWithinTouchRegion(ev) && !isButtonPressFromTrackpad(ev);
@@ -1210,12 +1247,14 @@
}
private void pilferPointers() {
- if (mInputMonitor != null) {
+ //TODO(b/382774299): Pilfer pointers on the correct display
+ InputMonitorResource inputMonitorResource = mInputMonitorResources.get(mDisplayId);
+ if (inputMonitorResource != null) {
// Capture inputs
- mInputMonitor.pilferPointers();
+ inputMonitorResource.mInputMonitorCompat.pilferPointers();
// Notify FalsingManager that an intentional gesture has occurred.
mFalsingManager.isFalseTouch(BACK_GESTURE);
- mInputEventReceiver.setBatchingEnabled(true);
+ inputMonitorResource.mInputEventReceiver.setBatchingEnabled(true);
}
}
@@ -1344,6 +1383,11 @@
if (mEdgeBackPlugin != null) {
mEdgeBackPlugin.dump(pw);
}
+ pw.println(" mInputMonitorResources=" + mInputMonitorResources);
+ for (Map.Entry<Integer, InputMonitorResource> inputMonitorResource :
+ mInputMonitorResources.entrySet()) {
+ inputMonitorResource.getValue().dump("\t", pw);
+ }
}
private void updateTopActivityPackageName() {
@@ -1376,6 +1420,33 @@
}
}
+ private class InputMonitorResource {
+ private final int mDisplayId;
+ private final InputMonitorCompat mInputMonitorCompat;
+ private final InputChannelCompat.InputEventReceiver mInputEventReceiver;
+
+ private InputMonitorResource(int displayId) {
+ this.mDisplayId = displayId;
+ mInputMonitorCompat = new InputMonitorCompat("edge-swipe", displayId);
+ mInputEventReceiver = mInputMonitorCompat.getInputReceiver(mUiThreadContext.getLooper(),
+ mUiThreadContext.getChoreographer(), EdgeBackGestureHandler.this::onInputEvent);
+ }
+
+ public void dispose() {
+ mInputEventReceiver.dispose();
+ mInputMonitorCompat.dispose();
+ }
+
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + this);
+ }
+
+ @Override
+ public String toString() {
+ return "InputMonitorResource (displayId=" + mDisplayId + ")";
+ }
+ }
+
private static class LogArray extends ArrayDeque<String> {
private final int mLength;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
index ad0acbd..8bc3203 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
@@ -502,10 +502,6 @@
boolean mHasBlurs;
@Override
- public void onWallpaperZoomOutChanged(float zoomOut) {
- }
-
- @Override
public void onBlurRadiusChanged(int radius) {
boolean hasBlurs = radius != 0;
if (hasBlurs == mHasBlurs) {
diff --git a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModel.kt
index cc11702..0a5222e 100644
--- a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModel.kt
@@ -37,7 +37,7 @@
mapOf(
Swipe.Up to HideOverlay(Overlays.NotificationsShade),
Back to HideOverlay(Overlays.NotificationsShade),
- Swipe.Down(fromSource = SceneContainerArea.EndHalf) to
+ Swipe.Down(fromSource = SceneContainerArea.TopEdgeEndHalf) to
ReplaceByOverlay(Overlays.QuickSettingsShade),
)
)
diff --git a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt
index 18b4b7d2..465c78e 100644
--- a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt
@@ -23,6 +23,7 @@
import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
@@ -50,6 +51,7 @@
val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory,
val sceneInteractor: SceneInteractor,
private val shadeInteractor: ShadeInteractor,
+ shadeModeInteractor: ShadeModeInteractor,
disableFlagsInteractor: DisableFlagsInteractor,
mediaCarouselInteractor: MediaCarouselInteractor,
activeNotificationsInteractor: ActiveNotificationsInteractor,
@@ -62,13 +64,13 @@
traceName = "showClock",
initialValue =
shouldShowClock(
- isShadeLayoutWide = shadeInteractor.isShadeLayoutWide.value,
+ isShadeLayoutWide = shadeModeInteractor.isShadeLayoutWide.value,
areAnyNotificationsPresent =
activeNotificationsInteractor.areAnyNotificationsPresentValue,
),
source =
combine(
- shadeInteractor.isShadeLayoutWide,
+ shadeModeInteractor.isShadeLayoutWide,
activeNotificationsInteractor.areAnyNotificationsPresent,
this::shouldShowClock,
),
diff --git a/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt
index faa77e5..e38a0a7 100644
--- a/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt
@@ -17,14 +17,16 @@
package com.android.systemui.power.data.repository
+import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.PowerManager
+import com.android.keyguard.UserActivityNotifier
+import com.android.systemui.Flags
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
-import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.power.shared.model.DozeScreenStateModel
@@ -33,6 +35,7 @@
import com.android.systemui.power.shared.model.WakefulnessModel
import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.util.time.SystemClock
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
@@ -102,6 +105,7 @@
@Application private val applicationContext: Context,
private val systemClock: SystemClock,
dispatcher: BroadcastDispatcher,
+ private val userActivityNotifier: UserActivityNotifier,
) : PowerRepository {
override val dozeScreenState = MutableStateFlow(DozeScreenStateModel.UNKNOWN)
@@ -163,12 +167,22 @@
)
}
+ @SuppressLint("MissingPermission")
override fun userTouch(noChangeLights: Boolean) {
- manager.userActivity(
- systemClock.uptimeMillis(),
- PowerManager.USER_ACTIVITY_EVENT_TOUCH,
- if (noChangeLights) PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS else 0,
- )
+ val pmFlags = if (noChangeLights) PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS else 0
+ if (Flags.bouncerUiRevamp()) {
+ userActivityNotifier.notifyUserActivity(
+ timeOfActivity = systemClock.uptimeMillis(),
+ event = PowerManager.USER_ACTIVITY_EVENT_TOUCH,
+ flags = pmFlags,
+ )
+ } else {
+ manager.userActivity(
+ systemClock.uptimeMillis(),
+ PowerManager.USER_ACTIVITY_EVENT_TOUCH,
+ pmFlags,
+ )
+ }
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt
index f9b1a36..11622be 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt
@@ -77,7 +77,7 @@
val showMedia: Boolean by
hydrator.hydratedStateOf(
traceName = "showMedia",
- source = mediaCarouselInteractor.hasActiveMediaOrRecommendation,
+ source = mediaCarouselInteractor.hasAnyMediaOrRecommendation,
)
override suspend fun onActivated(): Nothing {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModel.kt
index c86454e..2f7bc09 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModel.kt
@@ -46,7 +46,7 @@
put(Back, HideOverlay(Overlays.QuickSettingsShade))
}
put(
- Swipe.Down(fromSource = SceneContainerArea.StartHalf),
+ Swipe.Down(fromSource = SceneContainerArea.TopEdgeStartHalf),
ReplaceByOverlay(Overlays.NotificationsShade),
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerSwipeDetector.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerSwipeDetector.kt
index ede453db..760b97e 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerSwipeDetector.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerSwipeDetector.kt
@@ -58,6 +58,22 @@
}
)
+ data object TopEdgeStartHalf :
+ SceneContainerArea(
+ resolveArea = {
+ if (it == LayoutDirection.Ltr) Resolved.TopEdgeLeftHalf
+ else Resolved.TopEdgeRightHalf
+ }
+ )
+
+ data object TopEdgeEndHalf :
+ SceneContainerArea(
+ resolveArea = {
+ if (it == LayoutDirection.Ltr) Resolved.TopEdgeRightHalf
+ else Resolved.TopEdgeLeftHalf
+ }
+ )
+
override fun resolve(layoutDirection: LayoutDirection): Resolved {
return resolveArea(layoutDirection)
}
@@ -72,6 +88,12 @@
data object RightEdge : Resolved
data object RightHalf : Resolved
+
+ /** The left half of the top edge of the display. */
+ data object TopEdgeLeftHalf : Resolved
+
+ /** The right half of the top edge of the display. */
+ data object TopEdgeRightHalf : Resolved
}
}
@@ -108,9 +130,14 @@
Edge.Resolved.Left -> SceneContainerArea.Resolved.LeftEdge
Edge.Resolved.Bottom -> SceneContainerArea.Resolved.BottomEdge
Edge.Resolved.Right -> SceneContainerArea.Resolved.RightEdge
- else -> {
- // Note: This intentionally includes Edge.Resolved.Top. At the moment, we don't need
- // to detect swipes on the top edge, and consider them part of the right/left half.
+ Edge.Resolved.Top -> {
+ if (position.x < layoutSize.width * 0.5f) {
+ SceneContainerArea.Resolved.TopEdgeLeftHalf
+ } else {
+ SceneContainerArea.Resolved.TopEdgeRightHalf
+ }
+ }
+ null -> {
if (position.x < layoutSize.width * 0.5f) {
SceneContainerArea.Resolved.LeftHalf
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
index 917869a6..3e6f234 100644
--- a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
@@ -30,8 +30,10 @@
import android.graphics.RenderEffect;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Looper;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
@@ -52,6 +54,9 @@
* need to be careful to synchronize when necessary.
*/
public class ScrimView extends View {
+ private static final String TAG = "ScrimView";
+ private static final boolean isDebugLoggable = Build.isDebuggable() || Log.isLoggable(TAG,
+ Log.DEBUG);
private final Object mColorLock = new Object();
@@ -381,12 +386,21 @@
*/
public void setBlurRadius(float blurRadius) {
if (blurRadius > 0) {
+ debugLog("Apply blur RenderEffect to ScrimView " + mScrimName + " for radius "
+ + blurRadius);
setRenderEffect(RenderEffect.createBlurEffect(
blurRadius,
blurRadius,
Shader.TileMode.CLAMP));
} else {
+ debugLog("Resetting blur RenderEffect to ScrimView " + mScrimName);
setRenderEffect(null);
}
}
+
+ private void debugLog(String logMsg) {
+ if (isDebugLoggable) {
+ Log.d(TAG, logMsg);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
index 362b5db..c800ab3 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -43,6 +43,7 @@
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.compose.theme.PlatformTheme
import com.android.internal.annotations.VisibleForTesting
+import com.android.keyguard.UserActivityNotifier
import com.android.systemui.Flags
import com.android.systemui.ambient.touch.TouchMonitor
import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent
@@ -101,6 +102,7 @@
private val keyguardMediaController: KeyguardMediaController,
private val lockscreenSmartspaceController: LockscreenSmartspaceController,
@CommunalTouchLog logBuffer: LogBuffer,
+ private val userActivityNotifier: UserActivityNotifier,
) : LifecycleOwner {
private val logger = Logger(logBuffer, TAG)
@@ -655,11 +657,17 @@
}
return handled || hubShowing
} finally {
- powerManager.userActivity(
- SystemClock.uptimeMillis(),
- PowerManager.USER_ACTIVITY_EVENT_TOUCH,
- 0,
- )
+ if (Flags.bouncerUiRevamp()) {
+ userActivityNotifier.notifyUserActivity(
+ event = PowerManager.USER_ACTIVITY_EVENT_TOUCH
+ )
+ } else {
+ powerManager.userActivity(
+ SystemClock.uptimeMillis(),
+ PowerManager.USER_ACTIVITY_EVENT_TOUCH,
+ 0,
+ )
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index b906242..fcfce12 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -989,8 +989,10 @@
mBlurConfig.getMaxBlurRadiusPx(),
Shader.TileMode.CLAMP);
}
+ debugLog("Applying blur RenderEffect to shade.");
mView.setRenderEffect(mBlurRenderEffect);
} else {
+ debugLog("Resetting blur RenderEffect on shade.");
mView.setRenderEffect(null);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeStateTraceLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeStateTraceLogger.kt
index bd77961..de1b180 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeStateTraceLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeStateTraceLogger.kt
@@ -47,7 +47,7 @@
scope.launchTraced("ShadeStateTraceLogger") {
launch {
val stateLogger = createTraceStateLogger("isShadeLayoutWide")
- shadeInteractor.isShadeLayoutWide.collect { stateLogger.log(it.toString()) }
+ shadeModeInteractor.isShadeLayoutWide.collect { stateLogger.log(it.toString()) }
}
launch {
val stateLogger = createTraceStateLogger("shadeMode")
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index 6d68796..b54b518 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -56,15 +56,6 @@
/** Whether the shade can be expanded from QQS to QS. */
val isExpandToQsEnabled: Flow<Boolean>
-
- /**
- * Whether the shade layout should be wide (true) or narrow (false).
- *
- * In a wide layout, notifications and quick settings each take up only half the screen width
- * (whether they are shown at the same time or not). In a narrow layout, they can each be as
- * wide as the entire screen.
- */
- val isShadeLayoutWide: StateFlow<Boolean>
}
/** ShadeInteractor methods with implementations that differ between non-empty impls. */
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
index 77e6a83..4154e2c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
@@ -46,7 +46,6 @@
override val isUserInteracting: StateFlow<Boolean> = inactiveFlowBoolean
override val isShadeTouchable: Flow<Boolean> = inactiveFlowBoolean
override val isExpandToQsEnabled: Flow<Boolean> = inactiveFlowBoolean
- override val isShadeLayoutWide: StateFlow<Boolean> = inactiveFlowBoolean
override fun expandNotificationsShade(loggingReason: String, transitionKey: TransitionKey?) {}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
index e8b5d5b..fb3fc52 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
@@ -55,11 +55,7 @@
userSetupRepository: UserSetupRepository,
userSwitcherInteractor: UserSwitcherInteractor,
private val baseShadeInteractor: BaseShadeInteractor,
- shadeModeInteractor: ShadeModeInteractor,
-) :
- ShadeInteractor,
- BaseShadeInteractor by baseShadeInteractor,
- ShadeModeInteractor by shadeModeInteractor {
+) : ShadeInteractor, BaseShadeInteractor by baseShadeInteractor {
override val isShadeEnabled: StateFlow<Boolean> =
disableFlagsInteractor.disableFlags
.map { it.isShadeEnabled() }
@@ -127,8 +123,4 @@
disableFlags.isQuickSettingsEnabled() &&
!isDozing
}
-
- companion object {
- private const val TAG = "ShadeInteractor"
- }
}
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 8824276..d03f091 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
@@ -99,12 +99,12 @@
traceName = "showClock",
initialValue =
shouldShowClock(
- isShadeLayoutWide = shadeInteractor.isShadeLayoutWide.value,
+ isShadeLayoutWide = shadeModeInteractor.isShadeLayoutWide.value,
overlays = sceneInteractor.currentOverlays.value,
),
source =
combine(
- shadeInteractor.isShadeLayoutWide,
+ shadeModeInteractor.isShadeLayoutWide,
sceneInteractor.currentOverlays,
::shouldShowClock,
),
@@ -276,15 +276,17 @@
data object Weak : HeaderChipHighlight {
override fun backgroundColor(colorScheme: ColorScheme): Color =
- colorScheme.primary.copy(alpha = 0.1f)
+ colorScheme.surface.copy(alpha = 0.1f)
- override fun foregroundColor(colorScheme: ColorScheme): Color = colorScheme.primary
+ override fun foregroundColor(colorScheme: ColorScheme): Color = colorScheme.onSurface
}
data object Strong : HeaderChipHighlight {
- override fun backgroundColor(colorScheme: ColorScheme): Color = colorScheme.secondary
+ override fun backgroundColor(colorScheme: ColorScheme): Color =
+ colorScheme.primaryContainer
- override fun foregroundColor(colorScheme: ColorScheme): Color = colorScheme.onSecondary
+ override fun foregroundColor(colorScheme: ColorScheme): Color =
+ colorScheme.onPrimaryContainer
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt
index cf3b08c..8d2d9ef 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt
@@ -71,6 +71,8 @@
Swipe.Down to ShowOverlay(Overlays.NotificationsShade),
Swipe.Down(fromSource = SceneContainerArea.EndHalf) to
ShowOverlay(Overlays.QuickSettingsShade),
+ Swipe.Down(fromSource = SceneContainerArea.TopEdgeEndHalf) to
+ ShowOverlay(Overlays.QuickSettingsShade),
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ImmersiveModeConfirmation.java b/packages/SystemUI/src/com/android/systemui/statusbar/ImmersiveModeConfirmation.java
index 2a9a47d..c12742e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ImmersiveModeConfirmation.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ImmersiveModeConfirmation.java
@@ -79,7 +79,6 @@
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.util.settings.SecureSettings;
-import com.android.systemui.utils.windowmanager.WindowManagerProvider;
import javax.inject.Inject;
@@ -106,7 +105,6 @@
private long mShowDelayMs = 0L;
private final IBinder mWindowToken = new Binder();
private final CommandQueue mCommandQueue;
- private final WindowManagerProvider mWindowManagerProvider;
private ClingWindowView mClingWindow;
/** The wrapper on the last {@link WindowManager} used to add the confirmation window. */
@@ -133,8 +131,7 @@
@Inject
public ImmersiveModeConfirmation(Context context, CommandQueue commandQueue,
- SecureSettings secureSettings, @Background Handler backgroundHandler,
- WindowManagerProvider windowManagerProvider) {
+ SecureSettings secureSettings, @Background Handler backgroundHandler) {
mSysUiContext = context;
final Display display = mSysUiContext.getDisplay();
mDisplayContext = display.getDisplayId() == DEFAULT_DISPLAY
@@ -142,7 +139,6 @@
mCommandQueue = commandQueue;
mSecureSettings = secureSettings;
mBackgroundHandler = backgroundHandler;
- mWindowManagerProvider = windowManagerProvider;
}
boolean loadSetting(int currentUserId) {
@@ -527,7 +523,7 @@
mWindowContextRootDisplayAreaId = rootDisplayAreaId;
mWindowContext = mDisplayContext.createWindowContext(
IMMERSIVE_MODE_CONFIRMATION_WINDOW_TYPE, options);
- mWindowManager = mWindowManagerProvider.getWindowManager(mWindowContext);
+ mWindowManager = mWindowContext.getSystemService(WindowManager.class);
return mWindowManager;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index d2f424a..ba44683 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -74,7 +74,7 @@
private val singleShadeOverScrollerFactory: SingleShadeLockScreenOverScroller.Factory,
private val activityStarter: ActivityStarter,
wakefulnessLifecycle: WakefulnessLifecycle,
- configurationController: ConfigurationController,
+ @ShadeDisplayAware configurationController: ConfigurationController,
falsingManager: FalsingManager,
dumpManager: DumpManager,
qsTransitionControllerFactory: LockscreenShadeQsTransitionController.Factory,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java
index 2030606..72ece3d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java
@@ -73,7 +73,7 @@
}
return null;
} else {
- return row.getEntry().getSbn().getNotification();
+ return row.getEntryLegacy().getSbn().getNotification();
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index e292bcf..f844d1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -342,7 +342,6 @@
keyguardInteractor.setZoomOut(zoomOutFromShadeRadius)
}
listeners.forEach {
- it.onWallpaperZoomOutChanged(zoomOutFromShadeRadius)
it.onBlurRadiusChanged(appliedBlurRadius)
}
notificationShadeWindowController.setBackgroundBlurRadius(appliedBlurRadius)
@@ -761,9 +760,6 @@
/** Invoked when changes are needed in z-space */
interface DepthListener {
- /** Current wallpaper zoom out, where 0 is the closest, and 1 the farthest */
- fun onWallpaperZoomOutChanged(zoomOut: Float)
-
fun onBlurRadiusChanged(blurRadius: Int) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
index 9cae6c1..0763cb7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
@@ -21,6 +21,7 @@
import android.content.Context
import android.view.View
import com.android.internal.jank.Cuj
+import com.android.internal.logging.InstanceId
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.animation.ComposableControllerFactory
import com.android.systemui.animation.DelegateTransitionAnimatorController
@@ -41,6 +42,7 @@
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel
+import com.android.systemui.statusbar.chips.uievents.StatusBarChipsUiEventLogger
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
@@ -59,7 +61,7 @@
/** View model for the ongoing phone call chip shown in the status bar. */
@SysUISingleton
-open class CallChipViewModel
+class CallChipViewModel
@Inject
constructor(
@Main private val context: Context,
@@ -68,6 +70,7 @@
systemClock: SystemClock,
private val activityStarter: ActivityStarter,
@StatusBarChipsLog private val logger: LogBuffer,
+ private val uiEventLogger: StatusBarChipsUiEventLogger,
) : OngoingActivityChipViewModel {
/** The transition cookie used to register and unregister launch and return animations. */
private val cookie =
@@ -180,7 +183,7 @@
isHidden: Boolean,
transitionState: TransitionState = TransitionState.NoTransition,
): OngoingActivityChipModel.Active {
- val key = state.notificationKey
+ val key = "$KEY_PREFIX${state.notificationKey}"
val contentDescription = getContentDescription(state.appName)
val icon =
if (state.notificationIconView != null) {
@@ -199,6 +202,8 @@
}
val colors = ColorsModel.AccentThemed
+ val intent = state.intent
+ val instanceId = state.notificationInstanceId
// This block mimics OngoingCallController#updateChip.
if (state.startTimeMs <= 0L) {
@@ -208,10 +213,11 @@
key = key,
icon = icon,
colors = colors,
- onClickListenerLegacy = getOnClickListener(state.intent),
- clickBehavior = getClickBehavior(state.intent),
+ onClickListenerLegacy = getOnClickListener(intent, instanceId),
+ clickBehavior = getClickBehavior(intent, instanceId),
isHidden = isHidden,
transitionManager = getTransitionManager(state, transitionState),
+ instanceId = instanceId,
)
} else {
val startTimeInElapsedRealtime =
@@ -221,19 +227,26 @@
icon = icon,
colors = colors,
startTimeMs = startTimeInElapsedRealtime,
- onClickListenerLegacy = getOnClickListener(state.intent),
- clickBehavior = getClickBehavior(state.intent),
+ onClickListenerLegacy = getOnClickListener(intent, instanceId),
+ clickBehavior = getClickBehavior(intent, instanceId),
isHidden = isHidden,
transitionManager = getTransitionManager(state, transitionState),
+ instanceId = instanceId,
)
}
}
- private fun getOnClickListener(intent: PendingIntent?): View.OnClickListener? {
+ private fun getOnClickListener(
+ intent: PendingIntent?,
+ instanceId: InstanceId?,
+ ): View.OnClickListener? {
if (intent == null) return null
return View.OnClickListener { view ->
StatusBarChipsModernization.assertInLegacyMode()
+
logger.log(TAG, LogLevel.INFO, {}, { "Chip clicked" })
+ uiEventLogger.logChipTapToShow(instanceId)
+
val backgroundView =
view.requireViewById<ChipBackgroundContainer>(R.id.ongoing_activity_chip_background)
// This mimics OngoingCallController#updateChipClickListener.
@@ -247,13 +260,20 @@
}
}
- private fun getClickBehavior(intent: PendingIntent?): OngoingActivityChipModel.ClickBehavior =
+ private fun getClickBehavior(
+ intent: PendingIntent?,
+ instanceId: InstanceId?,
+ ): OngoingActivityChipModel.ClickBehavior =
if (intent == null) {
OngoingActivityChipModel.ClickBehavior.None
} else {
OngoingActivityChipModel.ClickBehavior.ExpandAction(
onClick = { expandable ->
StatusBarChipsModernization.unsafeAssertInNewMode()
+
+ logger.log(TAG, LogLevel.INFO, {}, { "Chip clicked" })
+ uiEventLogger.logChipTapToShow(instanceId)
+
val animationController =
if (
!StatusBarChipsReturnAnimations.isEnabled ||
@@ -413,6 +433,8 @@
)
private val TAG = "CallVM".pad()
+ const val KEY_PREFIX = "callChip-"
+
/** Determines whether or not an active call chip should be hidden. */
private fun shouldChipBeHidden(
oldState: OngoingCallModel,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
index c862460..596770f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
@@ -18,7 +18,6 @@
import android.content.Context
import androidx.annotation.DrawableRes
-import androidx.annotation.VisibleForTesting
import com.android.internal.jank.Cuj
import com.android.systemui.animation.DialogCuj
import com.android.systemui.animation.DialogTransitionAnimator
@@ -44,6 +43,7 @@
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickCallback
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickListener
+import com.android.systemui.statusbar.chips.uievents.StatusBarChipsUiEventLogger
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -70,7 +70,11 @@
private val dialogTransitionAnimator: DialogTransitionAnimator,
private val endMediaProjectionDialogHelper: EndMediaProjectionDialogHelper,
@StatusBarChipsLog private val logger: LogBuffer,
+ private val uiEventLogger: StatusBarChipsUiEventLogger,
) : OngoingActivityChipViewModel {
+ // There can only be 1 active cast-to-other-device chip at a time, so we can re-use the ID.
+ private val instanceId = uiEventLogger.createNewInstanceId()
+
/** The cast chip to show, based only on MediaProjection API events. */
private val projectionChip: StateFlow<OngoingActivityChipModel> =
mediaProjectionChipInteractor.projection
@@ -213,8 +217,10 @@
createCastScreenToOtherDeviceDialogDelegate(state),
dialogTransitionAnimator,
DIALOG_CUJ,
- logger,
- TAG,
+ instanceId = instanceId,
+ uiEventLogger = uiEventLogger,
+ logger = logger,
+ tag = TAG,
),
clickBehavior =
OngoingActivityChipModel.ClickBehavior.ExpandAction(
@@ -223,10 +229,13 @@
createCastScreenToOtherDeviceDialogDelegate(state),
dialogTransitionAnimator,
DIALOG_CUJ,
- logger,
- TAG,
+ instanceId = instanceId,
+ uiEventLogger = uiEventLogger,
+ logger = logger,
+ tag = TAG,
)
),
+ instanceId = instanceId,
)
}
@@ -248,8 +257,10 @@
createGenericCastToOtherDeviceDialogDelegate(deviceName),
dialogTransitionAnimator,
DIALOG_CUJ_AUDIO_ONLY,
- logger,
- TAG,
+ instanceId = instanceId,
+ uiEventLogger = uiEventLogger,
+ logger = logger,
+ tag = TAG,
),
clickBehavior =
OngoingActivityChipModel.ClickBehavior.ExpandAction(
@@ -257,10 +268,13 @@
createGenericCastToOtherDeviceDialogDelegate(deviceName),
dialogTransitionAnimator,
DIALOG_CUJ_AUDIO_ONLY,
- logger,
- TAG,
+ instanceId = instanceId,
+ uiEventLogger = uiEventLogger,
+ logger = logger,
+ tag = TAG,
)
),
+ instanceId = instanceId,
)
}
@@ -281,7 +295,7 @@
)
companion object {
- @VisibleForTesting const val KEY = "CastToOtherDevice"
+ const val KEY = "CastToOtherDevice"
@DrawableRes val CAST_TO_OTHER_DEVICE_ICON = R.drawable.ic_cast_connected
private val DIALOG_CUJ =
DialogCuj(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, tag = "Cast to other device")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndMediaProjectionDialogHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndMediaProjectionDialogHelper.kt
index 2d9ccb7..33ff6c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndMediaProjectionDialogHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndMediaProjectionDialogHelper.kt
@@ -19,6 +19,7 @@
import android.app.ActivityManager
import android.content.DialogInterface
import android.content.pm.PackageManager
+import android.util.Log
import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.mediaprojection.data.model.MediaProjectionState
@@ -54,10 +55,6 @@
// dialog to animate back into the chip just for the chip to disappear in a few frames.
dialogTransitionAnimator.disableAllCurrentDialogsExitAnimations()
stopAction.invoke()
- // TODO(b/332662551): If the projection is stopped, there's a brief moment where the
- // dialog closes and the chip re-shows because the system APIs haven't come back and
- // told SysUI that the projection has officially stopped. It would be great for the chip
- // to not re-show at all.
}
}
@@ -85,8 +82,17 @@
val appInfo = packageManager.getApplicationInfo(packageName, 0)
appInfo.loadLabel(packageManager)
} catch (e: PackageManager.NameNotFoundException) {
- // TODO(b/332662551): Log this error.
+ Log.w(
+ TAG,
+ "Failed to find application info for package: $packageName when creating " +
+ "end media projection dialog",
+ e,
+ )
null
}
}
+
+ companion object {
+ private const val TAG = "EndMediaProjectionDialogHelper"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
index a0de879..6e0682c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
@@ -149,6 +149,7 @@
creationTime = creationTime,
isAppVisible = appVisibility.isAppCurrentlyVisible,
lastAppVisibleTime = appVisibility.lastAppVisibleTime,
+ instanceId = instanceId,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
index 9380dfe..0560c9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
@@ -145,7 +145,9 @@
/**
* Emits all notifications that are eligible to show as chips in the status bar. This is
- * different from which chips will *actually* show, see [shownNotificationChips] for that.
+ * different from which chips will *actually* show, because
+ * [com.android.systemui.statusbar.chips.notification.ui.viewmodel.NotifChipsViewModel] will
+ * hide chips that have [NotificationChipModel.isAppVisible] as true.
*/
val allNotificationChips: Flow<List<NotificationChipModel>> =
if (StatusBarNotifChips.isEnabled) {
@@ -186,15 +188,6 @@
initialValue = emptyList(),
)
- /** Emits the notifications that should actually be *shown* as chips in the status bar. */
- val shownNotificationChips: Flow<List<NotificationChipModel>> =
- allNotificationChips.map { chipsList ->
- // If the app that posted this notification is visible, we want to hide the chip
- // because information between the status bar chip and the app itself could be
- // out-of-sync (like a timer that's slightly off)
- chipsList.filter { !it.isAppVisible }
- }
-
/*
Stable sort the promoted notifications by two criteria:
Criteria #1: Whichever app was most recently visible has higher ranking.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt
index 356731c..dad51bac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.chips.notification.domain.model
+import com.android.internal.logging.InstanceId
import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModels
@@ -35,4 +36,6 @@
* hasn't become visible since the notification became promoted.
*/
val lastAppVisibleTime: Long?,
+ /** An optional per-notification ID used for logging. */
+ val instanceId: InstanceId?,
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
index dfbd12d..83ef13d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
@@ -55,12 +55,12 @@
private val systemClock: SystemClock,
) {
/**
- * A flow modeling the notification chips that should be shown. Emits an empty list if there are
- * no notifications that should show a status bar chip.
+ * A flow modeling the current notification chips. Emits an empty list if there are no
+ * notifications that are eligible to show a status bar chip.
*/
val chips: Flow<List<OngoingActivityChipModel.Active>> =
combine(
- notifChipsInteractor.shownNotificationChips,
+ notifChipsInteractor.allNotificationChips,
headsUpNotificationInteractor.statusBarHeadsUpState,
) { notifications, headsUpState ->
notifications.map { it.toActivityChipModel(headsUpState) }
@@ -98,6 +98,10 @@
notifChipsInteractor.onPromotedNotificationChipTapped(this@toActivityChipModel.key)
}
}
+ // If the app that posted this notification is visible, we want to hide the chip
+ // because information between the status bar chip and the app itself could be
+ // out-of-sync (like a timer that's slightly off)
+ val isHidden = this.isAppVisible
val onClickListenerLegacy =
View.OnClickListener {
StatusBarChipsModernization.assertInLegacyMode()
@@ -122,6 +126,8 @@
colors = colors,
onClickListenerLegacy = onClickListenerLegacy,
clickBehavior = clickBehavior,
+ isHidden = isHidden,
+ instanceId = instanceId,
)
}
@@ -133,6 +139,8 @@
text = chipContent.shortCriticalText,
onClickListenerLegacy = onClickListenerLegacy,
clickBehavior = clickBehavior,
+ isHidden = isHidden,
+ instanceId = instanceId,
)
}
@@ -147,6 +155,8 @@
colors = colors,
onClickListenerLegacy = onClickListenerLegacy,
clickBehavior = clickBehavior,
+ isHidden = isHidden,
+ instanceId = instanceId,
)
}
@@ -157,6 +167,8 @@
colors = colors,
onClickListenerLegacy = onClickListenerLegacy,
clickBehavior = clickBehavior,
+ isHidden = isHidden,
+ instanceId = instanceId,
)
}
@@ -173,6 +185,8 @@
time = chipContent.time.currentTimeMillis,
onClickListenerLegacy = onClickListenerLegacy,
clickBehavior = clickBehavior,
+ isHidden = isHidden,
+ instanceId = instanceId,
)
} else {
// Don't show a `when` time that's close to now or in the past because it's
@@ -189,6 +203,8 @@
colors = colors,
onClickListenerLegacy = onClickListenerLegacy,
clickBehavior = clickBehavior,
+ isHidden = isHidden,
+ instanceId = instanceId,
)
}
}
@@ -201,6 +217,8 @@
isEventInFuture = chipContent.time.isCountDown,
onClickListenerLegacy = onClickListenerLegacy,
clickBehavior = clickBehavior,
+ isHidden = isHidden,
+ instanceId = instanceId,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
index 363b8be..336a9f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
@@ -19,7 +19,6 @@
import android.app.ActivityManager
import android.content.Context
import androidx.annotation.DrawableRes
-import androidx.annotation.VisibleForTesting
import com.android.internal.jank.Cuj
import com.android.systemui.animation.DialogCuj
import com.android.systemui.animation.DialogTransitionAnimator
@@ -44,6 +43,7 @@
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickCallback
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickListener
+import com.android.systemui.statusbar.chips.uievents.StatusBarChipsUiEventLogger
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
@@ -66,7 +66,9 @@
private val endMediaProjectionDialogHelper: EndMediaProjectionDialogHelper,
private val dialogTransitionAnimator: DialogTransitionAnimator,
@StatusBarChipsLog private val logger: LogBuffer,
+ private val uiEventLogger: StatusBarChipsUiEventLogger,
) : OngoingActivityChipViewModel {
+ private val instanceId = uiEventLogger.createNewInstanceId()
/** A direct mapping from [ScreenRecordChipModel] to [OngoingActivityChipModel]. */
private val simpleChip =
@@ -80,6 +82,7 @@
isImportantForPrivacy = true,
colors = ColorsModel.Red,
secondsUntilStarted = state.millisUntilStarted.toCountdownSeconds(),
+ instanceId = instanceId,
)
}
is ScreenRecordChipModel.Recording -> {
@@ -102,8 +105,10 @@
createDelegate(state.recordedTask),
dialogTransitionAnimator,
DIALOG_CUJ,
- logger,
- TAG,
+ instanceId = instanceId,
+ uiEventLogger = uiEventLogger,
+ logger = logger,
+ tag = TAG,
),
clickBehavior =
OngoingActivityChipModel.ClickBehavior.ExpandAction(
@@ -111,10 +116,13 @@
dialogDelegate = createDelegate(state.recordedTask),
dialogTransitionAnimator = dialogTransitionAnimator,
DIALOG_CUJ,
- logger,
- TAG,
+ instanceId = instanceId,
+ uiEventLogger = uiEventLogger,
+ logger = logger,
+ tag = TAG,
)
),
+ instanceId = instanceId,
)
}
}
@@ -167,7 +175,7 @@
}
companion object {
- @VisibleForTesting const val KEY = "ScreenRecord"
+ const val KEY = "ScreenRecord"
@DrawableRes val ICON = R.drawable.ic_screenrecord
private val DIALOG_CUJ =
DialogCuj(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, tag = "Screen record")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
index 0defa53..2678718 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
@@ -18,7 +18,6 @@
import android.content.Context
import androidx.annotation.DrawableRes
-import androidx.annotation.VisibleForTesting
import com.android.internal.jank.Cuj
import com.android.systemui.CoreStartable
import com.android.systemui.animation.DialogCuj
@@ -44,6 +43,7 @@
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickCallback
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickListener
+import com.android.systemui.statusbar.chips.uievents.StatusBarChipsUiEventLogger
import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
@@ -72,7 +72,10 @@
private val endMediaProjectionDialogHelper: EndMediaProjectionDialogHelper,
private val dialogTransitionAnimator: DialogTransitionAnimator,
@StatusBarChipsLog private val logger: LogBuffer,
+ private val uiEventLogger: StatusBarChipsUiEventLogger,
) : OngoingActivityChipViewModel, CoreStartable {
+ // There can only be 1 active cast-to-other-device chip at a time, so we can re-use the ID.
+ private val instanceId = uiEventLogger.createNewInstanceId()
private val _stopDialogToShow: MutableStateFlow<MediaProjectionStopDialogModel> =
MutableStateFlow(MediaProjectionStopDialogModel.Hidden)
@@ -238,8 +241,10 @@
createShareScreenToAppDialogDelegate(state),
dialogTransitionAnimator,
DIALOG_CUJ,
- logger,
- TAG,
+ instanceId = instanceId,
+ uiEventLogger = uiEventLogger,
+ logger = logger,
+ tag = TAG,
),
clickBehavior =
OngoingActivityChipModel.ClickBehavior.ExpandAction(
@@ -248,10 +253,13 @@
createShareScreenToAppDialogDelegate(state),
dialogTransitionAnimator,
DIALOG_CUJ,
- logger,
- TAG,
+ instanceId = instanceId,
+ uiEventLogger = uiEventLogger,
+ logger = logger,
+ tag = TAG,
)
),
+ instanceId = instanceId,
)
}
@@ -274,8 +282,10 @@
createGenericShareToAppDialogDelegate(),
dialogTransitionAnimator,
DIALOG_CUJ_AUDIO_ONLY,
- logger,
- TAG,
+ instanceId = instanceId,
+ uiEventLogger = uiEventLogger,
+ logger = logger,
+ tag = TAG,
),
clickBehavior =
OngoingActivityChipModel.ClickBehavior.ExpandAction(
@@ -283,10 +293,13 @@
createGenericShareToAppDialogDelegate(),
dialogTransitionAnimator,
DIALOG_CUJ_AUDIO_ONLY,
- logger,
- TAG,
+ instanceId = instanceId,
+ uiEventLogger = uiEventLogger,
+ logger = logger,
+ tag = TAG,
)
),
+ instanceId = instanceId,
)
}
@@ -306,7 +319,7 @@
)
companion object {
- @VisibleForTesting const val KEY = "ShareToApp"
+ const val KEY = "ShareToApp"
@DrawableRes val SHARE_TO_APP_ICON = R.drawable.ic_present_to_all
private val DIALOG_CUJ =
DialogCuj(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, tag = "Share to app")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt
index b268376..fe6065d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt
@@ -46,8 +46,9 @@
}
/** The chip should match the system theme main color. */
- // TODO(b/347717946): The chip's color isn't getting updated when the user switches theme, it
- // only gets updated when a different configuration change happens, like a rotation.
+ // Note: When StatusBarChipsModernization is disabled, the chip's color doesn't get
+ // updated when the user switches theme. It only gets updated when a different
+ // configuration change happens, like a rotation.
data object SystemThemed : ColorsModel {
override fun background(context: Context): ColorStateList =
ColorStateList.valueOf(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
index e28f368..d7b67b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
@@ -20,6 +20,7 @@
import android.annotation.ElapsedRealtimeLong
import android.os.SystemClock
import android.view.View
+import com.android.internal.logging.InstanceId
import com.android.systemui.animation.ComposableControllerFactory
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.ContentDescription
@@ -81,6 +82,11 @@
open val isHidden: Boolean,
/** Whether the transition from hidden to shown should be animated. */
open val shouldAnimate: Boolean,
+ /**
+ * An optional per-chip ID used for logging. Should stay the same throughout the lifetime of
+ * a single chip.
+ */
+ open val instanceId: InstanceId? = null,
) : OngoingActivityChipModel() {
/** This chip shows only an icon and nothing else. */
@@ -94,6 +100,7 @@
override val transitionManager: TransitionManager? = null,
override val isHidden: Boolean = false,
override val shouldAnimate: Boolean = true,
+ override val instanceId: InstanceId? = null,
) :
Active(
key,
@@ -105,6 +112,7 @@
transitionManager,
isHidden,
shouldAnimate,
+ instanceId,
) {
override val logName = "Active.Icon"
}
@@ -143,6 +151,7 @@
override val transitionManager: TransitionManager? = null,
override val isHidden: Boolean = false,
override val shouldAnimate: Boolean = true,
+ override val instanceId: InstanceId? = null,
) :
Active(
key,
@@ -154,6 +163,7 @@
transitionManager,
isHidden,
shouldAnimate,
+ instanceId,
) {
override val logName = "Active.Timer"
}
@@ -182,6 +192,7 @@
override val transitionManager: TransitionManager? = null,
override val isHidden: Boolean = false,
override val shouldAnimate: Boolean = true,
+ override val instanceId: InstanceId? = null,
) :
Active(
key,
@@ -193,6 +204,7 @@
transitionManager,
isHidden,
shouldAnimate,
+ instanceId,
) {
init {
StatusBarNotifChips.unsafeAssertInNewMode()
@@ -214,6 +226,7 @@
override val transitionManager: TransitionManager? = null,
override val isHidden: Boolean = false,
override val shouldAnimate: Boolean = true,
+ override val instanceId: InstanceId? = null,
) :
Active(
key,
@@ -225,6 +238,7 @@
transitionManager,
isHidden,
shouldAnimate,
+ instanceId,
) {
override val logName = "Active.Countdown"
}
@@ -235,13 +249,13 @@
override val isImportantForPrivacy: Boolean = false,
override val icon: ChipIcon,
override val colors: ColorsModel,
- // TODO(b/361346412): Enforce a max length requirement?
val text: String,
override val onClickListenerLegacy: View.OnClickListener? = null,
override val clickBehavior: ClickBehavior,
override val transitionManager: TransitionManager? = null,
override val isHidden: Boolean = false,
override val shouldAnimate: Boolean = true,
+ override val instanceId: InstanceId? = null,
) :
Active(
key,
@@ -253,6 +267,7 @@
transitionManager,
isHidden,
shouldAnimate,
+ instanceId,
) {
override val logName = "Active.Text"
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModel.kt
index 229d1a5..efc54f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.chips.ui.viewmodel
import android.view.View
+import com.android.internal.logging.InstanceId
import com.android.systemui.animation.DialogCuj
import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.animation.Expandable
@@ -26,6 +27,7 @@
import com.android.systemui.statusbar.chips.StatusBarChipsLog
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
+import com.android.systemui.statusbar.chips.uievents.StatusBarChipsUiEventLogger
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
import kotlinx.coroutines.flow.StateFlow
@@ -44,12 +46,17 @@
dialogDelegate: SystemUIDialog.Delegate,
dialogTransitionAnimator: DialogTransitionAnimator,
cuj: DialogCuj,
+ instanceId: InstanceId,
+ uiEventLogger: StatusBarChipsUiEventLogger,
@StatusBarChipsLog logger: LogBuffer,
tag: String,
): View.OnClickListener {
return View.OnClickListener { view ->
StatusBarChipsModernization.assertInLegacyMode()
+
logger.log(tag, LogLevel.INFO, {}, { "Chip clicked" })
+ uiEventLogger.logChipTapToShow(instanceId)
+
val dialog = dialogDelegate.createDialog()
val launchableView =
view.requireViewById<ChipBackgroundContainer>(
@@ -67,12 +74,17 @@
dialogDelegate: SystemUIDialog.Delegate,
dialogTransitionAnimator: DialogTransitionAnimator,
cuj: DialogCuj,
+ instanceId: InstanceId,
+ uiEventLogger: StatusBarChipsUiEventLogger,
@StatusBarChipsLog logger: LogBuffer,
tag: String,
): (Expandable) -> Unit {
return { expandable ->
StatusBarChipsModernization.unsafeAssertInNewMode()
+
logger.log(tag, LogLevel.INFO, {}, { "Chip clicked" })
+ uiEventLogger.logChipTapToShow(instanceId)
+
val dialog = dialogDelegate.createDialog()
val controller = expandable.dialogTransitionController(cuj)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
index 76d2af8..606604a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
@@ -264,6 +264,7 @@
// [OngoingActivityChipModel.Active.Countdown] is the only chip without an icon and
// [shouldSquish] returns false for that model, but protect against it just in case.)
val currentIcon = icon ?: return this
+ // TODO(b/364653005): Make sure every field is copied over.
return OngoingActivityChipModel.Active.IconOnly(
key = key,
isImportantForPrivacy = isImportantForPrivacy,
@@ -271,6 +272,7 @@
colors = colors,
onClickListenerLegacy = onClickListenerLegacy,
clickBehavior = clickBehavior,
+ instanceId = instanceId,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/uievents/StatusBarChipUiEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/uievents/StatusBarChipUiEvent.kt
new file mode 100644
index 0000000..8374930
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/uievents/StatusBarChipUiEvent.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.uievents
+
+import com.android.internal.logging.UiEvent
+import com.android.internal.logging.UiEventLogger
+
+/** All UI Events related to the status bar chips. */
+enum class StatusBarChipUiEvent(private val _id: Int) : UiEventLogger.UiEventEnum {
+ // New chip events, with chip type embedded in the event
+ @UiEvent(doc = "New status bar chip: Call") STATUS_BAR_NEW_CHIP_CALL(2211),
+ @UiEvent(doc = "New status bar chip: Screen record") STATUS_BAR_NEW_CHIP_SCREEN_RECORD(2212),
+ @UiEvent(doc = "New status bar chip: Share screen/audio to another app")
+ STATUS_BAR_NEW_CHIP_SHARE_TO_APP(2213),
+ @UiEvent(doc = "New status bar chip: Cast screen/audio to different device")
+ STATUS_BAR_NEW_CHIP_CAST_TO_OTHER_DEVICE(2214),
+ @UiEvent(doc = "New status bar chip: Promoted notification")
+ STATUS_BAR_NEW_CHIP_NOTIFICATION(2215),
+
+ // Other chip events, which don't need the chip type embedded in the event because an instanceId
+ // should also be provided with the new event and all subsequent events
+ @UiEvent(doc = "A status bar chip was removed") STATUS_BAR_CHIP_REMOVED(2216),
+ @UiEvent(doc = "A status bar chip was tapped to show more information")
+ STATUS_BAR_CHIP_TAP_TO_SHOW(2217),
+ @UiEvent(
+ doc = "A status bar chip was re-tapped to hide the information that was previously shown"
+ )
+ STATUS_BAR_CHIP_TAP_TO_HIDE(2218);
+
+ override fun getId() = _id
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/uievents/StatusBarChipsUiEventLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/uievents/StatusBarChipsUiEventLogger.kt
new file mode 100644
index 0000000..c2349db
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/uievents/StatusBarChipsUiEventLogger.kt
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.uievents
+
+import com.android.internal.logging.InstanceId
+import com.android.internal.logging.InstanceIdSequence
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.chips.call.ui.viewmodel.CallChipViewModel
+import com.android.systemui.statusbar.chips.casttootherdevice.ui.viewmodel.CastToOtherDeviceChipViewModel
+import com.android.systemui.statusbar.chips.screenrecord.ui.viewmodel.ScreenRecordChipViewModel
+import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.ShareToAppChipViewModel
+import com.android.systemui.statusbar.pipeline.shared.ui.model.ChipsVisibilityModel
+import com.android.systemui.util.kotlin.pairwise
+import javax.inject.Inject
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+
+/** Does all the UiEvent-related logging for the status bar chips. */
+@SysUISingleton
+class StatusBarChipsUiEventLogger @Inject constructor(private val logger: UiEventLogger) {
+ private val instanceIdSequence = InstanceIdSequence(INSTANCE_ID_MAX)
+
+ /** Get a new instance ID for a status bar chip. */
+ fun createNewInstanceId(): InstanceId {
+ return instanceIdSequence.newInstanceId()
+ }
+
+ /** Logs that the chip with the given ID was tapped to show additional information. */
+ fun logChipTapToShow(instanceId: InstanceId?) {
+ logger.log(StatusBarChipUiEvent.STATUS_BAR_CHIP_TAP_TO_SHOW, instanceId)
+ }
+
+ /**
+ * Logs that the chip with the given ID was tapped to hide the additional information that was
+ * previously shown.
+ */
+ fun logChipTapToHide(instanceId: InstanceId?) {
+ logger.log(StatusBarChipUiEvent.STATUS_BAR_CHIP_TAP_TO_HIDE, instanceId)
+ }
+
+ /** Starts UiEvent logging for the chips. */
+ suspend fun hydrateUiEventLogging(chipsFlow: Flow<ChipsVisibilityModel>) {
+ coroutineScope {
+ launch {
+ chipsFlow
+ .map { it.chips }
+ .distinctUntilChanged()
+ .pairwise()
+ .collect { (old, new) ->
+ val oldActive: Map<String, Pair<InstanceId?, Int>> =
+ old.active.withIndex().associate {
+ it.value.key to Pair(it.value.instanceId, it.index)
+ }
+ val newActive: Map<String, Pair<InstanceId?, Int>> =
+ new.active.withIndex().associate {
+ it.value.key to Pair(it.value.instanceId, it.index)
+ }
+
+ // Newly active keys
+ newActive.keys.minus(oldActive.keys).forEach { key ->
+ val uiEvent = key.getUiEventForNewChip()
+ val instanceId = newActive[key]!!.first
+ val position = newActive[key]!!.second
+ logger.logWithInstanceIdAndPosition(
+ uiEvent,
+ /* uid= */ 0,
+ /* packageName= */ null,
+ instanceId,
+ position,
+ )
+ }
+
+ // Newly inactive keys
+ oldActive.keys.minus(newActive.keys).forEach { key ->
+ val instanceId = oldActive[key]?.first
+ logger.log(StatusBarChipUiEvent.STATUS_BAR_CHIP_REMOVED, instanceId)
+ }
+ }
+ }
+ }
+ }
+
+ companion object {
+ private const val INSTANCE_ID_MAX = 1 shl 20
+
+ /**
+ * Given a key from an [OngoingActivityChipModel.Active] instance that was just added,
+ * return the right UiEvent type to log.
+ */
+ private fun String.getUiEventForNewChip(): StatusBarChipUiEvent {
+ return when {
+ this == ScreenRecordChipViewModel.KEY ->
+ StatusBarChipUiEvent.STATUS_BAR_NEW_CHIP_SCREEN_RECORD
+ this == ShareToAppChipViewModel.KEY ->
+ StatusBarChipUiEvent.STATUS_BAR_NEW_CHIP_SHARE_TO_APP
+ this == CastToOtherDeviceChipViewModel.KEY ->
+ StatusBarChipUiEvent.STATUS_BAR_NEW_CHIP_CAST_TO_OTHER_DEVICE
+ this.startsWith(CallChipViewModel.KEY_PREFIX) ->
+ StatusBarChipUiEvent.STATUS_BAR_NEW_CHIP_CALL
+ else -> StatusBarChipUiEvent.STATUS_BAR_NEW_CHIP_NOTIFICATION
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java
index 11ec2ed..e9a6ad2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java
@@ -108,13 +108,12 @@
/**
* Get the feedback status according to assistant's adjustments
*
- * @param entry Notification Entry to show feedback for
+ * @param ranking Ranking of the notification show feedback for
*/
- public int getFeedbackStatus(NotificationEntry entry) {
+ public int getFeedbackStatus(Ranking ranking) {
if (!isFeedbackEnabled()) {
return STATUS_UNCHANGED;
}
- Ranking ranking = entry.getRanking();
int oldImportance = ranking.getChannel().getImportance();
int newImportance = ranking.getImportance();
if (oldImportance < NotificationManager.IMPORTANCE_DEFAULT
@@ -138,11 +137,11 @@
* Get the feedback indicator image and content description resources according to assistant's
* changes on this notification's rank or importance.
*
- * @param entry Notification Entry to show feedback for
+ * @param ranking Ranking of the notification to show feedback for
*/
@Nullable
- public FeedbackIcon getFeedbackIcon(NotificationEntry entry) {
- int feedbackStatus = getFeedbackStatus(entry);
+ public FeedbackIcon getFeedbackIcon(Ranking ranking) {
+ int feedbackStatus = getFeedbackStatus(ranking);
return mIcons.get(feedbackStatus);
}
@@ -150,10 +149,10 @@
* Get the inline settings description resource according to assistant's changes on this
* notification's rank or importance.
*
- * @param entry Notification Entry to show feedback for
+ * @param ranking Ranking of the notification to show feedback for
*/
- public int getInlineDescriptionResource(NotificationEntry entry) {
- int feedbackStatus = getFeedbackStatus(entry);
+ public int getInlineDescriptionResource(Ranking ranking) {
+ int feedbackStatus = getFeedbackStatus(ranking);
switch (feedbackStatus) {
case STATUS_ALERTED:
return com.android.systemui.res.R.string.notification_channel_summary_automatic_alerted;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
index df8fb5e..afbec7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -71,46 +71,49 @@
Notification.MessagingStyle.CONVERSATION_TYPE_IMPORTANT
else if (entry.ranking.isConversation)
Notification.MessagingStyle.CONVERSATION_TYPE_NORMAL
- else
- Notification.MessagingStyle.CONVERSATION_TYPE_LEGACY
+ else Notification.MessagingStyle.CONVERSATION_TYPE_LEGACY
entry.ranking.conversationShortcutInfo?.let { shortcutInfo ->
logger.logAsyncTaskProgress(entry.logKey, "getting shortcut icon")
messagingStyle.shortcutIcon = launcherApps.getShortcutIcon(shortcutInfo)
shortcutInfo.label?.let { label -> messagingStyle.conversationTitle = label }
}
- if (NmSummarizationUiFlag.isEnabled && !TextUtils.isEmpty(entry.ranking.summarization)) {
- val icon = context.getDrawable(R.drawable.ic_notification_summarization)?.mutate()
- val imageSpan =
- icon?.let {
- it.setBounds(
- /* left= */ 0,
- /* top= */ 0,
- icon.getIntrinsicWidth(),
- icon.getIntrinsicHeight(),
- )
- ImageSpan(it, ImageSpan.ALIGN_CENTER)
- }
- val decoratedSummary =
- SpannableString("x " + entry.ranking.summarization).apply {
- setSpan(
- /* what = */ imageSpan,
- /* start = */ 0,
- /* end = */ 1,
- /* flags = */ Spanned.SPAN_INCLUSIVE_EXCLUSIVE,
- )
- entry.ranking.summarization?.let {
- setSpan(
- /* what = */ StyleSpan(Typeface.ITALIC),
- /* start = */ 2,
- /* end = */ it.length + 2,
- /* flags = */ Spanned.SPAN_EXCLUSIVE_INCLUSIVE,
+ if (NmSummarizationUiFlag.isEnabled) {
+ if (!TextUtils.isEmpty(entry.ranking.summarization)) {
+ val icon = context.getDrawable(R.drawable.ic_notification_summarization)?.mutate()
+ val imageSpan =
+ icon?.let {
+ it.setBounds(
+ /* left= */ 0,
+ /* top= */ 0,
+ icon.getIntrinsicWidth(),
+ icon.getIntrinsicHeight(),
)
+ ImageSpan(it, ImageSpan.ALIGN_CENTER)
}
- }
- entry.sbn.notification.extras.putCharSequence(
- EXTRA_SUMMARIZED_CONTENT,
- decoratedSummary,
- )
+ val decoratedSummary =
+ SpannableString("x " + entry.ranking.summarization).apply {
+ setSpan(
+ /* what = */ imageSpan,
+ /* start = */ 0,
+ /* end = */ 1,
+ /* flags = */ Spanned.SPAN_INCLUSIVE_EXCLUSIVE,
+ )
+ entry.ranking.summarization?.let {
+ setSpan(
+ /* what = */ StyleSpan(Typeface.ITALIC),
+ /* start = */ 2,
+ /* end = */ it.length + 2,
+ /* flags = */ Spanned.SPAN_EXCLUSIVE_INCLUSIVE,
+ )
+ }
+ }
+ entry.sbn.notification.extras.putCharSequence(
+ EXTRA_SUMMARIZED_CONTENT,
+ decoratedSummary,
+ )
+ } else {
+ entry.sbn.notification.extras.putCharSequence(EXTRA_SUMMARIZED_CONTENT, null)
+ }
}
messagingStyle.unreadMessageCount =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
index ba40010..e19ffb4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
@@ -17,4 +17,4 @@
yurilin@google.com
per-file MediaNotificationProcessor.java = ethibodeau@google.com
-per-file MagicActionBackgroundDrawable.kt = dupin@google.com
+per-file AnimatedActionBackgroundDrawable.kt = dupin@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimator.kt
index 68c13af..7b0d90c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimator.kt
@@ -24,14 +24,19 @@
import com.android.systemui.res.R
import com.android.systemui.statusbar.notification.PhysicsPropertyAnimator.Companion.createDefaultSpring
import com.android.systemui.statusbar.notification.stack.AnimationProperties
+import kotlin.math.sign
/**
* A physically animatable property of a view.
*
* @param tag the view tag to safe this property in
* @param property the property to animate.
+ * @param avoidDoubleOvershoot should this property avoid double overshoot when animated
*/
-data class PhysicsProperty(val tag: Int, val property: Property<View, Float>) {
+data class PhysicsProperty
+@JvmOverloads constructor(
+ val tag: Int, val property: Property<View, Float>, val avoidDoubleOvershoot: Boolean = true
+) {
val offsetProperty =
object : FloatProperty<View>(property.name) {
override fun get(view: View): Float {
@@ -61,6 +66,8 @@
var offset: Float = 0f,
var animator: SpringAnimation? = null,
var delayRunnable: Runnable? = null,
+ var startOffset: Float = 0f,
+ var doubleOvershootAvoidingListener: DynamicAnimation.OnAnimationUpdateListener? = null
)
/**
@@ -140,30 +147,67 @@
if (animator == null) {
animator = SpringAnimation(view, animatableProperty.offsetProperty)
propertyData.animator = animator
- animator.setSpring(createDefaultSpring())
val listener = properties?.getAnimationEndListener(animatableProperty.property)
if (listener != null) {
animator.addEndListener(listener)
- // We always notify things as started even if we have a delay
- properties.getAnimationStartListener(animatableProperty.property)?.accept(animator)
}
+ // We always notify things as started even if we have a delay
+ properties?.getAnimationStartListener(animatableProperty.property)?.accept(animator)
// remove the tag when the animation is finished
- animator.addEndListener { _, _, _, _ -> propertyData.animator = null }
+ animator.addEndListener { _, _, _, _ ->
+ propertyData.animator = null
+ propertyData.doubleOvershootAvoidingListener = null
+ // Let's make sure we never get stuck with an offset even when canceling
+ // We never actually cancel running animations but keep it around, so this only
+ // triggers if things really should end.
+ propertyData.offset = 0f
+ }
}
+ if (animatableProperty.avoidDoubleOvershoot
+ && propertyData.doubleOvershootAvoidingListener == null) {
+ propertyData.doubleOvershootAvoidingListener =
+ DynamicAnimation.OnAnimationUpdateListener { _, offset: Float, velocity: Float ->
+ val isOscillatingBackwards = velocity.sign == propertyData.startOffset.sign
+ val didAlreadyRemoveBounciness =
+ animator.spring.dampingRatio == SpringForce.DAMPING_RATIO_NO_BOUNCY
+ val isOvershooting = offset.sign != propertyData.startOffset.sign
+ if (isOvershooting && isOscillatingBackwards && !didAlreadyRemoveBounciness) {
+ // our offset is starting to decrease, let's remove all overshoot
+ animator.spring.setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)
+ } else if (!isOvershooting
+ && (didAlreadyRemoveBounciness || isOscillatingBackwards)) {
+ // we already did overshoot, let's skip to the end to avoid oscillations.
+ // Usually we shouldn't hit this as setting the damping ratio avoid overshoots
+ // but it may still happen if we see jank
+ animator.skipToEnd();
+ }
+ }
+ animator.addUpdateListener(propertyData.doubleOvershootAvoidingListener)
+ } else if (!animatableProperty.avoidDoubleOvershoot
+ && propertyData.doubleOvershootAvoidingListener != null) {
+ animator.removeUpdateListener(propertyData.doubleOvershootAvoidingListener)
+ }
+ // reset a new spring as it may have been modified
+ animator.setSpring(createDefaultSpring().setFinalPosition(0f))
// TODO(b/393581344): look at custom spring
endListener?.let { animator.addEndListener(it) }
- val newOffset = previousEndValue - newEndValue + propertyData.offset
- // Immedialely set the new offset that compensates for the immediate end value change
- propertyData.offset = newOffset
- property.set(view, newEndValue + newOffset)
+ val startOffset = previousEndValue - newEndValue + propertyData.offset
+ // Immediately set the new offset that compensates for the immediate end value change
+ propertyData.offset = startOffset
+ propertyData.startOffset = startOffset
+ property.set(view, newEndValue + startOffset)
// cancel previous starters still pending
view.removeCallbacks(propertyData.delayRunnable)
- animator.setStartValue(newOffset)
+ animator.setStartValue(startOffset)
val startRunnable = Runnable {
animator.animateToFinalPosition(0f)
propertyData.delayRunnable = null
+ // When setting a new spring on a running animation it doesn't properly set the finish
+ // conditions and will never actually end them only calling start explicitly does that,
+ // so let's start them again!
+ animator.start()
}
if (properties != null && properties.delay > 0 && !animator.isRunning) {
propertyData.delayRunnable = startRunnable
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java
index 8fc6cbe..e69de29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2025 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection;
-
-import static android.app.NotificationChannel.NEWS_ID;
-import static android.app.NotificationChannel.PROMOTIONS_ID;
-import static android.app.NotificationChannel.RECS_ID;
-import static android.app.NotificationChannel.SOCIAL_MEDIA_ID;
-
-import android.app.Notification;
-import android.content.Context;
-import android.os.Build;
-import android.service.notification.StatusBarNotification;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-
-import com.android.systemui.statusbar.notification.icon.IconPack;
-import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import kotlinx.coroutines.flow.MutableStateFlow;
-import kotlinx.coroutines.flow.StateFlow;
-import kotlinx.coroutines.flow.StateFlowKt;
-
-/**
- * Class to represent notifications bundled by classification.
- */
-public class BundleEntry extends PipelineEntry {
-
- // TODO(b/394483200): move NotificationEntry's implementation to PipelineEntry?
- private final MutableStateFlow<Boolean> mSensitive = StateFlowKt.MutableStateFlow(false);
-
- // TODO (b/389839319): implement the row
- private ExpandableNotificationRow mRow;
-
- private final List<ListEntry> mChildren = new ArrayList<>();
-
- private final List<ListEntry> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
-
- public BundleEntry(String key) {
- super(key);
- }
-
- void addChild(ListEntry child) {
- mChildren.add(child);
- }
-
- @NonNull
- public List<ListEntry> getChildren() {
- return mUnmodifiableChildren;
- }
-
- void clearChildren() {
- mChildren.clear();
- }
-
- /**
- * @return Null because bundles do not have an associated NotificationEntry.
- */
- @Nullable
- @Override
- public NotificationEntry getRepresentativeEntry() {
- return null;
- }
-
- @Nullable
- @Override
- public PipelineEntry getParent() {
- return null;
- }
-
- @Override
- public boolean wasAttachedInPreviousPass() {
- return false;
- }
-
- @Nullable
- public ExpandableNotificationRow getRow() {
- return mRow;
- }
-
- public static final List<BundleEntry> ROOT_BUNDLES = List.of(
- new BundleEntry(PROMOTIONS_ID),
- new BundleEntry(SOCIAL_MEDIA_ID),
- new BundleEntry(NEWS_ID),
- new BundleEntry(RECS_ID));
-
- public MutableStateFlow<Boolean> isSensitive() {
- return mSensitive;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.kt
new file mode 100644
index 0000000..0da76c3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.collection
+
+import android.app.NotificationChannel
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import java.util.Collections
+import kotlinx.coroutines.flow.MutableStateFlow
+
+/** Class to represent notifications bundled by classification. */
+class BundleEntry(key: String) : PipelineEntry(key) {
+ // TODO(b/394483200): move NotificationEntry's implementation to PipelineEntry?
+ val isSensitive: MutableStateFlow<Boolean> = MutableStateFlow(false)
+
+ // TODO (b/389839319): implement the row
+ val row: ExpandableNotificationRow? = null
+
+ private val _children: MutableList<ListEntry> = ArrayList()
+ val children: List<ListEntry> = Collections.unmodifiableList(_children)
+
+ fun addChild(child: ListEntry) {
+ _children.add(child)
+ }
+
+ fun clearChildren() {
+ _children.clear()
+ }
+
+ /** @return Null because bundles do not have an associated NotificationEntry. */
+ override fun getRepresentativeEntry(): NotificationEntry? {
+ return null
+ }
+
+ override fun getParent(): PipelineEntry? {
+ return null
+ }
+
+ override fun wasAttachedInPreviousPass(): Boolean {
+ return false
+ }
+
+ companion object {
+ val ROOT_BUNDLES: List<BundleEntry> =
+ listOf(
+ BundleEntry(NotificationChannel.PROMOTIONS_ID),
+ BundleEntry(NotificationChannel.SOCIAL_MEDIA_ID),
+ BundleEntry(NotificationChannel.NEWS_ID),
+ BundleEntry(NotificationChannel.RECS_ID),
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt
index be17ae56c..6a3f8f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt
@@ -19,14 +19,20 @@
import android.app.Notification
import android.content.Context
import android.os.Build
+import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import android.util.Log
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
import com.android.systemui.statusbar.notification.icon.IconPack
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import kotlinx.coroutines.flow.StateFlow
-class BundleEntryAdapter(val entry: BundleEntry) : EntryAdapter {
+class BundleEntryAdapter(
+ private val highPriorityProvider: HighPriorityProvider,
+ val entry: BundleEntry,
+) : EntryAdapter {
/** TODO (b/394483200): convert to PipelineEntry.ROOT_ENTRY when pipeline is migrated? */
override fun getParent(): GroupEntry {
return GroupEntry.ROOT_ENTRY
@@ -94,6 +100,41 @@
return null
}
+ override fun getRanking(): NotificationListenerService.Ranking? {
+ return null
+ }
+
+ override fun endLifetimeExtension(
+ callback: NotifLifetimeExtender.OnEndLifetimeExtensionCallback?,
+ extender: NotifLifetimeExtender,
+ ) {
+ Log.wtf(TAG, "endLifetimeExtension() called")
+ }
+
+ override fun onImportanceChanged() {
+ Log.wtf(TAG, "onImportanceChanged() called")
+ }
+
+ override fun markForUserTriggeredMovement() {
+ Log.wtf(TAG, "markForUserTriggeredMovement() called")
+ }
+
+ override fun isMarkedForUserTriggeredMovement(): Boolean {
+ return false
+ }
+
+ override fun isHighPriority(): Boolean {
+ return highPriorityProvider.isHighPriority(entry)
+ }
+
+ override fun setInlineControlsShown(currentlyVisible: Boolean) {
+ // nothing to do, yet
+ }
+
+ override fun isBlockable(): Boolean {
+ return false
+ }
+
override fun canDragAndDrop(): Boolean {
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java
index 3757ebf..16d9c78 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java
@@ -17,11 +17,13 @@
package com.android.systemui.statusbar.notification.collection;
import android.content.Context;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.statusbar.notification.icon.IconPack;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -123,6 +125,40 @@
@Nullable
StatusBarNotification getSbn();
+ /**
+ * Returns the ranking that backs this row, if present
+ */
+ @Nullable
+ NotificationListenerService.Ranking getRanking();
+
+ void endLifetimeExtension(
+ @Nullable NotifLifetimeExtender.OnEndLifetimeExtensionCallback callback,
+ @NonNull NotifLifetimeExtender extender);
+
+
+ void onImportanceChanged();
+
+ /**
+ * Use when a change has been made to the underlying object that will both rerank the object
+ * in the shade and change something about its appearance to delay the appearance change until
+ * the ranking reordering is likely to have settled.
+ */
+ void markForUserTriggeredMovement();
+
+ /**
+ * Determines whether a row is considered 'high priority'.
+ *
+ * Notifications that are high priority are visible on the lock screen/status bar and in the top
+ * section in the shade.
+ */
+ boolean isHighPriority();
+
+ boolean isMarkedForUserTriggeredMovement();
+
+ void setInlineControlsShown(boolean currentlyVisible);
+
+ boolean isBlockable();
+
boolean canDragAndDrop();
boolean isBubble();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt
index a516986..2fce19c2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt
@@ -19,6 +19,8 @@
import com.android.internal.logging.MetricsLogger
import com.android.systemui.statusbar.notification.NotificationActivityStarter
import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.row.NotificationActionClickManager
import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider
@@ -34,6 +36,8 @@
private val iconStyleProvider: NotificationIconStyleProvider,
private val visualStabilityCoordinator: VisualStabilityCoordinator,
private val notificationActionClickManager: NotificationActionClickManager,
+ private val highPriorityProvider: HighPriorityProvider,
+ private val headsUpManager: HeadsUpManager,
) : EntryAdapterFactory {
override fun create(entry: PipelineEntry): EntryAdapter {
return if (entry is NotificationEntry) {
@@ -44,10 +48,12 @@
iconStyleProvider,
visualStabilityCoordinator,
notificationActionClickManager,
+ highPriorityProvider,
+ headsUpManager,
entry,
)
} else {
- BundleEntryAdapter((entry as BundleEntry))
+ BundleEntryAdapter(highPriorityProvider, (entry as BundleEntry))
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index b5ab092..c94289c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -1030,7 +1030,7 @@
}
/**
- * Mark this entry for movement triggered by a user action (ex: changing the priorirty of a
+ * Mark this entry for movement triggered by a user action (ex: changing the priority of a
* conversation). This can then be used for custom animations.
*/
public void markForUserTriggeredMovement(boolean marked) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt
index a23c5a3..339a999 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt
@@ -17,10 +17,15 @@
package com.android.systemui.statusbar.notification.collection
import android.content.Context
+import android.os.SystemClock
+import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import com.android.internal.logging.MetricsLogger
import com.android.systemui.statusbar.notification.NotificationActivityStarter
import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
import com.android.systemui.statusbar.notification.icon.IconPack
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
@@ -35,6 +40,8 @@
private val iconStyleProvider: NotificationIconStyleProvider,
private val visualStabilityCoordinator: VisualStabilityCoordinator,
private val notificationActionClickManager: NotificationActionClickManager,
+ private val highPriorityProvider: HighPriorityProvider,
+ private val headsUpManager: HeadsUpManager,
private val entry: NotificationEntry,
) : EntryAdapter {
@@ -110,6 +117,41 @@
return entry.sbn
}
+ override fun getRanking(): NotificationListenerService.Ranking? {
+ return entry.ranking
+ }
+
+ override fun endLifetimeExtension(
+ callback: NotifLifetimeExtender.OnEndLifetimeExtensionCallback?,
+ extender: NotifLifetimeExtender,
+ ) {
+ callback?.onEndLifetimeExtension(extender, entry)
+ }
+
+ override fun onImportanceChanged() {
+ visualStabilityCoordinator.temporarilyAllowSectionChanges(entry, SystemClock.uptimeMillis())
+ }
+
+ override fun markForUserTriggeredMovement() {
+ entry.markForUserTriggeredMovement(true)
+ }
+
+ override fun isMarkedForUserTriggeredMovement(): Boolean {
+ return entry.isMarkedForUserTriggeredMovement
+ }
+
+ override fun isHighPriority(): Boolean {
+ return highPriorityProvider.isHighPriority(entry)
+ }
+
+ override fun setInlineControlsShown(currentlyVisible: Boolean) {
+ headsUpManager.setGutsShown(entry, currentlyVisible)
+ }
+
+ override fun isBlockable(): Boolean {
+ return entry.isBlockable
+ }
+
override fun canDragAndDrop(): Boolean {
val canBubble: Boolean = entry.canBubble()
val notif = entry.sbn.notification
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt
index 9045aac..754f891 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt
@@ -18,9 +18,10 @@
import android.util.ArraySet
import com.android.systemui.Dumpable
import com.android.systemui.dump.DumpManager
-import com.android.systemui.statusbar.notification.collection.PipelineEntry
+import com.android.systemui.statusbar.notification.collection.EntryAdapter
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.PipelineEntry
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback
@@ -28,6 +29,7 @@
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager
import com.android.systemui.statusbar.notification.row.NotificationGuts
import com.android.systemui.statusbar.notification.row.NotificationGutsManager
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
import com.android.systemui.util.asIndenting
import com.android.systemui.util.printCollection
import com.android.systemui.util.println
@@ -38,23 +40,25 @@
private const val TAG = "GutsCoordinator"
/**
- * Coordinates the guts displayed by the [NotificationGutsManager] with the pipeline.
- * Specifically, this just adds the lifetime extension necessary to keep guts from disappearing.
+ * Coordinates the guts displayed by the [NotificationGutsManager] with the pipeline. Specifically,
+ * this just adds the lifetime extension necessary to keep guts from disappearing.
*/
@CoordinatorScope
-class GutsCoordinator @Inject constructor(
+class GutsCoordinator
+@Inject
+constructor(
private val notifGutsViewManager: NotifGutsViewManager,
private val logger: GutsCoordinatorLogger,
- dumpManager: DumpManager
+ dumpManager: DumpManager,
) : Coordinator, Dumpable {
- /** Keys of any Notifications for which we've been told the guts are open */
+ /** Keys of any Notifications for which we've been told the guts are open */
private val notifsWithOpenGuts = ArraySet<String>()
- /** Keys of any Notifications we've extended the lifetime for, based on guts */
+ /** Keys of any Notifications we've extended the lifetime for, based on guts */
private val notifsExtendingLifetime = ArraySet<String>()
- /** Callback for ending lifetime extension */
+ /** Callback for ending lifetime extension */
private var onEndLifetimeExtensionCallback: OnEndLifetimeExtensionCallback? = null
init {
@@ -66,55 +70,77 @@
pipeline.addNotificationLifetimeExtender(mLifetimeExtender)
}
- override fun dump(pw: PrintWriter, args: Array<String>) = pw.asIndenting().run {
- withIncreasedIndent {
- printCollection("notifsWithOpenGuts", notifsWithOpenGuts)
- printCollection("notifsExtendingLifetime", notifsExtendingLifetime)
- println("onEndLifetimeExtensionCallback", onEndLifetimeExtensionCallback)
- }
- }
-
- private val mLifetimeExtender: NotifLifetimeExtender = object : NotifLifetimeExtender {
- override fun getName(): String {
- return TAG
- }
-
- override fun setCallback(callback: OnEndLifetimeExtensionCallback) {
- onEndLifetimeExtensionCallback = callback
- }
-
- override fun maybeExtendLifetime(entry: NotificationEntry, reason: Int): Boolean {
- val isShowingGuts = isCurrentlyShowingGuts(entry)
- if (isShowingGuts) {
- notifsExtendingLifetime.add(entry.key)
+ override fun dump(pw: PrintWriter, args: Array<String>) =
+ pw.asIndenting().run {
+ withIncreasedIndent {
+ printCollection("notifsWithOpenGuts", notifsWithOpenGuts)
+ printCollection("notifsExtendingLifetime", notifsExtendingLifetime)
+ println("onEndLifetimeExtensionCallback", onEndLifetimeExtensionCallback)
}
- return isShowingGuts
}
- override fun cancelLifetimeExtension(entry: NotificationEntry) {
- notifsExtendingLifetime.remove(entry.key)
- }
- }
+ private val mLifetimeExtender: NotifLifetimeExtender =
+ object : NotifLifetimeExtender {
+ override fun getName(): String {
+ return TAG
+ }
- private val mGutsListener: NotifGutsViewListener = object : NotifGutsViewListener {
- override fun onGutsOpen(entry: NotificationEntry, guts: NotificationGuts) {
- logger.logGutsOpened(entry.key, guts)
- if (guts.isLeavebehind) {
- // leave-behind guts should not extend the lifetime of the notification
+ override fun setCallback(callback: OnEndLifetimeExtensionCallback) {
+ onEndLifetimeExtensionCallback = callback
+ }
+
+ override fun maybeExtendLifetime(entry: NotificationEntry, reason: Int): Boolean {
+ val isShowingGuts = isCurrentlyShowingGuts(entry)
+ if (isShowingGuts) {
+ notifsExtendingLifetime.add(entry.key)
+ }
+ return isShowingGuts
+ }
+
+ override fun cancelLifetimeExtension(entry: NotificationEntry) {
+ notifsExtendingLifetime.remove(entry.key)
+ }
+ }
+
+ private val mGutsListener: NotifGutsViewListener =
+ object : NotifGutsViewListener {
+ override fun onGutsOpen(entry: NotificationEntry, guts: NotificationGuts) {
+ NotificationBundleUi.assertInLegacyMode()
+ logger.logGutsOpened(entry.key, guts)
+ if (guts.isLeavebehind) {
+ // leave-behind guts should not extend the lifetime of the notification
+ closeGutsAndEndLifetimeExtension(entry)
+ } else {
+ notifsWithOpenGuts.add(entry.key)
+ }
+ }
+
+ override fun onGutsClose(entry: NotificationEntry) {
+ NotificationBundleUi.assertInLegacyMode()
+ logger.logGutsClosed(entry.key)
closeGutsAndEndLifetimeExtension(entry)
- } else {
- notifsWithOpenGuts.add(entry.key)
+ }
+
+ override fun onGutsOpen(entryAdapter: EntryAdapter, guts: NotificationGuts) {
+ NotificationBundleUi.isUnexpectedlyInLegacyMode()
+ logger.logGutsOpened(entryAdapter.key, guts)
+ if (guts.isLeavebehind) {
+ // leave-behind guts should not extend the lifetime of the notification
+ closeGutsAndEndLifetimeExtension(entryAdapter)
+ } else {
+ notifsWithOpenGuts.add(entryAdapter.key)
+ }
+ }
+
+ override fun onGutsClose(entryAdapter: EntryAdapter) {
+ NotificationBundleUi.isUnexpectedlyInLegacyMode()
+ logger.logGutsClosed(entryAdapter.key)
+ closeGutsAndEndLifetimeExtension(entryAdapter)
}
}
- override fun onGutsClose(entry: NotificationEntry) {
- logger.logGutsClosed(entry.key)
- closeGutsAndEndLifetimeExtension(entry)
- }
- }
-
private fun isCurrentlyShowingGuts(entry: PipelineEntry) =
- notifsWithOpenGuts.contains(entry.key)
+ notifsWithOpenGuts.contains(entry.key)
private fun closeGutsAndEndLifetimeExtension(entry: NotificationEntry) {
notifsWithOpenGuts.remove(entry.key)
@@ -122,4 +148,11 @@
onEndLifetimeExtensionCallback?.onEndLifetimeExtension(mLifetimeExtender, entry)
}
}
+
+ private fun closeGutsAndEndLifetimeExtension(entryAdapter: EntryAdapter) {
+ notifsWithOpenGuts.remove(entryAdapter.key)
+ if (notifsExtendingLifetime.remove(entryAdapter.key)) {
+ entryAdapter.endLifetimeExtension(onEndLifetimeExtensionCallback, mLifetimeExtender)
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
index 26b86f9..a40a228 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
@@ -15,18 +15,19 @@
*/
package com.android.systemui.statusbar.notification.collection.coordinator
-import com.android.systemui.Flags.notificationSkipSilentUpdates
-
import android.app.Notification
import android.app.Notification.GROUP_ALERT_SUMMARY
+import android.app.NotificationChannel.SYSTEM_RESERVED_IDS
import android.util.ArrayMap
import android.util.ArraySet
import com.android.internal.annotations.VisibleForTesting
+import com.android.systemui.Flags.notificationSkipSilentUpdates
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.NotificationRemoteInputManager
import com.android.systemui.statusbar.chips.notification.domain.interactor.StatusBarNotificationChipsInteractor
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
+import com.android.systemui.statusbar.chips.uievents.StatusBarChipsUiEventLogger
import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.BundleEntry
import com.android.systemui.statusbar.notification.collection.GroupEntry
@@ -48,7 +49,10 @@
import com.android.systemui.statusbar.notification.headsup.OnHeadsUpChangedListener
import com.android.systemui.statusbar.notification.headsup.PinnedStatus
import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder
+import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionLogger
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider
+import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProviderImpl.DecisionImpl
+import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType
import com.android.systemui.statusbar.notification.logKey
import com.android.systemui.statusbar.notification.row.NotificationActionClickManager
import com.android.systemui.statusbar.notification.shared.GroupHunAnimationFix
@@ -81,6 +85,7 @@
constructor(
@Application private val applicationScope: CoroutineScope,
private val mLogger: HeadsUpCoordinatorLogger,
+ private val mInterruptLogger: VisualInterruptionDecisionLogger,
private val mSystemClock: SystemClock,
private val notifCollection: NotifCollection,
private val mHeadsUpManager: HeadsUpManager,
@@ -91,6 +96,7 @@
private val mLaunchFullScreenIntentProvider: LaunchFullScreenIntentProvider,
private val mFlags: NotifPipelineFlags,
private val statusBarNotificationChipsInteractor: StatusBarNotificationChipsInteractor,
+ private val statusBarChipsUiEventLogger: StatusBarChipsUiEventLogger,
@IncomingHeader private val mIncomingHeaderController: NodeController,
@Main private val mExecutor: DelayableExecutor,
) : Coordinator {
@@ -146,6 +152,14 @@
// not just any notification.
val isCurrentlyHeadsUp = mHeadsUpManager.isHeadsUpEntry(entry.key)
+
+ if (isCurrentlyHeadsUp) {
+ // If the chip's notif is currently showing as heads up, then we'll stop showing it.
+ statusBarChipsUiEventLogger.logChipTapToHide(entry.sbn.instanceId)
+ } else {
+ statusBarChipsUiEventLogger.logChipTapToShow(entry.sbn.instanceId)
+ }
+
val posted =
PostedEntry(
entry,
@@ -281,6 +295,19 @@
return@forEach
}
+ if (isDisqualifiedChild(childToReceiveParentHeadsUp)) {
+ mInterruptLogger.logDecision(
+ VisualInterruptionType.PEEK.name,
+ childToReceiveParentHeadsUp,
+ DecisionImpl(shouldInterrupt = false,
+ logReason = "disqualified-transfer-target"))
+ postedEntries.forEach {
+ it.shouldHeadsUpEver = false
+ it.shouldHeadsUpAgain = false
+ handlePostedEntry(it, hunMutator, scenario = "disqualified-transfer-target")
+ }
+ return@forEach
+ }
// At this point we just need to initiate the transfer
val summaryUpdate = mPostedEntries[logicalSummary.key]
@@ -383,6 +410,14 @@
cleanUpEntryTimes()
}
+ private fun isDisqualifiedChild(entry: NotificationEntry): Boolean {
+ if (entry.channel == null || entry.channel.id == null) {
+ return false
+ }
+ return entry.channel.id in SYSTEM_RESERVED_IDS
+ }
+
+
/**
* Find the posted child with the newest when, and return it if it is isolated and has
* GROUP_ALERT_SUMMARY so that it can be heads uped.
@@ -478,8 +513,10 @@
// instead of waiting for any sort of minimum timeout.
// TODO(b/401068530) Ensure that status bar chip HUNs are not
// removed for silent update
- hunMutator.removeNotification(posted.key,
- /* releaseImmediately= */ true)
+ hunMutator.removeNotification(
+ posted.key,
+ /* releaseImmediately= */ true,
+ )
} else {
// Do NOT remove HUN for non-user update.
// Let the HUN show for its remaining duration.
@@ -596,8 +633,11 @@
// TODO(b/403703828) Move canceling to OnBeforeFinalizeFilter, since we are not
// removing from HeadsUpManager and don't need to deal with re-entrant behavior
// between HeadsUpCoordinator, HeadsUpManager, and VisualStabilityManager.
- if (posted?.shouldHeadsUpEver == false
- && !posted.isHeadsUpEntry && posted.isBinding) {
+ if (
+ posted?.shouldHeadsUpEver == false &&
+ !posted.isHeadsUpEntry &&
+ posted.isBinding
+ ) {
// Don't let the bind finish
cancelHeadsUpBind(posted.entry)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
index a987c54..341cc09 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
@@ -20,9 +20,9 @@
import com.android.systemui.res.R
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.notification.AssistantFeedbackController
-import com.android.systemui.statusbar.notification.collection.PipelineEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.PipelineEntry
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
import com.android.systemui.statusbar.notification.collection.render.NotifRowController
@@ -79,6 +79,6 @@
(mAutoExpandFirstNotification && entry == entryToExpand)
)
// Show/hide the feedback icon
- controller.setFeedbackIcon(mAssistantFeedbackController.getFeedbackIcon(entry))
+ controller.setFeedbackIcon(mAssistantFeedbackController.getFeedbackIcon(entry.ranking))
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java
index 03b4076..ca3d2e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java
@@ -35,6 +35,7 @@
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import javax.inject.Inject;
@@ -83,6 +84,7 @@
@Override
public void onImportanceChanged(NotificationEntry entry) {
+ NotificationBundleUi.assertInLegacyMode();
mVisualStabilityCoordinator.temporarilyAllowSectionChanges(
entry,
UseElapsedRealtimeForCreationTime.getCurrentTime());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt
index 129f6b1..9e49083 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt
@@ -15,16 +15,21 @@
*/
package com.android.systemui.statusbar.notification.collection.render
+import com.android.systemui.statusbar.notification.collection.EntryAdapter
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.row.NotificationGuts
-/**
- * Interface for listening to guts open and close events.
- */
+/** Interface for listening to guts open and close events. */
interface NotifGutsViewListener {
/** A notification's guts are being opened */
fun onGutsOpen(entry: NotificationEntry, guts: NotificationGuts)
/** A notification's guts are being closed */
fun onGutsClose(entry: NotificationEntry)
+
+ /** A notification's guts are being opened */
+ fun onGutsOpen(entryAdapter: EntryAdapter, guts: NotificationGuts)
+
+ /** A notification's guts are being closed */
+ fun onGutsClose(entryAdapter: EntryAdapter)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
index e7cc342..9f42a1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
@@ -27,6 +27,7 @@
import android.service.notification.StatusBarNotification
import android.util.ArrayMap
import com.android.app.tracing.traceSection
+import com.android.internal.logging.InstanceId
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.notification.collection.GroupEntry
@@ -167,7 +168,7 @@
packageName = sbn.packageName,
appName = sbn.notification.loadHeaderAppName(context),
contentIntent = sbn.notification.contentIntent,
- instanceId = sbn.instanceId?.id,
+ instanceId = sbn.instanceId,
isGroupSummary = sbn.notification.isGroupSummary,
bucket = bucket,
callType = sbn.toCallType(),
@@ -196,7 +197,7 @@
packageName: String,
appName: String,
contentIntent: PendingIntent?,
- instanceId: Int?,
+ instanceId: InstanceId?,
isGroupSummary: Boolean,
bucket: Int,
callType: CallType,
@@ -278,7 +279,7 @@
packageName: String,
appName: String,
contentIntent: PendingIntent?,
- instanceId: Int?,
+ instanceId: InstanceId?,
isGroupSummary: Boolean,
bucket: Int,
callType: CallType,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
index 8240a0a..9f67e50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
@@ -87,7 +87,7 @@
val eventLogData: EventLogData?
}
- private class DecisionImpl(
+ class DecisionImpl(
override val shouldInterrupt: Boolean,
override val logReason: String,
) : Decision
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
index 1755123..bd06a37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
@@ -33,6 +33,7 @@
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.nano.Notifications;
import com.android.systemui.statusbar.notification.stack.PriorityBucket;
@@ -64,6 +65,8 @@
*/
void logNotificationDrag(NotificationEntry draggedNotification);
+ void logNotificationDrag(EntryAdapter draggedNotification);
+
enum NotificationPanelEvent implements UiEventLogger.UiEventEnum {
@UiEvent(doc = "Notification panel shown from status bar.")
NOTIFICATION_PANEL_OPEN_STATUS_BAR(200),
@@ -123,6 +126,42 @@
}
/**
+ * Composes a NotificationsList proto from the list of visible notifications.
+ * @param visibleNotifications as provided by NotificationEntryManager.getVisibleNotifications()
+ * @return NotificationList proto suitable for SysUiStatsLog.write(NOTIFICATION_PANEL_REPORTED)
+ */
+ static Notifications.NotificationList adapterToNotificationProto(
+ @Nullable List<EntryAdapter> visibleNotifications) {
+ Notifications.NotificationList notificationList = new Notifications.NotificationList();
+ if (visibleNotifications == null) {
+ return notificationList;
+ }
+ final Notifications.Notification[] proto_array =
+ new Notifications.Notification[visibleNotifications.size()];
+ int i = 0;
+ for (EntryAdapter ne : visibleNotifications) {
+ final StatusBarNotification n = ne.getSbn();
+ if (n != null) {
+ final Notifications.Notification proto = new Notifications.Notification();
+ proto.uid = n.getUid();
+ proto.packageName = n.getPackageName();
+ if (n.getInstanceId() != null) {
+ proto.instanceId = n.getInstanceId().getId();
+ }
+ // TODO set np.groupInstanceId
+ if (n.getNotification() != null) {
+ proto.isGroupSummary = n.getNotification().isGroupSummary();
+ }
+ proto.section = toNotificationSection(ne.getSectionBucket());
+ proto_array[i] = proto;
+ }
+ ++i;
+ }
+ notificationList.notifications = proto_array;
+ return notificationList;
+ }
+
+ /**
* Maps PriorityBucket enum to Notification.SECTION constant. The two lists should generally
* use matching names, but the values may differ, because PriorityBucket order changes from
* time to time, while logs need to have stable meanings.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java
index d7f7b76..7eb74a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java
@@ -19,6 +19,7 @@
import static com.android.systemui.statusbar.notification.logging.NotificationPanelLogger.NotificationPanelEvent.NOTIFICATION_DRAG;
import com.android.systemui.shared.system.SysUiStatsLog;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.nano.Notifications;
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor;
@@ -62,4 +63,15 @@
/* num_notifications = */ proto.notifications.length,
/* notifications = */ MessageNano.toByteArray(proto));
}
+
+ @Override
+ public void logNotificationDrag(EntryAdapter draggedNotification) {
+ final Notifications.NotificationList proto =
+ NotificationPanelLogger.adapterToNotificationProto(
+ Collections.singletonList(draggedNotification));
+ SysUiStatsLog.write(SysUiStatsLog.NOTIFICATION_PANEL_REPORTED,
+ /* event_id = */ NOTIFICATION_DRAG.getId(),
+ /* num_notifications = */ proto.notifications.length,
+ /* notifications = */ MessageNano.toByteArray(proto));
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt
index 777392d..9282e16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt
@@ -16,13 +16,13 @@
package com.android.systemui.statusbar.notification.promoted
-import android.app.Flags
import android.app.Flags.notificationsRedesignTemplates
import android.app.Notification
import android.content.Context
import android.graphics.PorterDuff
import android.util.Log
import android.view.LayoutInflater
+import android.view.NotificationTopLineView
import android.view.View
import android.view.View.GONE
import android.view.View.MeasureSpec.AT_MOST
@@ -202,7 +202,7 @@
private val PromotedNotificationContentModel.layoutResource: Int?
get() {
- return if (Flags.notificationsRedesignTemplates()) {
+ return if (notificationsRedesignTemplates()) {
when (style) {
Style.Base -> R.layout.notification_2025_template_expanded_base
Style.BigPicture -> R.layout.notification_2025_template_expanded_big_picture
@@ -226,7 +226,7 @@
private class AODPromotedNotificationViewUpdater(root: View) {
private val alertedIcon: ImageView? = root.findViewById(R.id.alerted_icon)
private val alternateExpandTarget: View? = root.findViewById(R.id.alternate_expand_target)
- private val appNameDivider: View? = root.findViewById(R.id.app_name_divider)
+ private val appNameDivider: TextView? = root.findViewById(R.id.app_name_divider)
private val appNameText: TextView? = root.findViewById(R.id.app_name_text)
private val bigPicture: BigPictureNotificationImageView? = root.findViewById(R.id.big_picture)
private val bigText: ImageFloatingTextView? = root.findViewById(R.id.big_text)
@@ -241,9 +241,9 @@
)
private val expandButton: NotificationExpandButton? = root.findViewById(R.id.expand_button)
private val headerText: TextView? = root.findViewById(R.id.header_text)
- private val headerTextDivider: View? = root.findViewById(R.id.header_text_divider)
+ private val headerTextDivider: TextView? = root.findViewById(R.id.header_text_divider)
private val headerTextSecondary: TextView? = root.findViewById(R.id.header_text_secondary)
- private val headerTextSecondaryDivider: View? =
+ private val headerTextSecondaryDivider: TextView? =
root.findViewById(R.id.header_text_secondary_divider)
private val icon: NotificationRowIconView? = root.findViewById(R.id.icon)
private val leftIcon: ImageView? = root.findViewById(R.id.left_icon)
@@ -256,9 +256,10 @@
private val rightIcon: ImageView? = root.findViewById(R.id.right_icon)
private val text: ImageFloatingTextView? = root.findViewById(R.id.text)
private val time: DateTimeView? = root.findViewById(R.id.time)
- private val timeDivider: View? = root.findViewById(R.id.time_divider)
+ private val timeDivider: TextView? = root.findViewById(R.id.time_divider)
private val title: TextView? = root.findViewById(R.id.title)
- private val verificationDivider: View? = root.findViewById(R.id.verification_divider)
+ private val topLine: NotificationTopLineView? = root.findViewById(R.id.notification_top_line)
+ private val verificationDivider: TextView? = root.findViewById(R.id.verification_divider)
private val verificationIcon: ImageView? = root.findViewById(R.id.verification_icon)
private val verificationText: TextView? = root.findViewById(R.id.verification_text)
@@ -266,6 +267,29 @@
private var oldProgressBar: ProgressBar? = null
private val newProgressBar = root.findViewById<View>(R.id.progress) as? NotificationProgressBar
+ private val largeIconSizePx: Int =
+ root.context.resources.getDimensionPixelSize(R.dimen.notification_right_icon_size)
+
+ private val endMarginPx: Int =
+ if (notificationsRedesignTemplates()) {
+ root.context.resources.getDimensionPixelSize(R.dimen.notification_2025_margin)
+ } else {
+ root.context.resources.getDimensionPixelSize(
+ systemuiR.dimen.notification_shade_content_margin_horizontal
+ )
+ }
+
+ private val imageEndMarginPx: Int
+ get() = largeIconSizePx + 2 * endMarginPx
+
+ private val PromotedNotificationContentModel.imageEndMarginPxIfHasLargeIcon: Int
+ get() =
+ if (!skeletonLargeIcon.isNullOrEmpty()) {
+ imageEndMarginPx
+ } else {
+ 0
+ }
+
init {
// Hide views that are never visible in the skeleton promoted notification.
alternateExpandTarget?.visibility = GONE
@@ -283,7 +307,20 @@
?.mutate()
?.setColorFilter(SecondaryText.colorInt, PorterDuff.Mode.SRC_IN)
- if (Flags.notificationsRedesignTemplates()) {
+ (rightIcon?.layoutParams as? MarginLayoutParams)?.let {
+ it.marginEnd = endMarginPx
+ rightIcon.layoutParams = it
+ }
+ bigText?.setImageEndMargin(largeIconSizePx + endMarginPx)
+ text?.setImageEndMargin(largeIconSizePx + endMarginPx)
+
+ setTextViewColor(appNameDivider, SecondaryText)
+ setTextViewColor(headerTextDivider, SecondaryText)
+ setTextViewColor(headerTextSecondaryDivider, SecondaryText)
+ setTextViewColor(timeDivider, SecondaryText)
+ setTextViewColor(verificationDivider, SecondaryText)
+
+ if (notificationsRedesignTemplates()) {
(mainColumn?.layoutParams as? MarginLayoutParams)?.let { mainColumnMargins ->
mainColumnMargins.topMargin =
Notification.Builder.getContentMarginTop(
@@ -309,19 +346,15 @@
private fun updateBase(
content: PromotedNotificationContentModel,
- textView: ImageFloatingTextView? = null,
- showOldProgress: Boolean = true,
+ textView: ImageFloatingTextView? = text,
) {
- updateHeader(content, hideTitle = true)
+ updateHeader(content)
updateTitle(title, content)
- updateText(textView ?: text, content)
+ updateText(textView, content)
updateSmallIcon(icon, content)
updateImageView(rightIcon, content.skeletonLargeIcon)
-
- if (showOldProgress) {
- updateOldProgressBar(content)
- }
+ updateOldProgressBar(content)
}
private fun updateBigPictureStyle(content: PromotedNotificationContentModel) {
@@ -339,14 +372,15 @@
}
private fun updateProgressStyle(content: PromotedNotificationContentModel) {
- updateBase(content, showOldProgress = false)
+ updateBase(content)
updateNewProgressBar(content)
}
private fun updateOldProgressBar(content: PromotedNotificationContentModel) {
if (
- content.oldProgress == null ||
+ content.style == Style.Progress ||
+ content.oldProgress == null ||
content.oldProgress.max == 0 ||
content.oldProgress.isIndeterminate
) {
@@ -375,27 +409,24 @@
}
}
- private fun updateHeader(
- content: PromotedNotificationContentModel,
- hideTitle: Boolean = false,
- ) {
+ private fun updateHeader(content: PromotedNotificationContentModel) {
updateAppName(content)
updateTextView(headerTextSecondary, content.subText)
- if (!hideTitle) {
- updateTitle(headerText, content)
- }
+ // Not calling updateTitle(headerText, content) because the title is always a separate
+ // element in the expanded layout used for AOD RONs.
updateTimeAndChronometer(content)
- updateHeaderDividers(content, hideTitle = hideTitle)
+ updateHeaderDividers(content)
+
+ updateTopLine(content)
}
- private fun updateHeaderDividers(
- content: PromotedNotificationContentModel,
- hideTitle: Boolean = false,
- ) {
- val hasAppName = content.appName != null && content.appName.isNotEmpty()
- val hasSubText = content.subText != null && content.subText.isNotEmpty()
- val hasHeader = content.title != null && content.title.isNotEmpty() && !hideTitle
+ private fun updateHeaderDividers(content: PromotedNotificationContentModel) {
+ val hasAppName = content.appName != null
+ val hasSubText = content.subText != null
+ // Not setting hasHeader = content.title because the title is always a separate element in
+ // the expanded layout used for AOD RONs.
+ val hasHeader = false
val hasTimeOrChronometer = content.time != null
val hasTextBeforeSubText = hasAppName
@@ -412,26 +443,27 @@
}
private fun updateConversationHeader(content: PromotedNotificationContentModel) {
- updateTitle(conversationText, content)
updateAppName(content)
updateTimeAndChronometer(content)
- updateConversationHeaderDividers(content, hideTitle = true)
-
updateImageView(verificationIcon, content.verificationIcon)
updateTextView(verificationText, content.verificationText)
+ updateConversationHeaderDividers(content)
+
+ updateTopLine(content)
+
updateSmallIcon(conversationIcon, content)
+ updateTitle(conversationText, content)
}
- private fun updateConversationHeaderDividers(
- content: PromotedNotificationContentModel,
- hideTitle: Boolean = false,
- ) {
- val hasTitle = content.title != null && !hideTitle
+ private fun updateConversationHeaderDividers(content: PromotedNotificationContentModel) {
+ // Not setting hasTitle = content.title because the title is always a separate element in
+ // the expanded layout used for AOD RONs.
+ val hasTitle = false
val hasAppName = content.appName != null
val hasTimeOrChronometer = content.time != null
val hasVerification =
- !content.verificationIcon.isNullOrEmpty() || !content.verificationText.isNullOrEmpty()
+ !content.verificationIcon.isNullOrEmpty() || content.verificationText != null
val hasTextBeforeAppName = hasTitle
val hasTextBeforeTime = hasTitle || hasAppName
@@ -451,6 +483,10 @@
}
private fun updateTitle(titleView: TextView?, content: PromotedNotificationContentModel) {
+ (titleView?.layoutParams as? MarginLayoutParams)?.let {
+ it.marginEnd = content.imageEndMarginPxIfHasLargeIcon
+ titleView.layoutParams = it
+ }
updateTextView(titleView, content.title, color = PrimaryText)
}
@@ -499,6 +535,10 @@
chronometer?.appendFontFeatureSetting("tnum")
}
+ private fun updateTopLine(content: PromotedNotificationContentModel) {
+ topLine?.headerTextMarginEnd = content.imageEndMarginPxIfHasLargeIcon
+ }
+
private fun inflateOldProgressBar() {
if (oldProgressBar != null) {
return
@@ -512,7 +552,8 @@
view: ImageFloatingTextView?,
content: PromotedNotificationContentModel,
) {
- view?.setHasImage(false)
+ view?.setHasImage(!content.skeletonLargeIcon.isNullOrEmpty())
+ view?.setNumIndentLines(if (content.title != null) 0 else 1)
updateTextView(view, content.text)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt
index a8a7e88..d9bdfbc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt
@@ -183,9 +183,10 @@
private fun Notification.smallIconModel(imageModelProvider: ImageModelProvider): ImageModel? =
imageModelProvider.getImageModel(smallIcon, SmallSquare)
- private fun Notification.title(): CharSequence? = extras?.getCharSequence(EXTRA_TITLE)
+ private fun Notification.title(): CharSequence? = getCharSequenceExtraUnlessEmpty(EXTRA_TITLE)
- private fun Notification.bigTitle(): CharSequence? = extras?.getCharSequence(EXTRA_TITLE_BIG)
+ private fun Notification.bigTitle(): CharSequence? =
+ getCharSequenceExtraUnlessEmpty(EXTRA_TITLE_BIG)
private fun Notification.callPerson(): Person? =
extras?.getParcelable(EXTRA_CALL_PERSON, Person::class.java)
@@ -200,9 +201,10 @@
} ?: title()
}
- private fun Notification.text(): CharSequence? = extras?.getCharSequence(EXTRA_TEXT)
+ private fun Notification.text(): CharSequence? = getCharSequenceExtraUnlessEmpty(EXTRA_TEXT)
- private fun Notification.bigText(): CharSequence? = extras?.getCharSequence(EXTRA_BIG_TEXT)
+ private fun Notification.bigText(): CharSequence? =
+ getCharSequenceExtraUnlessEmpty(EXTRA_BIG_TEXT)
private fun Notification.text(style: Notification.Style?): CharSequence? {
return when (style) {
@@ -211,17 +213,17 @@
} ?: text()
}
- private fun Notification.subText(): String? = extras?.getString(EXTRA_SUB_TEXT)
+ private fun Notification.subText(): String? = getStringExtraUnlessEmpty(EXTRA_SUB_TEXT)
private fun Notification.shortCriticalText(): String? {
if (!android.app.Flags.apiRichOngoing()) {
return null
}
- if (this.shortCriticalText != null) {
- return this.shortCriticalText
+ if (shortCriticalText != null) {
+ return shortCriticalText
}
if (Flags.promoteNotificationsAutomatically()) {
- return this.extras?.getString(EXTRA_AUTOMATICALLY_EXTRACTED_SHORT_CRITICAL_TEXT)
+ return getStringExtraUnlessEmpty(EXTRA_AUTOMATICALLY_EXTRACTED_SHORT_CRITICAL_TEXT)
}
return null
}
@@ -277,7 +279,7 @@
}
private fun Notification.verificationText(): CharSequence? =
- extras.getCharSequence(EXTRA_VERIFICATION_TEXT)
+ getCharSequenceExtraUnlessEmpty(EXTRA_VERIFICATION_TEXT)
private fun Notification.Builder.extractStyleContent(
notification: Notification,
@@ -344,3 +346,11 @@
contentBuilder.newProgress = createProgressModel(0xffffffff.toInt(), 0xff000000.toInt())
}
}
+
+private fun Notification.getCharSequenceExtraUnlessEmpty(key: String): CharSequence? =
+ extras?.getCharSequence(key)?.takeUnlessEmpty()
+
+private fun Notification.getStringExtraUnlessEmpty(key: String): String? =
+ extras?.getString(key)?.takeUnlessEmpty()
+
+private fun <T : CharSequence> T.takeUnlessEmpty(): T? = takeUnless { it.isEmpty() }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt
index ffacf62..339a5bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt
@@ -23,11 +23,13 @@
import android.app.Notification.FLAG_PROMOTED_ONGOING
import androidx.annotation.ColorInt
import com.android.internal.widget.NotificationProgressModel
+import com.android.systemui.Flags
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi
import com.android.systemui.statusbar.notification.row.ImageResult
import com.android.systemui.statusbar.notification.row.LazyImage
import com.android.systemui.statusbar.notification.row.shared.ImageModel
+import com.android.systemui.util.Compile
data class PromotedNotificationContentModels(
/** The potentially redacted version of the content that will be exposed to the public */
@@ -238,6 +240,10 @@
*/
@JvmStatic
fun isPromotedForStatusBarChip(notification: Notification): Boolean {
+ if (Compile.IS_DEBUG && Flags.debugLiveUpdatesPromoteAll()) {
+ return true
+ }
+
// Notification.isPromotedOngoing checks the ui_rich_ongoing flag, but we want the
// status bar chip to be ready before all the features behind the ui_rich_ongoing flag
// are ready.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AnimatedActionBackgroundDrawable.kt
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AnimatedActionBackgroundDrawable.kt
index a9ca635..514e165 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AnimatedActionBackgroundDrawable.kt
@@ -36,7 +36,7 @@
import android.graphics.drawable.RippleDrawable
import androidx.core.content.ContextCompat
-class MagicActionBackgroundDrawable(
+class AnimatedActionBackgroundDrawable(
context: Context,
) : RippleDrawable(
ContextCompat.getColorStateList(
@@ -56,13 +56,13 @@
context: Context,
) : Drawable() {
- private val cornerRadius = context.resources.getDimension(R.dimen.magic_action_button_corner_radius)
- private val outlineStrokeWidth = context.resources.getDimension(R.dimen.magic_action_button_outline_stroke_width)
+ private val cornerRadius = context.resources.getDimension(R.dimen.animated_action_button_corner_radius)
+ private val outlineStrokeWidth = context.resources.getDimension(R.dimen.animated_action_button_outline_stroke_width)
private val insetVertical = 8 * context.resources.displayMetrics.density
private val buttonShape = Path()
// Color and style
- private val outlineStaticColor = context.getColor(R.color.magic_action_button_stroke_color)
+ private val outlineStaticColor = context.getColor(R.color.animated_action_button_stroke_color)
private val bgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
val bgColor =
context.getColor(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionButton.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AnimatedActionButton.kt
similarity index 82%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionButton.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AnimatedActionButton.kt
index d735360..a1d75c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionButton.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AnimatedActionButton.kt
@@ -22,15 +22,15 @@
import android.widget.Button
/**
- * Custom Button for Magic Action Button, which includes the custom background and foreground.
+ * Custom Button for Animated Action Button, which includes the custom background and foreground.
*/
@SuppressLint("AppCompatCustomView")
-class MagicActionButton @JvmOverloads constructor(
+class AnimatedActionButton @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
) : Button(context, attrs, defStyleAttr) {
init {
- background = MagicActionBackgroundDrawable(context)
+ background = AnimatedActionBackgroundDrawable(context)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
index 20b826a..c04613a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
@@ -145,7 +145,11 @@
| View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION);
if (result) {
// Log notification drag only if it succeeds
- mNotificationPanelLogger.logNotificationDrag(enr.getEntry());
+ if (NotificationBundleUi.isEnabled()) {
+ mNotificationPanelLogger.logNotificationDrag(enr.getEntryAdapter());
+ } else {
+ mNotificationPanelLogger.logNotificationDrag(enr.getEntryLegacy());
+ }
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
if (enr.isPinned()) {
mHeadsUpManager.releaseAllImmediately();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java
index 40897da..d80d5e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java
@@ -45,7 +45,6 @@
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.util.Compile;
public class FeedbackInfo extends LinearLayout implements NotificationGuts.GutsContent {
@@ -58,7 +57,6 @@
private PackageManager mPm;
private String mAppName;
private String mPkg;
- private NotificationEntry mEntry;
private IStatusBarService mStatusBarService;
private AssistantFeedbackController mFeedbackController;
@@ -73,16 +71,15 @@
public void bindGuts(
final PackageManager pm,
final StatusBarNotification sbn,
- final NotificationEntry entry,
+ final NotificationListenerService.Ranking ranking,
final ExpandableNotificationRow row,
final AssistantFeedbackController controller,
final IStatusBarService statusBarService,
final NotificationGutsManager notificationGutsManager) {
mPkg = sbn.getPackageName();
mPm = pm;
- mEntry = entry;
mExpandableNotificationRow = row;
- mRanking = entry.getRanking();
+ mRanking = ranking;
mFeedbackController = controller;
mAppName = mPkg;
mStatusBarService = statusBarService;
@@ -143,7 +140,7 @@
@SuppressLint("DefaultLocale")
private String getPrompt() {
StringBuilder sb = new StringBuilder();
- int status = mFeedbackController.getFeedbackStatus(mEntry);
+ int status = mFeedbackController.getFeedbackStatus(mRanking);
if (DEBUG) {
sb.append(String.format(
"[DEBUG]: oldImportance=%d, newImportance=%d, ranking=%f\n\n",
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
index ba80f01..4c7c46d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
@@ -51,7 +51,7 @@
*/
public class HybridConversationNotificationView extends HybridNotificationView {
- private static final int MAX_SUMMARIZATION_LINES = 2;
+ private static final int MAX_SUMMARIZATION_LINES = 1;
private ImageView mConversationIconView;
private TextView mConversationSenderName;
private ViewStub mConversationFacePileStub;
@@ -295,7 +295,6 @@
if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) return;
if (!TextUtils.isEmpty(summarization)) {
mConversationSenderName.setVisibility(GONE);
- titleText = null;
contentText = summarization;
mTextView.setSingleLine(false);
mTextView.setMaxLines(MAX_SUMMARIZATION_LINES);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 57ceafc..f17ae57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -1392,7 +1392,7 @@
mPromotedNotificationContentExtractor.extractContent(mEntry,
recoveredBuilder, mBindParams.redactionType, imageModelProvider);
mLogger.logAsyncTaskProgress(logKey, "extracted promoted notification content: "
- + promotedContent);
+ + (promotedContent != null ? promotedContent.toRedactedString() : null));
result.mPromotedContent = promotedContent;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 3c7d9ef..2cf3b14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -49,6 +49,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.transition.ChangeBounds;
@@ -72,7 +73,9 @@
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.notification.NmSummarizationUiFlag;
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.wmshell.BubblesManager;
@@ -104,6 +107,8 @@
private ShortcutInfo mShortcutInfo;
private NotificationEntry mEntry;
private StatusBarNotification mSbn;
+ private EntryAdapter mEntryAdapter;
+ private NotificationListenerService.Ranking mRanking;
@Nullable private Notification.BubbleMetadata mBubbleMetadata;
private Context mUserContext;
private boolean mIsDeviceProvisioned;
@@ -200,9 +205,10 @@
INotificationManager iNotificationManager,
OnUserInteractionCallback onUserInteractionCallback,
String pkg,
- NotificationChannel notificationChannel,
NotificationEntry entry,
- Notification.BubbleMetadata bubbleMetadata,
+ EntryAdapter entryAdapter,
+ NotificationListenerService.Ranking ranking,
+ StatusBarNotification sbn,
OnSettingsClickListener onSettingsClick,
NotificationInfo.OnFeedbackClickListener onFeedbackClickListener,
ConversationIconFactory conversationIconFactory,
@@ -218,25 +224,27 @@
mOnUserInteractionCallback = onUserInteractionCallback;
mPackageName = pkg;
mEntry = entry;
- mSbn = entry.getSbn();
+ mSbn = sbn;
+ mRanking = ranking;
+ mEntryAdapter = entryAdapter;
mPm = pm;
mUm = um;
mAppName = mPackageName;
mOnSettingsClickListener = onSettingsClick;
- mNotificationChannel = notificationChannel;
+ mNotificationChannel = ranking.getChannel();
mAppUid = mSbn.getUid();
mDelegatePkg = mSbn.getOpPkg();
mIsDeviceProvisioned = isDeviceProvisioned;
mOnConversationSettingsClickListener = onConversationSettingsClickListener;
mIconFactory = conversationIconFactory;
mUserContext = userContext;
- mBubbleMetadata = bubbleMetadata;
+ mBubbleMetadata = sbn.getNotification().getBubbleMetadata();
mBubblesManagerOptional = bubblesManagerOptional;
mShadeController = shadeController;
mMainHandler = mainHandler;
mBgHandler = bgHandler;
mShortcutManager = shortcutManager;
- mShortcutInfo = entry.getRanking().getConversationShortcutInfo();
+ mShortcutInfo = ranking.getConversationShortcutInfo();
mFeedbackClickListener = onFeedbackClickListener;
if (mShortcutInfo == null) {
throw new IllegalArgumentException("Does not have required information");
@@ -308,11 +316,11 @@
private void bindFeedback() {
View feedbackButton = findViewById(R.id.feedback);
if (!NmSummarizationUiFlag.isEnabled()
- || TextUtils.isEmpty(mEntry.getRanking().getSummarization())) {
+ || TextUtils.isEmpty(mRanking.getSummarization())) {
feedbackButton.setVisibility(GONE);
} else {
Intent intent = NotificationInfo.getAssistantFeedbackIntent(
- mINotificationManager, mPm, mEntry);
+ mINotificationManager, mPm, mSbn.getKey(), mRanking);
if (intent == null) {
feedbackButton.setVisibility(GONE);
} else {
@@ -551,10 +559,17 @@
mBgHandler.post(
new UpdateChannelRunnable(mINotificationManager, mPackageName,
mAppUid, mSelectedAction, mNotificationChannel));
- mEntry.markForUserTriggeredMovement(true);
- mMainHandler.postDelayed(
- () -> mOnUserInteractionCallback.onImportanceChanged(mEntry),
- StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ if (NotificationBundleUi.isEnabled()) {
+ mEntryAdapter.markForUserTriggeredMovement();
+ mMainHandler.postDelayed(
+ () -> mEntryAdapter.onImportanceChanged(),
+ StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ } else {
+ mEntry.markForUserTriggeredMovement(true);
+ mMainHandler.postDelayed(
+ () -> mOnUserInteractionCallback.onImportanceChanged(mEntry),
+ StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ }
}
private boolean willBypassDnd() {
@@ -658,8 +673,13 @@
BUBBLE_PREFERENCE_SELECTED);
}
if (mBubblesManagerOptional.isPresent()) {
- post(() -> mBubblesManagerOptional.get()
- .onUserSetImportantConversation(mEntry));
+ if (NotificationBundleUi.isEnabled()) {
+ post(() -> mBubblesManagerOptional.get()
+ .onUserSetImportantConversation(mEntryAdapter));
+ } else {
+ post(() -> mBubblesManagerOptional.get()
+ .onUserSetImportantConversation(mEntry));
+ }
}
}
mChannelToUpdate.setImportance(Math.max(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index f4e01bf..6c7c7a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -33,6 +33,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.IconDrawableFactory;
@@ -66,7 +67,6 @@
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewListener;
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager;
@@ -289,10 +289,21 @@
@VisibleForTesting
protected boolean bindGuts(final ExpandableNotificationRow row,
NotificationMenuRowPlugin.MenuItem item) {
- NotificationEntry entry = row.getEntry();
+
+ StatusBarNotification sbn = NotificationBundleUi.isEnabled()
+ ? row.getEntryAdapter().getSbn()
+ : row.getEntryLegacy().getSbn();
+ NotificationListenerService.Ranking ranking = NotificationBundleUi.isEnabled()
+ ? row.getEntryAdapter().getRanking()
+ : row.getEntryLegacy().getRanking();
+
+ if (sbn == null || ranking == null) {
+ // only valid for notification rows
+ return false;
+ }
row.setGutsView(item);
- row.setTag(entry.getSbn().getPackageName());
+ row.setTag(sbn.getPackageName());
row.getGuts().setClosedListener((NotificationGuts g) -> {
row.onGutsClosed();
if (!g.willBeRemoved() && !row.isRemoved()) {
@@ -304,28 +315,37 @@
mGutsMenuItem = null;
}
if (mGutsListener != null) {
- mGutsListener.onGutsClose(entry);
+ if (NotificationBundleUi.isEnabled()) {
+ mGutsListener.onGutsClose(row.getEntryAdapter());
+ row.updateBubbleButton();
+ } else {
+ mGutsListener.onGutsClose(row.getEntryLegacy());
+ }
}
- mHeadsUpManager.setGutsShown(row.getEntry(), false);
+ if(NotificationBundleUi.isEnabled()) {
+ row.getEntryAdapter().setInlineControlsShown(false);
+ } else {
+ mHeadsUpManager.setGutsShown(row.getEntryLegacy(), false);
+ }
});
View gutsView = item.getGutsView();
try {
if (gutsView instanceof NotificationSnooze) {
- initializeSnoozeView(row, (NotificationSnooze) gutsView);
+ initializeSnoozeView(row, sbn, ranking, (NotificationSnooze) gutsView);
} else if (gutsView instanceof NotificationInfo) {
- initializeNotificationInfo(row, (NotificationInfo) gutsView);
+ initializeNotificationInfo(row, sbn, ranking, (NotificationInfo) gutsView);
} else if (gutsView instanceof NotificationConversationInfo) {
initializeConversationNotificationInfo(
- row, (NotificationConversationInfo) gutsView);
+ row, sbn, ranking, (NotificationConversationInfo) gutsView);
} else if (gutsView instanceof PartialConversationInfo) {
- initializePartialConversationNotificationInfo(row,
+ initializePartialConversationNotificationInfo(row, sbn, ranking,
(PartialConversationInfo) gutsView);
} else if (gutsView instanceof FeedbackInfo) {
- initializeFeedbackInfo(row, (FeedbackInfo) gutsView);
+ initializeFeedbackInfo(row, sbn, ranking, (FeedbackInfo) gutsView);
} else if (gutsView instanceof PromotedPermissionGutsContent) {
- initializeDemoteView(row, (PromotedPermissionGutsContent) gutsView);
+ initializeDemoteView(row, sbn, (PromotedPermissionGutsContent) gutsView);
}
return true;
} catch (Exception e) {
@@ -342,13 +362,14 @@
*/
private void initializeSnoozeView(
final ExpandableNotificationRow row,
+ final StatusBarNotification sbn,
+ final NotificationListenerService.Ranking ranking,
NotificationSnooze notificationSnoozeView) {
NotificationGuts guts = row.getGuts();
- StatusBarNotification sbn = row.getEntry().getSbn();
notificationSnoozeView.setSnoozeListener(mListContainer.getSwipeActionHelper());
notificationSnoozeView.setStatusBarNotification(sbn);
- notificationSnoozeView.setSnoozeOptions(row.getEntry().getSnoozeCriteria());
+ notificationSnoozeView.setSnoozeOptions(ranking.getSnoozeCriteria());
guts.setHeightChangedListener((NotificationGuts g) -> {
mListContainer.onHeightChanged(row, row.isShown() /* needsAnimation */);
});
@@ -362,8 +383,8 @@
*/
private void initializeDemoteView(
final ExpandableNotificationRow row,
+ StatusBarNotification sbn,
PromotedPermissionGutsContent demoteGuts) {
- StatusBarNotification sbn = row.getEntry().getSbn();
demoteGuts.setStatusBarNotification(sbn);
demoteGuts.setOnDemoteAction(new View.OnClickListener() {
@Override
@@ -387,16 +408,17 @@
*/
private void initializeFeedbackInfo(
final ExpandableNotificationRow row,
+ final StatusBarNotification sbn,
+ final NotificationListenerService.Ranking ranking,
FeedbackInfo feedbackInfo) {
- if (mAssistantFeedbackController.getFeedbackIcon(row.getEntry()) == null) {
+ if (mAssistantFeedbackController.getFeedbackIcon(ranking) == null) {
return;
}
- StatusBarNotification sbn = row.getEntry().getSbn();
UserHandle userHandle = sbn.getUser();
PackageManager pmUser = CentralSurfaces.getPackageManagerForUser(mContext,
userHandle.getIdentifier());
- feedbackInfo.bindGuts(pmUser, sbn, row.getEntry(), row, mAssistantFeedbackController,
+ feedbackInfo.bindGuts(pmUser, sbn, ranking, row, mAssistantFeedbackController,
mStatusBarService, this);
}
@@ -408,9 +430,10 @@
@VisibleForTesting
void initializeNotificationInfo(
final ExpandableNotificationRow row,
+ final StatusBarNotification sbn,
+ final NotificationListenerService.Ranking ranking,
NotificationInfo notificationInfoView) throws Exception {
NotificationGuts guts = row.getGuts();
- StatusBarNotification sbn = row.getEntry().getSbn();
String packageName = sbn.getPackageName();
// Settings link is only valid for notifications that specify a non-system user
NotificationInfo.OnSettingsClickListener onSettingsClick = null;
@@ -449,18 +472,22 @@
mChannelEditorDialogController,
mPackageDemotionInteractor,
packageName,
- row.getEntry().getChannel(),
- row.getEntry(),
+ ranking,
+ sbn,
+ NotificationBundleUi.isEnabled() ? null : row.getEntryLegacy(),
+ NotificationBundleUi.isEnabled() ? row.getEntryAdapter() : null,
onSettingsClick,
onAppSettingsClick,
onNasFeedbackClick,
mUiEventLogger,
mDeviceProvisionedController.isDeviceProvisioned(),
NotificationBundleUi.isEnabled()
- ? !row.getEntry().isBlockable()
+ ? !row.getEntryAdapter().isBlockable()
: row.getIsNonblockable(),
row.canViewBeDismissed(),
- mHighPriorityProvider.isHighPriority(row.getEntry()),
+ NotificationBundleUi.isEnabled()
+ ? row.getEntryAdapter().isHighPriority()
+ : mHighPriorityProvider.isHighPriority(row.getEntryLegacy()),
mAssistantFeedbackController,
mMetricsLogger,
row.getCloseButtonOnClickListener(row));
@@ -474,9 +501,10 @@
@VisibleForTesting
void initializePartialConversationNotificationInfo(
final ExpandableNotificationRow row,
+ final StatusBarNotification sbn,
+ final NotificationListenerService.Ranking ranking,
PartialConversationInfo notificationInfoView) throws Exception {
NotificationGuts guts = row.getGuts();
- StatusBarNotification sbn = row.getEntry().getSbn();
String packageName = sbn.getPackageName();
// Settings link is only valid for notifications that specify a non-system user
NotificationInfo.OnSettingsClickListener onSettingsClick = null;
@@ -499,12 +527,12 @@
mNotificationManager,
mChannelEditorDialogController,
packageName,
- row.getEntry().getChannel(),
- row.getEntry(),
+ ranking,
+ sbn,
onSettingsClick,
mDeviceProvisionedController.isDeviceProvisioned(),
NotificationBundleUi.isEnabled()
- ? !row.getEntry().isBlockable()
+ ? !row.getEntryAdapter().isBlockable()
: row.getIsNonblockable());
}
@@ -516,10 +544,10 @@
@VisibleForTesting
void initializeConversationNotificationInfo(
final ExpandableNotificationRow row,
+ final StatusBarNotification sbn,
+ final NotificationListenerService.Ranking ranking,
NotificationConversationInfo notificationInfoView) throws Exception {
NotificationGuts guts = row.getGuts();
- NotificationEntry entry = row.getEntry();
- StatusBarNotification sbn = entry.getSbn();
String packageName = sbn.getPackageName();
// Settings link is only valid for notifications that specify a non-system user
NotificationConversationInfo.OnSettingsClickListener onSettingsClick = null;
@@ -567,9 +595,10 @@
mNotificationManager,
mOnUserInteractionCallback,
packageName,
- entry.getChannel(),
- entry,
- entry.getBubbleMetadata(),
+ NotificationBundleUi.isEnabled() ? null : row.getEntryLegacy(),
+ NotificationBundleUi.isEnabled() ? row.getEntryAdapter() : null,
+ ranking,
+ sbn,
onSettingsClick,
onNasFeedbackClick,
iconFactoryLoader,
@@ -746,13 +775,21 @@
row::onGutsOpened);
if (mGutsListener != null) {
- mGutsListener.onGutsOpen(row.getEntry(), guts);
+ if(NotificationBundleUi.isEnabled()) {
+ mGutsListener.onGutsOpen(row.getEntryAdapter(), guts);
+ } else {
+ mGutsListener.onGutsOpen(row.getEntryLegacy(), guts);
+ }
}
row.closeRemoteInput();
mListContainer.onHeightChanged(row, true /* needsAnimation */);
mGutsMenuItem = menuItem;
- mHeadsUpManager.setGutsShown(row.getEntry(), true);
+ if(NotificationBundleUi.isEnabled()) {
+ row.getEntryAdapter().setInlineControlsShown(true);
+ } else {
+ mHeadsUpManager.setGutsShown(row.getEntryLegacy(), true);
+ }
}
};
guts.post(mOpenRunnable);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index b6f4ffc..571006b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -50,6 +50,7 @@
import android.os.Handler;
import android.os.RemoteException;
import android.service.notification.NotificationAssistantService;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.text.Html;
import android.text.TextUtils;
@@ -73,10 +74,12 @@
import com.android.systemui.Dependency;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.promoted.domain.interactor.PackageDemotionInteractor;
import com.android.systemui.statusbar.notification.row.icon.AppIconProvider;
import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import java.lang.annotation.Retention;
import java.util.List;
@@ -124,6 +127,8 @@
private boolean mIsDismissable;
private NotificationEntry mEntry;
private StatusBarNotification mSbn;
+ private NotificationListenerService.Ranking mRanking;
+ private EntryAdapter mEntryAdapter;
private boolean mIsDeviceProvisioned;
private boolean mIsSystemRegisteredCall;
@@ -198,8 +203,10 @@
ChannelEditorDialogController channelEditorDialogController,
PackageDemotionInteractor packageDemotionInteractor,
String pkg,
- NotificationChannel notificationChannel,
+ NotificationListenerService.Ranking ranking,
+ StatusBarNotification sbn,
NotificationEntry entry,
+ EntryAdapter entryAdapter,
OnSettingsClickListener onSettingsClick,
OnAppSettingsClickListener onAppSettingsClick,
OnFeedbackClickListener onFeedbackClickListener,
@@ -220,14 +227,16 @@
mChannelEditorDialogController = channelEditorDialogController;
mAssistantFeedbackController = assistantFeedbackController;
mPackageName = pkg;
+ mSbn = sbn;
+ mRanking = ranking;
mEntry = entry;
- mSbn = entry.getSbn();
+ mEntryAdapter = entryAdapter;
mPm = pm;
mAppSettingsClickListener = onAppSettingsClick;
mFeedbackClickListener = onFeedbackClickListener;
mAppName = mPackageName;
mOnSettingsClickListener = onSettingsClick;
- mSingleNotificationChannel = notificationChannel;
+ mSingleNotificationChannel = ranking.getChannel();
mStartingChannelImportance = mSingleNotificationChannel.getImportance();
mWasShownHighPriority = wasShownHighPriority;
mIsNonblockable = isNonblockable;
@@ -301,7 +310,8 @@
View automatic = findViewById(R.id.automatic);
if (mShowAutomaticSetting) {
mAutomaticDescriptionView.setText(Html.fromHtml(mContext.getText(
- mAssistantFeedbackController.getInlineDescriptionResource(mEntry)).toString()));
+ mAssistantFeedbackController.getInlineDescriptionResource(mRanking))
+ .toString()));
automatic.setVisibility(VISIBLE);
automatic.setOnClickListener(mOnAutomatic);
} else {
@@ -381,7 +391,8 @@
private void bindFeedback() {
View feedbackButton = findViewById(R.id.feedback);
- Intent intent = getAssistantFeedbackIntent(mINotificationManager, mPm, mEntry);
+ Intent intent = getAssistantFeedbackIntent(
+ mINotificationManager, mPm, mSbn.getKey(), mRanking);
if (!android.app.Flags.notificationClassificationUi() || intent == null) {
feedbackButton.setVisibility(GONE);
} else {
@@ -395,7 +406,7 @@
}
public static Intent getAssistantFeedbackIntent(INotificationManager inm, PackageManager pm,
- NotificationEntry entry) {
+ String key, NotificationListenerService.Ranking ranking) {
try {
ComponentName assistant = inm.getAllowedNotificationAssistant();
if (assistant == null) {
@@ -414,9 +425,9 @@
final ActivityInfo activityInfo = resolveInfos.get(0).activityInfo;
intent.setClassName(activityInfo.packageName, activityInfo.name);
- intent.putExtra(NotificationAssistantService.EXTRA_NOTIFICATION_KEY, entry.getKey());
+ intent.putExtra(NotificationAssistantService.EXTRA_NOTIFICATION_KEY, key);
intent.putExtra(NotificationAssistantService.EXTRA_NOTIFICATION_ADJUSTMENT,
- entry.getRanking().getSummarization() != null ? KEY_SUMMARIZATION : KEY_TYPE);
+ ranking.getSummarization() != null ? KEY_SUMMARIZATION : KEY_TYPE);
return intent;
} catch (Exception e) {
Slog.d(TAG, "no assistant?", e);
@@ -526,7 +537,11 @@
new UpdateImportanceRunnable(mINotificationManager, mPackageName, mAppUid,
mSingleNotificationChannel,
mStartingChannelImportance, newImportance, mIsAutomaticChosen));
- mOnUserInteractionCallback.onImportanceChanged(mEntry);
+ if (NotificationBundleUi.isEnabled()) {
+ mEntryAdapter.onImportanceChanged();
+ } else {
+ mOnUserInteractionCallback.onImportanceChanged(mEntry);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
index 4f1b905..efc90c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
@@ -710,7 +710,7 @@
.also {
logger.logAsyncTaskProgress(
entry.logKey,
- "extracted promoted notification content: $it",
+ "extracted promoted notification content: ${it?.toRedactedString()}",
)
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
index 60e98a5..3b79579 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
@@ -24,6 +24,7 @@
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -35,6 +36,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.res.R;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
/**
@@ -79,18 +81,18 @@
INotificationManager iNotificationManager,
ChannelEditorDialogController channelEditorDialogController,
String pkg,
- NotificationChannel notificationChannel,
- NotificationEntry entry,
+ NotificationListenerService.Ranking ranking,
+ StatusBarNotification sbn,
NotificationInfo.OnSettingsClickListener onSettingsClick,
boolean isDeviceProvisioned,
boolean isNonBlockable) {
mINotificationManager = iNotificationManager;
mPackageName = pkg;
- mSbn = entry.getSbn();
+ mSbn = sbn;
mPm = pm;
mAppName = mPackageName;
mOnSettingsClickListener = onSettingsClick;
- mNotificationChannel = notificationChannel;
+ mNotificationChannel = ranking.getChannel();
mAppUid = mSbn.getUid();
mDelegatePkg = mSbn.getOpPkg();
mIsDeviceProvisioned = isDeviceProvisioned;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfo.java
index 769f0b5..2cb2089 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfo.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.RemoteException;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.util.Log;
@@ -30,6 +31,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.promoted.domain.interactor.PackageDemotionInteractor;
import com.android.systemui.statusbar.notification.row.icon.AppIconProvider;
@@ -60,8 +62,10 @@
ChannelEditorDialogController channelEditorDialogController,
PackageDemotionInteractor packageDemotionInteractor,
String pkg,
- NotificationChannel notificationChannel,
+ NotificationListenerService.Ranking ranking,
+ StatusBarNotification sbn,
NotificationEntry entry,
+ EntryAdapter entryAdapter,
OnSettingsClickListener onSettingsClick,
OnAppSettingsClickListener onAppSettingsClick,
OnFeedbackClickListener feedbackClickListener,
@@ -73,17 +77,17 @@
AssistantFeedbackController assistantFeedbackController,
MetricsLogger metricsLogger, OnClickListener onCloseClick) throws RemoteException {
super.bindNotification(pm, iNotificationManager, appIconProvider, iconStyleProvider,
- onUserInteractionCallback, channelEditorDialogController, packageDemotionInteractor,
- pkg, notificationChannel,
- entry, onSettingsClick, onAppSettingsClick, feedbackClickListener, uiEventLogger,
- isDeviceProvisioned, isNonblockable, isDismissable, wasShownHighPriority,
- assistantFeedbackController, metricsLogger, onCloseClick);
+ onUserInteractionCallback, channelEditorDialogController,
+ packageDemotionInteractor,pkg, ranking, sbn,
+ entry, entryAdapter, onSettingsClick, onAppSettingsClick, feedbackClickListener,
+ uiEventLogger, isDeviceProvisioned, isDismissable, isNonblockable,
+ wasShownHighPriority, assistantFeedbackController, metricsLogger, onCloseClick);
mNotificationManager = iNotificationManager;
mPackageDemotionInteractor = packageDemotionInteractor;
- bindDemote(entry.getSbn(), pkg);
+ bindDemote(sbn, pkg);
}
protected void bindDemote(StatusBarNotification sbn, String packageName) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
index 9652738..3c8ebfd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
@@ -18,6 +18,7 @@
import android.app.PendingIntent
import android.graphics.drawable.Icon
import android.util.Log
+import com.android.internal.logging.InstanceId
import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModels
@@ -78,7 +79,7 @@
/** The intent to execute if UI related to this notification is clicked. */
val contentIntent: PendingIntent?,
/** A small per-notification ID, used for statsd logging. */
- val instanceId: Int?,
+ val instanceId: InstanceId?,
/** If this notification is the group summary for a group of notifications. */
val isGroupSummary: Boolean,
/** Indicates in which section the notification is displayed in. @see [PriorityBucket]. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
index 8cf9dd3..d1e6c6f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
@@ -30,6 +30,7 @@
import androidx.annotation.NonNull;
import com.android.app.animation.Interpolators;
+import com.android.internal.dynamicanimation.animation.DynamicAnimation;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.PhysicsProperty;
import com.android.systemui.statusbar.notification.PhysicsPropertyAnimator;
@@ -199,15 +200,19 @@
if (animateHeight) {
expandableView.setActualHeightAnimating(true);
}
+ DynamicAnimation.OnAnimationEndListener endListener = null;
+ if (!ViewState.isAnimating(expandableView, HEIGHT_PROPERTY)) {
+ // only Add the end listener if we haven't already
+ endListener = (animation, canceled, value, velocity) -> {
+ expandableView.setActualHeightAnimating(false);
+ if (!canceled && child instanceof ExpandableNotificationRow row) {
+ row.setGroupExpansionChanging(false /* isExpansionChanging */);
+ }
+ };
+ }
PhysicsPropertyAnimator.setProperty(child, HEIGHT_PROPERTY, this.height, properties,
animateHeight,
- (animation, canceled, value, velocity) -> {
- expandableView.setActualHeightAnimating(false);
- if (!canceled && child instanceof ExpandableNotificationRow) {
- ((ExpandableNotificationRow) child).setGroupExpansionChanging(
- false /* isExpansionChanging */);
- }
- });
+ endListener);
} else {
startHeightAnimationInterpolator(expandableView, properties);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 503256a..afa988d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -6076,7 +6076,9 @@
if (mBlurRadius > 0) {
mBlurEffect =
RenderEffect.createBlurEffect(mBlurRadius, mBlurRadius, Shader.TileMode.CLAMP);
+ spewLog("Setting up blur RenderEffect for NotificationStackScrollLayout");
} else {
+ spewLog("Clearing the blur RenderEffect setup for NotificationStackScrollLayout");
mBlurEffect = null;
}
}
@@ -6252,6 +6254,7 @@
@Override
protected void dispatchDraw(@NonNull Canvas canvas) {
if (mBlurEffect != null) {
+ spewLog("Applying blur RenderEffect to NotificationStackScrollLayout");
// reuse the cached RenderNode to blur
mBlurNode.setPosition(0, 0, canvas.getWidth(), canvas.getHeight());
mBlurNode.setRenderEffect(mBlurEffect);
@@ -7025,4 +7028,10 @@
SceneContainerFlag.assertInLegacyMode();
mMaxTopPadding = maxTopPadding;
}
+
+ private void spewLog(String logMsg) {
+ if (SPEW) {
+ Log.v(TAG, logMsg);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 612c19f..66c9b17e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -420,10 +420,15 @@
return;
}
if (view instanceof ExpandableNotificationRow row) {
- mMetricsLogger.write(row.getEntry().getSbn().getLogMaker()
- .setCategory(MetricsEvent.ACTION_TOUCH_GEAR)
- .setType(MetricsEvent.TYPE_ACTION)
- );
+ StatusBarNotification sbn = NotificationBundleUi.isEnabled()
+ ? row.getEntryAdapter().getSbn()
+ : row.getEntryLegacy().getSbn();
+ if (sbn != null) {
+ mMetricsLogger.write(row.getEntry().getSbn().getLogMaker()
+ .setCategory(MetricsEvent.ACTION_TOUCH_GEAR)
+ .setType(MetricsEvent.TYPE_ACTION)
+ );
+ }
}
mNotificationGutsManager.openGuts(view, x, y, item);
}
@@ -440,9 +445,14 @@
@Override
public void onMenuShown(View row) {
if (row instanceof ExpandableNotificationRow notificationRow) {
- mMetricsLogger.write(notificationRow.getEntry().getSbn().getLogMaker()
- .setCategory(MetricsEvent.ACTION_REVEAL_GEAR)
- .setType(MetricsEvent.TYPE_ACTION));
+ StatusBarNotification sbn = NotificationBundleUi.isEnabled()
+ ? notificationRow.getEntryAdapter().getSbn()
+ : notificationRow.getEntryLegacy().getSbn();
+ if (sbn != null) {
+ mMetricsLogger.write(notificationRow.getEntry().getSbn().getLogMaker()
+ .setCategory(MetricsEvent.ACTION_REVEAL_GEAR)
+ .setType(MetricsEvent.TYPE_ACTION));
+ }
mSwipeHelper.onMenuShown(row);
mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
@@ -1355,11 +1365,15 @@
*/
public void setBlurRadius(float blurRadius) {
if (blurRadius > 0.0f) {
+ debugLog(
+ "Setting blur RenderEffect for NotificationStackScrollLayoutController with "
+ + "radius " + blurRadius);
mView.setRenderEffect(RenderEffect.createBlurEffect(
blurRadius,
blurRadius,
Shader.TileMode.CLAMP));
} else {
+ debugLog("Resetting blur RenderEffect for NotificationStackScrollLayoutController");
mView.setRenderEffect(null);
}
}
@@ -2175,4 +2189,10 @@
&& !mSwipeHelper.isSwiping();
}
}
+
+ private void debugLog(String msg) {
+ if (DEBUG) {
+ Log.d(TAG, msg);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index 5414318..f0c0301 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -405,7 +405,7 @@
public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value,
float velocity) {
mAnimatorSet.remove(animation);
- if (mAnimatorSet.isEmpty() && !canceled) {
+ if (mAnimatorSet.isEmpty()) {
onAnimationFinished();
}
mAnimationEndPool.push(this);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
index 29dbeb2..2dc5a81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
@@ -398,6 +398,14 @@
return childTag != null;
}
+ public static boolean isAnimating(View view, PhysicsProperty property) {
+ Object childTag = getChildTag(view, property.getTag());
+ if (childTag instanceof PropertyData propertyData) {
+ return propertyData.getAnimator() != null;
+ }
+ return childTag != null;
+ }
+
/**
* Start an animation to this viewstate
*
@@ -680,13 +688,18 @@
private void startYTranslationAnimation(final View child, AnimationProperties properties) {
if (mUsePhysicsForMovement) {
// Y Translation does some extra calls when it ends, so lets add a listener
- DynamicAnimation.OnAnimationEndListener endListener =
- (animation, canceled, value, velocity) -> {
- if (!canceled) {
- HeadsUpUtil.setNeedsHeadsUpDisappearAnimationAfterClick(child, false);
- onYTranslationAnimationFinished(child);
- }
- };
+ DynamicAnimation.OnAnimationEndListener endListener = null;
+ if (!isAnimatingY(child)) {
+ // Only add a listener if we're not animating yet
+ endListener =
+ (animation, canceled, value, velocity) -> {
+ if (!canceled) {
+ HeadsUpUtil.setNeedsHeadsUpDisappearAnimationAfterClick(child,
+ false);
+ onYTranslationAnimationFinished(child);
+ }
+ };
+ }
PhysicsPropertyAnimator.setProperty(child, Y_TRANSLATION, this.mYTranslation,
properties, properties.getAnimationFilter().animateY, endListener);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationStatsLoggerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationStatsLoggerImpl.kt
index 5689230..fdf06e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationStatsLoggerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationStatsLoggerImpl.kt
@@ -319,7 +319,7 @@
Notifications.Notification().apply {
uid = notification.uid
packageName = notification.packageName
- notification.instanceId?.let { instanceId = it }
+ notification.instanceId?.let { instanceId = it.id }
// TODO(b/308623704) check if we can set groupInstanceId as well
isGroupSummary = notification.isGroupSummary
section = NotificationPanelLogger.toNotificationSection(notification.bucket)
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 9d55e1d..0ea9509 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
@@ -245,7 +245,7 @@
val configurationBasedDimensions: Flow<ConfigurationBasedDimensions> =
if (SceneContainerFlag.isEnabled) {
combine(
- shadeInteractor.isShadeLayoutWide,
+ shadeModeInteractor.isShadeLayoutWide,
shadeModeInteractor.shadeMode,
configurationInteractor.onAnyConfigurationChange,
) { isShadeLayoutWide, shadeMode, _ ->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index b7eada1..207f0ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -24,6 +24,7 @@
import android.view.View
import androidx.annotation.VisibleForTesting
import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.internal.logging.InstanceId
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -165,6 +166,7 @@
// is visible (we issue [OngoingCallModel.NoCall] below in that case), so this can
// be safely made false.
isAppVisible = false,
+ notificationInstanceId = currentInfo.instanceId,
)
} else {
return OngoingCallModel.NoCall
@@ -222,6 +224,7 @@
notifModel.contentIntent,
notifModel.uid,
notifModel.appName,
+ notifModel.instanceId,
notifModel.promotedContent,
isOngoing = true,
statusBarSwipedAway = callNotificationInfo?.statusBarSwipedAway ?: false,
@@ -343,6 +346,7 @@
val intent: PendingIntent?,
val uid: Int,
val appName: String,
+ val instanceId: InstanceId?,
/**
* If the call notification also meets promoted notification criteria, this field is filled
* in with the content related to promotion. Otherwise null.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
index bed9e7c..ff9b7d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
@@ -166,6 +166,7 @@
appName = model.appName,
promotedContent = model.promotedContent,
isAppVisible = isVisible,
+ notificationInstanceId = model.instanceId,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
index 9546d37..e20d764 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone.ongoingcall.shared.model
import android.app.PendingIntent
+import com.android.internal.logging.InstanceId
import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModels
@@ -40,6 +41,8 @@
* @property promotedContent if the call notification also meets promoted notification criteria,
* this field is filled in with the content related to promotion. Otherwise null.
* @property isAppVisible whether the app to which the call belongs is currently visible.
+ * @property notificationInstanceId an optional per-chip ID used for logging. Should stay the
+ * same throughout the lifetime of a single chip.
*/
data class InCall(
val startTimeMs: Long,
@@ -49,5 +52,6 @@
val appName: String,
val promotedContent: PromotedNotificationContentModels?,
val isAppVisible: Boolean,
+ val notificationInstanceId: InstanceId?,
) : OngoingCallModel
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
index 540baba..2b13571 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
@@ -54,6 +54,7 @@
import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModelLegacy
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel
+import com.android.systemui.statusbar.chips.uievents.StatusBarChipsUiEventLogger
import com.android.systemui.statusbar.events.domain.interactor.SystemStatusEventAnimationInteractor
import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.Idle
import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips
@@ -228,6 +229,7 @@
@Background bgScope: CoroutineScope,
@Background bgDispatcher: CoroutineDispatcher,
shadeDisplaysInteractor: Provider<ShadeDisplaysInteractor>,
+ private val uiEventLogger: StatusBarChipsUiEventLogger,
) : HomeStatusBarViewModel, ExclusiveActivatable() {
private val hydrator = Hydrator(traceName = "HomeStatusBarViewModel.hydrator")
@@ -591,6 +593,7 @@
if (StatusBarPopupChips.isEnabled) {
launch { statusBarPopupChips.activate() }
}
+ launch { uiEventLogger.hydrateUiEventLogging(chipsFlow = chipsVisibilityModel) }
awaitCancellation()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
index 6d959be..b33c200 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
@@ -397,13 +397,13 @@
delayOnClickListener: Boolean,
packageContext: Context,
): Button {
- val isMagicAction =
- Flags.notificationMagicActionsTreatment() &&
+ val isAnimatedAction =
+ Flags.notificationAnimatedActionsTreatment() &&
smartActions.fromAssistant &&
- action.extras.getBoolean(Notification.Action.EXTRA_IS_MAGIC, false)
+ action.extras.getBoolean(Notification.Action.EXTRA_IS_ANIMATED, false)
val layoutRes =
- if (isMagicAction) {
- R.layout.magic_action_button
+ if (isAnimatedAction) {
+ R.layout.animated_action_button
} else {
if (notificationsRedesignTemplates()) {
R.layout.notification_2025_smart_action_button
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index bd3fead..f36f765 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -537,8 +537,10 @@
try {
JSONObject object = new JSONObject(overlayPackageJson);
String seedColorStr = Integer.toHexString(defaultSettings.seedColor.toArgb());
- object.put(OVERLAY_CATEGORY_SYSTEM_PALETTE, seedColorStr);
- object.put(OVERLAY_CATEGORY_ACCENT_COLOR, seedColorStr);
+ if(defaultSettings.colorSource == COLOR_SOURCE_PRESET){
+ object.put(OVERLAY_CATEGORY_SYSTEM_PALETTE, seedColorStr);
+ object.put(OVERLAY_CATEGORY_ACCENT_COLOR, seedColorStr);
+ }
object.put(OVERLAY_COLOR_SOURCE, defaultSettings.colorSource);
object.put(OVERLAY_CATEGORY_THEME_STYLE, Style.toString(mThemeStyle));
diff --git a/packages/SystemUI/src/com/android/systemui/underlay/OWNERS b/packages/SystemUI/src/com/android/systemui/underlay/OWNERS
new file mode 100644
index 0000000..04ac553
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/underlay/OWNERS
@@ -0,0 +1,9 @@
+# pixel team
+dupin@google.com
+klikli@google.com
+chriscui@google.com
+
+# System UI
+nijamkin@google.com
+pixel@google.com
+
diff --git a/packages/SystemUI/src/com/android/systemui/underlay/UnderlayCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/underlay/UnderlayCoreStartable.kt
new file mode 100644
index 0000000..d411a28
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/underlay/UnderlayCoreStartable.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.underlay
+
+import android.util.Log
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.underlay.shared.flag.UnderlayFlag
+import javax.inject.Inject
+
+/**
+ * Core startable for the underlay.
+ *
+ * This is responsible for starting the underlay and its dependencies.
+ */
+@SysUISingleton
+class UnderlayCoreStartable @Inject constructor() : CoreStartable {
+
+ override fun start() {
+ if (!UnderlayFlag.isEnabled) {
+ Log.d(TAG, "Underlay flag is disabled, not starting.")
+ return
+ }
+
+ Log.d(TAG, "start!")
+ }
+
+ private companion object {
+ const val TAG = "UnderlayCoreStartable"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/underlay/UnderlayModule.kt b/packages/SystemUI/src/com/android/systemui/underlay/UnderlayModule.kt
new file mode 100644
index 0000000..5b1a47f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/underlay/UnderlayModule.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.underlay
+
+import com.android.systemui.CoreStartable
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+
+@Module
+interface UnderlayModule {
+
+ @Binds
+ @IntoMap
+ @ClassKey(UnderlayCoreStartable::class)
+ fun bindUnderlayCoreStartable(startable: UnderlayCoreStartable): CoreStartable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/underlay/shared/flag/UnderlayFlag.kt b/packages/SystemUI/src/com/android/systemui/underlay/shared/flag/UnderlayFlag.kt
new file mode 100644
index 0000000..42d0486
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/underlay/shared/flag/UnderlayFlag.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE")
+
+package com.android.systemui.underlay.shared.flag
+
+import com.android.systemui.Flags.enableUnderlay
+
+/** Helper for reading or using the underlay flag state. */
+object UnderlayFlag {
+
+ @JvmStatic
+ inline val isEnabled
+ get() = enableUnderlay()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/annotations/DeprecatedSysuiVisibleForTesting.kt b/packages/SystemUI/src/com/android/systemui/util/annotations/DeprecatedSysuiVisibleForTesting.kt
new file mode 100644
index 0000000..3d808649
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/annotations/DeprecatedSysuiVisibleForTesting.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.annotations
+
+/**
+ * Given the effort in go/internal-harmful to eliminate the attempt to use Kotlin `internal` as a
+ * test-visibility marker, we are centrally moving these APIs to public, marked both with
+ * [VisibleForTesting] and this annotation. Ideally, over time, these APIs should be replaced with
+ * explicit named testing APIs (see go/internal-harmful)
+ */
+@Deprecated(
+ "Indicates an API that has been marked @VisibleForTesting, but requires further thought"
+)
+annotation class DeprecatedSysuiVisibleForTesting()
diff --git a/packages/SystemUI/src/com/android/systemui/util/display/DisplayHelper.java b/packages/SystemUI/src/com/android/systemui/util/display/DisplayHelper.java
index 757b2d9..7d1c631 100644
--- a/packages/SystemUI/src/com/android/systemui/util/display/DisplayHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/util/display/DisplayHelper.java
@@ -21,8 +21,6 @@
import android.view.Display;
import android.view.WindowManager;
-import com.android.systemui.utils.windowmanager.WindowManagerProvider;
-
import javax.inject.Inject;
/**
@@ -31,17 +29,14 @@
public class DisplayHelper {
private final Context mContext;
private final DisplayManager mDisplayManager;
- private final WindowManagerProvider mWindowManagerProvider;
/**
* Default constructor.
*/
@Inject
- public DisplayHelper(Context context, DisplayManager displayManager,
- WindowManagerProvider windowManagerProvider) {
+ public DisplayHelper(Context context, DisplayManager displayManager) {
mContext = context;
mDisplayManager = displayManager;
- mWindowManagerProvider = windowManagerProvider;
}
@@ -50,8 +45,9 @@
*/
public Rect getMaxBounds(int displayId, int windowContextType) {
final Display display = mDisplayManager.getDisplay(displayId);
- WindowManager windowManager = mWindowManagerProvider.getWindowManager(mContext
- .createDisplayContext(display).createWindowContext(windowContextType, null));
+ WindowManager windowManager = mContext
+ .createDisplayContext(display).createWindowContext(windowContextType, null)
+ .getSystemService(WindowManager.class);
return windowManager.getMaximumWindowMetrics().getBounds();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialogPlugin.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialogPlugin.kt
index 938e313..b06a3b7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialogPlugin.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialogPlugin.kt
@@ -68,6 +68,7 @@
viewModel.isShowingSafetyWarning
.mapLatest { isShowingSafetyWarning ->
if (isShowingSafetyWarning) {
+ viewModel.onSafetyWarningDialogShown()
showSafetyWarningVisibility { viewModel.onSafetyWarningDismissed() }
}
}
@@ -76,6 +77,7 @@
viewModel.csdWarning
.mapLatest { csdWarning ->
if (csdWarning != null) {
+ viewModel.onCsdWarningDialogShown()
showCsdWarningDialog(csdWarning, viewModel.csdWarningConfigModel.actions) {
viewModel.onCsdWarningDismissed()
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt
index 6d16300..87cc183 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt
@@ -70,10 +70,18 @@
val isShowingSafetyWarning: Flow<Boolean> = dialogSafetyWarningInteractor.isShowingSafetyWarning
val csdWarning: Flow<Int?> = dialogCsdWarningInteractor.csdWarning
+ fun onSafetyWarningDialogShown() {
+ dialogVisibilityInteractor.resetDismissTimeout()
+ }
+
fun onSafetyWarningDismissed() {
dialogSafetyWarningInteractor.onSafetyWarningDismissed()
}
+ fun onCsdWarningDialogShown() {
+ dialogVisibilityInteractor.resetDismissTimeout()
+ }
+
fun onCsdWarningDismissed() {
dialogCsdWarningInteractor.onCsdWarningDismissed()
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ui/compose/slider/Slider.kt b/packages/SystemUI/src/com/android/systemui/volume/ui/compose/slider/Slider.kt
index 54d2f79..0b11da3 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ui/compose/slider/Slider.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/ui/compose/slider/Slider.kt
@@ -18,9 +18,9 @@
package com.android.systemui.volume.ui.compose.slider
-import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.Spring
-import androidx.compose.animation.core.SpringSpec
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.animation.core.spring
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -32,11 +32,11 @@
import androidx.compose.material3.VerticalSlider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
@@ -53,14 +53,9 @@
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.volume.haptics.ui.VolumeHapticsConfigsProvider
import kotlin.math.round
-import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.launch
-
-private val defaultSpring =
- SpringSpec<Float>(dampingRatio = Spring.DampingRatioNoBouncy, stiffness = Spring.StiffnessHigh)
@Composable
fun Slider(
@@ -87,55 +82,31 @@
},
) {
require(stepDistance >= 0) { "stepDistance must not be negative" }
- val coroutineScope = rememberCoroutineScope()
- val snappedValue = snapValue(value, valueRange, stepDistance)
+ val snappedValue by valueState(value, isEnabled)
val hapticsViewModel = haptics.createViewModel(snappedValue, valueRange, interactionSource)
- val animatable = remember { Animatable(snappedValue) }
- var animationJob: Job? by remember { mutableStateOf(null) }
val sliderState =
remember(valueRange) { SliderState(value = snappedValue, valueRange = valueRange) }
val valueChange: (Float) -> Unit = { newValue ->
hapticsViewModel?.onValueChange(newValue)
- val snappedNewValue = snapValue(newValue, valueRange, stepDistance)
- if (animatable.targetValue != snappedNewValue) {
- onValueChanged(snappedNewValue)
- animationJob?.cancel()
- animationJob =
- coroutineScope.launch {
- animatable.animateTo(
- targetValue = snappedNewValue,
- animationSpec = defaultSpring,
- )
- }
- }
+ onValueChanged(newValue)
}
val semantics =
createSemantics(
accessibilityParams,
- animatable.targetValue,
+ snappedValue,
valueRange,
valueChange,
isEnabled,
stepDistance,
)
- LaunchedEffect(snappedValue) {
- if (!animatable.isRunning && animatable.targetValue != snappedValue) {
- animationJob?.cancel()
- animationJob =
- coroutineScope.launch {
- animatable.animateTo(targetValue = snappedValue, animationSpec = defaultSpring)
- }
- }
- }
-
sliderState.onValueChangeFinished = {
hapticsViewModel?.onValueChangeEnded()
- onValueChangeFinished?.invoke(animatable.targetValue)
+ onValueChangeFinished?.invoke(snappedValue)
}
sliderState.onValueChange = valueChange
- sliderState.value = animatable.value
+ sliderState.value = snappedValue
if (isVertical) {
VerticalSlider(
@@ -161,16 +132,26 @@
}
}
-private fun snapValue(
- value: Float,
- valueRange: ClosedFloatingPointRange<Float>,
- stepDistance: Float,
-): Float {
- if (stepDistance == 0f) {
- return value
- }
- val coercedValue = value.coerceIn(valueRange)
- return Math.round(coercedValue / stepDistance) * stepDistance
+@Composable
+private fun valueState(targetValue: Float, isEnabled: Boolean): State<Float> {
+ var prevValue by remember { mutableFloatStateOf(targetValue) }
+ var prevEnabled by remember { mutableStateOf(isEnabled) }
+ // Don't animate slider value when receive the first value and when changing isEnabled state
+ val value =
+ if (prevEnabled != isEnabled) mutableFloatStateOf(targetValue)
+ else
+ animateFloatAsState(
+ targetValue = targetValue,
+ animationSpec =
+ spring(
+ dampingRatio = Spring.DampingRatioNoBouncy,
+ stiffness = Spring.StiffnessMedium,
+ ),
+ label = "VolumeSliderValueAnimation",
+ )
+ prevValue = targetValue
+ prevEnabled = isEnabled
+ return value
}
private fun createSemantics(
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 8a447f7..60f1777 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -64,6 +64,7 @@
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -618,6 +619,28 @@
}
/**
+ * When a notification is set as important, make it a bubble
+ *
+ * @param entryAdapter the important notification.
+ */
+ public void onUserSetImportantConversation(EntryAdapter entryAdapter) {
+ if (entryAdapter.getSbn() != null
+ && entryAdapter.getSbn().getNotification().getBubbleMetadata() == null) {
+ // No bubble metadata, nothing to do.
+ return;
+ }
+ try {
+ int flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+ mBarService.onNotificationBubbleChanged(entryAdapter.getKey(), true, flags);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getMessage());
+ }
+ mShadeController.collapseShade(true);
+ // NotificationGutsManager will refresh the ENR when the guts close and update the
+ // bubble button if needed
+ }
+
+ /**
* Called when a user has indicated that an active notification should be shown as a bubble.
* <p>
* This method will collapse the shade, create the bubble without a flyout or dot, and suppress
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IMagnificationConnectionTest.java
index d3d4e24..8d9d06c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IMagnificationConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IMagnificationConnectionTest.java
@@ -49,7 +49,6 @@
import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.util.settings.SecureSettings;
-import com.android.systemui.utils.windowmanager.WindowManagerProvider;
import org.junit.Before;
import org.junit.Test;
@@ -93,8 +92,6 @@
private AccessibilityLogger mA11yLogger;
@Mock
private IWindowManager mIWindowManager;
- @Mock
- private WindowManagerProvider mWindowManagerProvider;
private IMagnificationConnection mIMagnificationConnection;
private MagnificationImpl mMagnification;
@@ -116,7 +113,7 @@
mTestableLooper.getLooper(), mContext.getMainExecutor(), mCommandQueue,
mModeSwitchesController, mSysUiState, mLauncherProxyService, mSecureSettings,
mDisplayTracker, getContext().getSystemService(DisplayManager.class),
- mA11yLogger, mIWindowManager, mAccessibilityManager, mWindowManagerProvider);
+ mA11yLogger, mIWindowManager, mAccessibilityManager);
mMagnification.mWindowMagnificationControllerSupplier =
new FakeWindowMagnificationControllerSupplier(
mContext.getSystemService(DisplayManager.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationTest.java
index ae96e8f..505432e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationTest.java
@@ -56,7 +56,6 @@
import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.util.settings.SecureSettings;
-import com.android.systemui.utils.windowmanager.WindowManagerProvider;
import org.junit.Before;
import org.junit.Test;
@@ -97,8 +96,6 @@
private AccessibilityLogger mA11yLogger;
@Mock
private IWindowManager mIWindowManager;
- @Mock
- private WindowManagerProvider mWindowManagerProvider;
@Before
public void setUp() throws Exception {
@@ -132,7 +129,7 @@
mCommandQueue, mModeSwitchesController,
mSysUiState, mLauncherProxyService, mSecureSettings, mDisplayTracker,
getContext().getSystemService(DisplayManager.class), mA11yLogger, mIWindowManager,
- getContext().getSystemService(AccessibilityManager.class), mWindowManagerProvider);
+ getContext().getSystemService(AccessibilityManager.class));
mMagnification.mWindowMagnificationControllerSupplier = new FakeControllerSupplier(
mContext.getSystemService(DisplayManager.class), mWindowMagnificationController);
mMagnification.mMagnificationSettingsSupplier = new FakeSettingsSupplier(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index 2c70249..bf79d11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -1472,7 +1472,7 @@
whenever(kosmos.udfpsUtils.onTouchOutsideOfSensorArea(any(), any(), any(), any(), any()))
.thenReturn("Direction")
- kosmos.promptViewModel.onAnnounceAccessibilityHint(
+ kosmos.promptViewModel.onUpdateAccessibilityHint(
obtainMotionEvent(MotionEvent.ACTION_HOVER_ENTER),
true,
)
@@ -1497,7 +1497,7 @@
whenever(kosmos.udfpsUtils.onTouchOutsideOfSensorArea(any(), any(), any(), any(), any()))
.thenReturn("Direction")
- kosmos.promptViewModel.onAnnounceAccessibilityHint(
+ kosmos.promptViewModel.onUpdateAccessibilityHint(
obtainMotionEvent(MotionEvent.ACTION_HOVER_ENTER),
true,
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index 061f798..2898a02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -618,6 +618,8 @@
when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
mGlobalActionsDialogLite.showOrHideDialog(true, true, null /* view */,
Display.DEFAULT_DISPLAY);
+ // Clear the dismiss override so we don't have behavior after dismissing the dialog
+ mGlobalActionsDialogLite.mDialog.setDismissOverride(null);
// Then smart lock will be disabled
verify(mLockPatternUtils).requireCredentialEntry(eq(expectedUser));
@@ -739,6 +741,8 @@
// Show dialog with keyguard showing
mGlobalActionsDialogLite.showOrHideDialog(true, true, null, Display.DEFAULT_DISPLAY);
+ // Clear the dismiss override so we don't have behavior after dismissing the dialog
+ mGlobalActionsDialogLite.mDialog.setDismissOverride(null);
assertOneItemOfType(mGlobalActionsDialogLite.mItems,
GlobalActionsDialogLite.SystemUpdateAction.class);
@@ -764,12 +768,15 @@
// Show dialog with keyguard showing
mGlobalActionsDialogLite.showOrHideDialog(false, false, null, Display.DEFAULT_DISPLAY);
+ // Clear the dismiss override so we don't have behavior after dismissing the dialog
+ mGlobalActionsDialogLite.mDialog.setDismissOverride(null);
assertNoItemsOfType(mGlobalActionsDialogLite.mItems,
GlobalActionsDialogLite.SystemUpdateAction.class);
// Hide dialog
mGlobalActionsDialogLite.showOrHideDialog(false, false, null, Display.DEFAULT_DISPLAY);
+
}
@Test
@@ -783,6 +790,8 @@
mGlobalActionsDialogLite.showOrHideDialog(false, true, null, Display.DEFAULT_DISPLAY);
mTestableLooper.processAllMessages();
+ // Clear the dismiss override so we don't have behavior after dismissing the dialog
+ mGlobalActionsDialogLite.mDialog.setDismissOverride(null);
assertThat(mGlobalActionsDialogLite.mDialog.isShowing()).isTrue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
index 78a4fbe..a530dda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
@@ -39,6 +39,7 @@
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.whenever
+import com.google.android.msdl.domain.MSDLPlayer
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.TestScope
@@ -59,6 +60,7 @@
private lateinit var featureFlags: FakeFeatureFlags
@Mock private lateinit var falsingManager: FalsingManager
@Mock private lateinit var deviceEntryIconViewModel: DeviceEntryIconViewModel
+ @Mock private lateinit var msdlPlayer: MSDLPlayer
private lateinit var underTest: DefaultDeviceEntrySection
@Before
@@ -81,6 +83,7 @@
{ mock(DeviceEntryBackgroundViewModel::class.java) },
{ falsingManager },
{ mock(VibratorHelper::class.java) },
+ { msdlPlayer },
logcatLogBuffer(),
logcatLogBuffer("blueprints"),
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
index 798aa42..eb72acc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
@@ -109,6 +109,7 @@
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
@SmallTest
@RunWith(ParameterizedAndroidJunit4.class)
@@ -151,8 +152,10 @@
private MediaDevice mMediaDevice1;
@Mock
private MediaDevice mMediaDevice2;
- @Mock
- private NearbyDevice mNearbyDevice1;
+ @Mock private MediaDevice mMediaDevice3;
+ @Mock private MediaDevice mMediaDevice4;
+ @Mock private MediaDevice mMediaDevice5;
+ @Mock private NearbyDevice mNearbyDevice1;
@Mock
private NearbyDevice mNearbyDevice2;
@Mock
@@ -1550,6 +1553,89 @@
assertThat(items.get(1).getMediaDevice().get()).isEqualTo(mMediaDevice2);
}
+ @EnableFlags(Flags.FLAG_ENABLE_OUTPUT_SWITCHER_DEVICE_GROUPING)
+ @Test
+ public void selectedDevicesAddedInSameOrderWhenRlpDoesNotExist() {
+ setUpSelectedDevicesAndOrdering();
+
+ mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
+
+ List<MediaDevice> devices =
+ mMediaSwitchingController.getMediaItemList().stream()
+ .filter(item -> item.getMediaDevice().isPresent())
+ .map(item -> item.getMediaDevice().orElse(null))
+ .collect(Collectors.toList());
+ assertThat(devices)
+ .containsExactly(
+ mMediaDevice4,
+ mMediaDevice3,
+ mMediaDevice5,
+ mMediaDevice1,
+ mMediaDevice2)
+ .inOrder();
+ }
+
+ @DisableFlags(Flags.FLAG_ENABLE_OUTPUT_SWITCHER_DEVICE_GROUPING)
+ @Test
+ public void selectedDevicesAddedInSortedOrderWhenRlpDoesNotExist() {
+ setUpSelectedDevicesAndOrdering();
+
+ mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
+
+ List<MediaDevice> devices =
+ mMediaSwitchingController.getMediaItemList().stream()
+ .filter(item -> item.getMediaDevice().isPresent())
+ .map(item -> item.getMediaDevice().orElse(null))
+ .collect(Collectors.toList());
+
+ assertThat(devices)
+ .containsExactly(
+ mMediaDevice5,
+ mMediaDevice4,
+ mMediaDevice3,
+ mMediaDevice1,
+ mMediaDevice2)
+ .inOrder();
+ }
+
+ private void setUpSelectedDevicesAndOrdering() {
+ when(mMediaDevice1.getId()).thenReturn(TEST_DEVICE_1_ID);
+ when(mMediaDevice2.getId()).thenReturn(TEST_DEVICE_2_ID);
+ when(mMediaDevice3.getId()).thenReturn(TEST_DEVICE_3_ID);
+ when(mMediaDevice4.getId()).thenReturn(TEST_DEVICE_4_ID);
+ when(mMediaDevice5.getId()).thenReturn(TEST_DEVICE_5_ID);
+ mMediaDevices.clear();
+ Collections.addAll(
+ mMediaDevices,
+ mMediaDevice2,
+ mMediaDevice1,
+ mMediaDevice4,
+ mMediaDevice3,
+ mMediaDevice5);
+ List<MediaDevice> selectedMediaDevices = new ArrayList<>();
+ Collections.addAll(selectedMediaDevices, mMediaDevice3, mMediaDevice4, mMediaDevice5);
+ doReturn(selectedMediaDevices).when(mLocalMediaManager).getSelectedMediaDevice();
+ // Sort the media devices in the order they appear in the deviceOrder list
+ List<MediaDevice> deviceOrder = new ArrayList<>();
+ Collections.addAll(
+ deviceOrder,
+ mMediaDevice1,
+ mMediaDevice2,
+ mMediaDevice3,
+ mMediaDevice4,
+ mMediaDevice5);
+ for (int i = 0; i < deviceOrder.size(); i++) {
+ for (int j = i + 1; j < deviceOrder.size(); j++) {
+ when(deviceOrder.get(i).compareTo(deviceOrder.get(j))).thenReturn(-1);
+ when(deviceOrder.get(j).compareTo(deviceOrder.get(i))).thenReturn(1);
+ }
+ }
+ when(mLocalMediaManager.isPreferenceRouteListingExist()).thenReturn(false);
+ mMediaSwitchingController.start(mCb);
+ reset(mCb);
+ mMediaSwitchingController.getMediaItemList().clear();
+ }
+
@DisableFlags(Flags.FLAG_ENABLE_OUTPUT_SWITCHER_DEVICE_GROUPING)
@Test
public void selectedDevicesAddedInReverseOrder() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
index 02a3429..41a099a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
@@ -21,10 +21,14 @@
import android.content.Intent
import android.content.IntentFilter
import android.os.PowerManager
+import android.os.powerManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.keyguard.userActivityNotifier
+import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
@@ -50,10 +54,10 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
class PowerRepositoryImplTest : SysuiTestCase() {
-
+ private val kosmos = testKosmos()
private val systemClock = FakeSystemClock()
- @Mock private lateinit var manager: PowerManager
+ val manager: PowerManager = kosmos.powerManager
@Mock private lateinit var dispatcher: BroadcastDispatcher
@Captor private lateinit var receiverCaptor: ArgumentCaptor<BroadcastReceiver>
@Captor private lateinit var filterCaptor: ArgumentCaptor<IntentFilter>
@@ -74,6 +78,7 @@
context.applicationContext,
systemClock,
dispatcher,
+ kosmos.userActivityNotifier,
)
}
@@ -198,13 +203,14 @@
systemClock.setUptimeMillis(345000)
underTest.userTouch()
+ kosmos.fakeExecutor.runAllReady()
val flagsCaptor = argumentCaptor<Int>()
verify(manager)
.userActivity(
eq(345000L),
eq(PowerManager.USER_ACTIVITY_EVENT_TOUCH),
- capture(flagsCaptor)
+ capture(flagsCaptor),
)
assertThat(flagsCaptor.value).isNotEqualTo(PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS)
assertThat(flagsCaptor.value).isNotEqualTo(PowerManager.USER_ACTIVITY_FLAG_INDIRECT)
@@ -215,13 +221,14 @@
systemClock.setUptimeMillis(345000)
underTest.userTouch(noChangeLights = true)
+ kosmos.fakeExecutor.runAllReady()
val flagsCaptor = argumentCaptor<Int>()
verify(manager)
.userActivity(
eq(345000L),
eq(PowerManager.USER_ACTIVITY_EVENT_TOUCH),
- capture(flagsCaptor)
+ capture(flagsCaptor),
)
assertThat(flagsCaptor.value).isEqualTo(PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
index ae8b52a..7728f68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -56,6 +56,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.keyguard.userActivityNotifier
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
@@ -137,6 +138,7 @@
keyguardMediaController,
lockscreenSmartspaceController,
logcatLogBuffer("GlanceableHubContainerControllerTest"),
+ kosmos.userActivityNotifier,
)
}
@@ -177,6 +179,7 @@
keyguardMediaController,
lockscreenSmartspaceController,
logcatLogBuffer("GlanceableHubContainerControllerTest"),
+ kosmos.userActivityNotifier,
)
// First call succeeds.
@@ -206,6 +209,7 @@
keyguardMediaController,
lockscreenSmartspaceController,
logcatLogBuffer("GlanceableHubContainerControllerTest"),
+ kosmos.userActivityNotifier,
)
assertThat(controller.lifecycle.currentState).isEqualTo(Lifecycle.State.INITIALIZED)
@@ -231,6 +235,7 @@
keyguardMediaController,
lockscreenSmartspaceController,
logcatLogBuffer("GlanceableHubContainerControllerTest"),
+ kosmos.userActivityNotifier,
)
// Only initView without attaching a view as we don't want the flows to start collecting
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index bc7ab9d..eae23e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -78,6 +78,8 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryAdapter;
import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
import com.android.systemui.statusbar.notification.headsup.PinnedStatus;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi;
@@ -1023,6 +1025,8 @@
mock(NotificationIconStyleProvider.class),
mock(VisualStabilityCoordinator.class),
mock(NotificationActionClickManager.class),
+ mock(HighPriorityProvider.class),
+ mock(HeadsUpManager.class),
entry);
row.setEntryAdapter(entryAdapter);
} else {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 3061842..2c800bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -89,8 +89,16 @@
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder;
+import com.android.systemui.statusbar.notification.NotificationActivityStarter;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider;
import com.android.systemui.wmshell.BubblesManager;
import com.android.systemui.wmshell.BubblesTestActivity;
@@ -127,6 +135,7 @@
private NotificationChannel mConversationChannel;
private StatusBarNotification mSbn;
private NotificationEntry mEntry;
+ private EntryAdapter mEntryAdapter;
private StatusBarNotification mBubbleSbn;
private NotificationEntry mBubbleEntry;
@Mock
@@ -228,7 +237,21 @@
notification.extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, applicationInfo);
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
notification, UserHandle.CURRENT, null, 0);
- mEntry = new NotificationEntryBuilder().setSbn(mSbn).setShortcutInfo(mShortcutInfo).build();
+ mEntry = new NotificationEntryBuilder().setSbn(mSbn).setShortcutInfo(mShortcutInfo)
+ .updateRanking(rankingBuilder -> {
+ rankingBuilder.setChannel(mNotificationChannel);
+ })
+ .build();
+ mEntryAdapter = new EntryAdapterFactoryImpl(
+ mock(NotificationActivityStarter.class),
+ mock(MetricsLogger.class),
+ mock(PeopleNotificationIdentifier.class),
+ mock(NotificationIconStyleProvider.class),
+ mock(VisualStabilityCoordinator.class),
+ mock(NotificationActionClickManager.class),
+ mock(HighPriorityProvider.class),
+ mock(HeadsUpManager.class)
+ ).create(mEntry);
PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0,
new Intent(mContext, BubblesTestActivity.class),
@@ -264,9 +287,10 @@
mMockINotificationManager,
mOnUserInteractionCallback,
TEST_PACKAGE_NAME,
- mNotificationChannel,
mEntry,
- mBubbleMetadata,
+ mEntryAdapter,
+ mEntry.getRanking(),
+ mSbn,
null,
null,
mIconFactory,
@@ -367,9 +391,10 @@
mMockINotificationManager,
mOnUserInteractionCallback,
TEST_PACKAGE_NAME,
- mNotificationChannel,
- entry,
- mBubbleMetadata,
+ mEntry,
+ mEntryAdapter,
+ mEntry.getRanking(),
+ mSbn,
null,
null,
mIconFactory,
@@ -404,9 +429,10 @@
mMockINotificationManager,
mOnUserInteractionCallback,
TEST_PACKAGE_NAME,
- mNotificationChannel,
mEntry,
- mBubbleMetadata,
+ mEntryAdapter,
+ mEntry.getRanking(),
+ mSbn,
null,
(View v, Intent intent) -> {
latch.countDown();
@@ -444,9 +470,10 @@
mMockINotificationManager,
mOnUserInteractionCallback,
TEST_PACKAGE_NAME,
- mNotificationChannel,
mEntry,
- mBubbleMetadata,
+ mEntryAdapter,
+ mEntry.getRanking(),
+ mSbn,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mConversationChannel, c);
latch.countDown();
@@ -483,9 +510,10 @@
mMockINotificationManager,
mOnUserInteractionCallback,
TEST_PACKAGE_NAME,
- mNotificationChannel,
mEntry,
- mBubbleMetadata,
+ mEntryAdapter,
+ mEntry.getRanking(),
+ mSbn,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
latch.countDown();
@@ -553,6 +581,7 @@
mConversationChannel.setImportance(IMPORTANCE_HIGH);
mConversationChannel.setImportantConversation(false);
mConversationChannel.setAllowBubbles(false);
+ mSbn.getNotification().setBubbleMetadata(null);
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
@@ -561,9 +590,10 @@
mMockINotificationManager,
mOnUserInteractionCallback,
TEST_PACKAGE_NAME,
- mNotificationChannel,
mEntry,
- null,
+ mEntryAdapter,
+ mEntry.getRanking(),
+ mSbn,
null,
null,
mIconFactory,
@@ -583,6 +613,7 @@
mConversationChannel.setImportance(IMPORTANCE_HIGH);
mConversationChannel.setImportantConversation(false);
mConversationChannel.setAllowBubbles(false);
+ mSbn.getNotification().setBubbleMetadata(null);
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
@@ -591,9 +622,10 @@
mMockINotificationManager,
mOnUserInteractionCallback,
TEST_PACKAGE_NAME,
- mNotificationChannel,
mEntry,
- null,
+ mEntryAdapter,
+ mEntry.getRanking(),
+ mSbn,
null,
null,
mIconFactory,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
index 10de866..49ebc8c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
@@ -63,13 +63,16 @@
import com.android.systemui.statusbar.NotificationPresenter
import com.android.systemui.statusbar.notification.AssistantFeedbackController
import com.android.systemui.statusbar.notification.NotificationActivityStarter
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
+import com.android.systemui.statusbar.notification.collection.provider.mockHighPriorityProvider
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.headsup.mockHeadsUpManager
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.promoted.domain.interactor.PackageDemotionInteractor
import com.android.systemui.statusbar.notification.row.icon.appIconProvider
import com.android.systemui.statusbar.notification.row.icon.notificationIconStyleProvider
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.notificationLockscreenUserManager
import com.android.systemui.statusbar.policy.deviceProvisionedController
@@ -233,14 +236,22 @@
assertEquals(View.INVISIBLE.toLong(), guts.visibility.toLong())
executor.runAllReady()
verify(guts).openControls(any<Int>(), any<Int>(), any<Boolean>(), any<Runnable>())
- verify(headsUpManager).setGutsShown(realRow!!.entry, true)
+ if (NotificationBundleUi.isEnabled) {
+ verify(kosmos.mockHeadsUpManager).setGutsShown(any<NotificationEntry>(), eq(true))
+ } else {
+ verify(headsUpManager).setGutsShown(realRow!!.entry, true)
+ }
assertEquals(View.VISIBLE.toLong(), guts.visibility.toLong())
gutsManager.closeAndSaveGuts(false, false, true, 0, 0, false)
verify(guts)
.closeControls(any<Boolean>(), any<Boolean>(), any<Int>(), any<Int>(), any<Boolean>())
verify(row, times(1)).setGutsView(any())
executor.runAllReady()
- verify(headsUpManager).setGutsShown(realRow.entry, false)
+ if (NotificationBundleUi.isEnabled) {
+ verify(kosmos.mockHeadsUpManager).setGutsShown(any<NotificationEntry>(), eq(false))
+ } else {
+ verify(headsUpManager).setGutsShown(realRow!!.entry, false)
+ }
}
@Test
@@ -385,16 +396,23 @@
@Throws(Exception::class)
fun testInitializeNotificationInfoView_highPriority() {
val notificationInfoView = mock<NotificationInfo>()
- val row = spy(helper.createRow())
- val entry = row.entry
+ val row = createTestNotificationRow()
+ val entry = row!!.entry
NotificationEntryHelper.modifyRanking(entry)
.setUserSentiment(Ranking.USER_SENTIMENT_NEGATIVE)
.setImportance(NotificationManager.IMPORTANCE_HIGH)
.build()
- whenever(row.canViewBeDismissed()).thenReturn(true)
+
whenever(highPriorityProvider.isHighPriority(entry)).thenReturn(true)
+ whenever(kosmos.mockHighPriorityProvider.isHighPriority(entry)).thenReturn(true)
val statusBarNotification = entry.sbn
- gutsManager.initializeNotificationInfo(row, notificationInfoView)
+
+ gutsManager.initializeNotificationInfo(
+ row,
+ statusBarNotification,
+ entry.ranking,
+ notificationInfoView,
+ )
verify(notificationInfoView)
.bindNotification(
any<PackageManager>(),
@@ -405,15 +423,17 @@
eq(channelEditorDialogController),
eq(packageDemotionInteractor),
eq(statusBarNotification.packageName),
- any<NotificationChannel>(),
- eq(entry),
+ eq(entry.ranking),
+ eq(statusBarNotification),
+ if (NotificationBundleUi.isEnabled) eq(null) else eq(entry),
+ if (NotificationBundleUi.isEnabled) eq(row.entryAdapter) else eq(null),
any<NotificationInfo.OnSettingsClickListener>(),
any<NotificationInfo.OnAppSettingsClickListener>(),
any<NotificationInfo.OnFeedbackClickListener>(),
any<UiEventLogger>(),
eq(true),
eq(false),
- eq(true),
+ eq(false),
eq(true),
eq(assistantFeedbackController),
any<MetricsLogger>(),
@@ -425,14 +445,19 @@
@Throws(Exception::class)
fun testInitializeNotificationInfoView_PassesAlongProvisionedState() {
val notificationInfoView = mock<NotificationInfo>()
- val row = spy(helper.createRow())
+ val row = createTestNotificationRow()
NotificationEntryHelper.modifyRanking(row.entry)
.setUserSentiment(Ranking.USER_SENTIMENT_NEGATIVE)
.build()
- whenever(row.canViewBeDismissed()).thenReturn(true)
val statusBarNotification = row.entry.sbn
val entry = row.entry
- gutsManager.initializeNotificationInfo(row, notificationInfoView)
+
+ gutsManager.initializeNotificationInfo(
+ row,
+ statusBarNotification,
+ entry.ranking,
+ notificationInfoView,
+ )
verify(notificationInfoView)
.bindNotification(
any<PackageManager>(),
@@ -443,15 +468,17 @@
eq(channelEditorDialogController),
eq(packageDemotionInteractor),
eq(statusBarNotification.packageName),
- any<NotificationChannel>(),
- eq(entry),
+ eq(entry.ranking),
+ eq(statusBarNotification),
+ if (NotificationBundleUi.isEnabled) eq(null) else eq(entry),
+ if (NotificationBundleUi.isEnabled) eq(row.entryAdapter) else eq(null),
any<NotificationInfo.OnSettingsClickListener>(),
any<NotificationInfo.OnAppSettingsClickListener>(),
any<NotificationInfo.OnFeedbackClickListener>(),
any<UiEventLogger>(),
eq(true),
eq(false),
- eq(true), /* wasShownHighPriority */
+ eq(false), /* wasShownHighPriority */
eq(false),
eq(assistantFeedbackController),
any<MetricsLogger>(),
@@ -470,7 +497,15 @@
whenever(row.canViewBeDismissed()).thenReturn(true)
val statusBarNotification = row.entry.sbn
val entry = row.entry
- gutsManager.initializeNotificationInfo(row, notificationInfoView)
+ val entryAdapter = kosmos.entryAdapterFactory.create(entry)
+ row.entryAdapter = entryAdapter
+
+ gutsManager.initializeNotificationInfo(
+ row,
+ statusBarNotification,
+ entry.ranking,
+ notificationInfoView,
+ )
verify(notificationInfoView)
.bindNotification(
any<PackageManager>(),
@@ -481,8 +516,10 @@
eq(channelEditorDialogController),
eq(packageDemotionInteractor),
eq(statusBarNotification.packageName),
- any<NotificationChannel>(),
- eq(entry),
+ eq(entry.ranking),
+ eq(statusBarNotification),
+ if (NotificationBundleUi.isEnabled) eq(null) else eq(entry),
+ if (NotificationBundleUi.isEnabled) eq(entryAdapter) else eq(null),
any<NotificationInfo.OnSettingsClickListener>(),
any<NotificationInfo.OnAppSettingsClickListener>(),
any<NotificationInfo.OnFeedbackClickListener>(),
@@ -497,7 +534,7 @@
)
}
- private fun createTestNotificationRow(): ExpandableNotificationRow? {
+ private fun createTestNotificationRow(): ExpandableNotificationRow {
val nb =
Notification.Builder(mContext, testNotificationChannel.id)
.setContentTitle("foo")
@@ -505,16 +542,10 @@
.setColor(Color.RED)
.setFlag(Notification.FLAG_CAN_COLORIZE, true)
.setSmallIcon(R.drawable.sym_def_app_icon)
- return try {
- val row = helper.createRow(nb.build())
- NotificationEntryHelper.modifyRanking(row.entry)
- .setChannel(testNotificationChannel)
- .build()
- row
- } catch (_: Exception) {
- Assert.fail()
- null
- }
+ val row = helper.createRow(nb.build())
+ NotificationEntryHelper.modifyRanking(row.entry).setChannel(testNotificationChannel).build()
+ row.entryAdapter = kosmos.entryAdapterFactory.create(row.entry)
+ return row
}
private fun setIsLockscreenOrShadeVisible(isVisible: Boolean) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionKairosAdapterTelephonySmokeTests.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionKairosAdapterTelephonySmokeTests.kt
new file mode 100644
index 0000000..5695df5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionKairosAdapterTelephonySmokeTests.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.pipeline.mobile.data.repository.prod
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.activated
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.launchKairosNetwork
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runCurrent
+import org.mockito.Mockito
+
+@OptIn(ExperimentalKairosApi::class, ExperimentalCoroutinesApi::class)
+@SmallTest
+class MobileConnectionKairosAdapterTelephonySmokeTests : MobileConnectionTelephonySmokeTestsBase() {
+
+ var job: Job? = null
+ val kairosNetwork = testScope.backgroundScope.launchKairosNetwork()
+
+ override fun recreateRepo(): MobileConnectionRepository {
+ lateinit var adapter: MobileConnectionRepositoryKairosAdapter
+ job?.cancel()
+ Mockito.clearInvocations(telephonyManager)
+ job =
+ testScope.backgroundScope.launch {
+ kairosNetwork.activateSpec {
+ val repo = activated {
+ MobileConnectionRepositoryKairosImpl(
+ MobileConnectionRepositoryTest.SUB_1_ID,
+ context,
+ subscriptionModel.toState(),
+ MobileConnectionRepositoryTest.DEFAULT_NAME_MODEL,
+ MobileConnectionRepositoryTest.SEP,
+ connectivityManager,
+ telephonyManager,
+ systemUiCarrierConfig,
+ fakeBroadcastDispatcher,
+ mobileMappings,
+ testDispatcher,
+ logger,
+ tableLogger,
+ flags,
+ )
+ }
+ adapter = MobileConnectionRepositoryKairosAdapter(repo, systemUiCarrierConfig)
+ Unit
+ }
+ }
+ testScope.runCurrent()
+ return adapter
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosAdapterTest.kt
new file mode 100644
index 0000000..0cb7c1e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosAdapterTest.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.pipeline.mobile.data.repository.prod
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.activated
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.launchKairosNetwork
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runCurrent
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+
+@OptIn(ExperimentalKairosApi::class, ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MobileConnectionRepositoryKairosAdapterTest : MobileConnectionRepositoryTest() {
+
+ var job: Job? = null
+ val kairosNetwork = testScope.backgroundScope.launchKairosNetwork()
+
+ override fun recreateRepo(): MobileConnectionRepository {
+ lateinit var adapter: MobileConnectionRepositoryKairosAdapter
+ job?.cancel()
+ Mockito.clearInvocations(telephonyManager)
+ job =
+ testScope.backgroundScope.launch {
+ kairosNetwork.activateSpec {
+ val repo = activated {
+ MobileConnectionRepositoryKairosImpl(
+ SUB_1_ID,
+ context,
+ subscriptionModel.toState(),
+ DEFAULT_NAME_MODEL,
+ SEP,
+ connectivityManager,
+ telephonyManager,
+ systemUiCarrierConfig,
+ fakeBroadcastDispatcher,
+ mobileMappings,
+ testDispatcher,
+ logger,
+ tableLogger,
+ flags,
+ )
+ }
+ adapter = MobileConnectionRepositoryKairosAdapter(repo, systemUiCarrierConfig)
+ Unit
+ }
+ }
+ testScope.runCurrent() // ensure the lateinit is set
+ return adapter
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index ed8be9b..2636195 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -88,6 +88,7 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfig
import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfigWithOverride
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.signalStrength
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.telephonyDisplayInfo
@@ -116,25 +117,49 @@
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@SmallTest
@RunWith(AndroidJUnit4::class)
-class MobileConnectionRepositoryTest : SysuiTestCase() {
- private lateinit var underTest: MobileConnectionRepositoryImpl
+class MobileConnectionRepositoryImplTest : MobileConnectionRepositoryTest() {
+ override fun recreateRepo(): MobileConnectionRepository =
+ MobileConnectionRepositoryImpl(
+ SUB_1_ID,
+ context,
+ subscriptionModel,
+ DEFAULT_NAME_MODEL,
+ SEP,
+ connectivityManager,
+ telephonyManager,
+ systemUiCarrierConfig,
+ fakeBroadcastDispatcher,
+ mobileMappings,
+ testDispatcher,
+ logger,
+ tableLogger,
+ flags,
+ testScope.backgroundScope,
+ )
+}
- private val flags =
+abstract class MobileConnectionRepositoryTest : SysuiTestCase() {
+
+ abstract fun recreateRepo(): MobileConnectionRepository
+
+ lateinit var underTest: MobileConnectionRepository
+
+ protected val flags =
FakeFeatureFlagsClassic().also { it.set(ROAMING_INDICATOR_VIA_DISPLAY_INFO, true) }
- @Mock private lateinit var connectivityManager: ConnectivityManager
- @Mock private lateinit var telephonyManager: TelephonyManager
- @Mock private lateinit var logger: MobileInputLogger
- @Mock private lateinit var tableLogger: TableLogBuffer
- @Mock private lateinit var context: Context
+ @Mock protected lateinit var connectivityManager: ConnectivityManager
+ @Mock protected lateinit var telephonyManager: TelephonyManager
+ @Mock protected lateinit var logger: MobileInputLogger
+ @Mock protected lateinit var tableLogger: TableLogBuffer
+ @Mock protected lateinit var context: Context
- private val mobileMappings = FakeMobileMappingsProxy()
- private val systemUiCarrierConfig = SystemUiCarrierConfig(SUB_1_ID, testCarrierConfig())
+ protected val mobileMappings = FakeMobileMappingsProxy()
+ protected val systemUiCarrierConfig = SystemUiCarrierConfig(SUB_1_ID, testCarrierConfig())
- private val testDispatcher = UnconfinedTestDispatcher()
- private val testScope = TestScope(testDispatcher)
+ protected val testDispatcher = UnconfinedTestDispatcher()
+ protected val testScope = TestScope(testDispatcher)
- private val subscriptionModel: MutableStateFlow<SubscriptionModel?> =
+ protected val subscriptionModel: MutableStateFlow<SubscriptionModel?> =
MutableStateFlow(
SubscriptionModel(
subscriptionId = SUB_1_ID,
@@ -144,28 +169,11 @@
)
@Before
- fun setUp() {
+ fun setUpBase() {
MockitoAnnotations.initMocks(this)
whenever(telephonyManager.subscriptionId).thenReturn(SUB_1_ID)
- underTest =
- MobileConnectionRepositoryImpl(
- SUB_1_ID,
- context,
- subscriptionModel,
- DEFAULT_NAME_MODEL,
- SEP,
- connectivityManager,
- telephonyManager,
- systemUiCarrierConfig,
- fakeBroadcastDispatcher,
- mobileMappings,
- testDispatcher,
- logger,
- tableLogger,
- flags,
- testScope.backgroundScope,
- )
+ underTest = recreateRepo()
}
@Test
@@ -400,6 +408,7 @@
fun carrierId_initialValueCaptured() =
testScope.runTest {
whenever(telephonyManager.simCarrierId).thenReturn(1234)
+ underTest = recreateRepo()
var latest: Int? = null
val job = underTest.carrierId.onEach { latest = it }.launchIn(this)
@@ -430,6 +439,8 @@
@Test
fun carrierNetworkChange() =
testScope.runTest {
+ underTest = recreateRepo()
+
var latest: Boolean? = null
val job = underTest.carrierNetworkChangeActive.onEach { latest = it }.launchIn(this)
@@ -622,24 +633,7 @@
flags.set(ROAMING_INDICATOR_VIA_DISPLAY_INFO, true)
// Re-create the repository, because the flag is read at init
- underTest =
- MobileConnectionRepositoryImpl(
- SUB_1_ID,
- context,
- subscriptionModel,
- DEFAULT_NAME_MODEL,
- SEP,
- connectivityManager,
- telephonyManager,
- systemUiCarrierConfig,
- fakeBroadcastDispatcher,
- mobileMappings,
- testDispatcher,
- logger,
- tableLogger,
- flags,
- testScope.backgroundScope,
- )
+ underTest = recreateRepo()
var latest: Boolean? = null
val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
@@ -671,24 +665,7 @@
flags.set(ROAMING_INDICATOR_VIA_DISPLAY_INFO, false)
// Re-create the repository, because the flag is read at init
- underTest =
- MobileConnectionRepositoryImpl(
- SUB_1_ID,
- context,
- subscriptionModel,
- DEFAULT_NAME_MODEL,
- SEP,
- connectivityManager,
- telephonyManager,
- systemUiCarrierConfig,
- fakeBroadcastDispatcher,
- mobileMappings,
- testDispatcher,
- logger,
- tableLogger,
- flags,
- testScope.backgroundScope,
- )
+ underTest = recreateRepo()
var latest: Boolean? = null
val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
@@ -1441,14 +1418,14 @@
}
companion object {
- private const val SUB_1_ID = 1
+ const val SUB_1_ID = 1
- private const val DEFAULT_NAME = "Fake Mobile Network"
- private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
- private const val SEP = "-"
+ const val DEFAULT_NAME = "Fake Mobile Network"
+ val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
+ const val SEP = "-"
- private const val SPN = "testSpn"
- private const val DATA_SPN = "testDataSpn"
- private const val PLMN = "testPlmn"
+ const val SPN = "testSpn"
+ const val DATA_SPN = "testDataSpn"
+ const val PLMN = "testPlmn"
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
index 6f21e79..caa6e21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
@@ -42,6 +42,7 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.getTelephonyCallbackForType
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.signalStrength
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
@@ -92,47 +93,53 @@
*/
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@SmallTest
-class MobileConnectionTelephonySmokeTests : SysuiTestCase() {
- private lateinit var underTest: MobileConnectionRepositoryImpl
+class MobileConnectionTelephonySmokeTests : MobileConnectionTelephonySmokeTestsBase() {
+ override fun recreateRepo(): MobileConnectionRepository =
+ MobileConnectionRepositoryImpl(
+ SUB_1_ID,
+ context,
+ subscriptionModel,
+ DEFAULT_NAME,
+ SEP,
+ connectivityManager,
+ telephonyManager,
+ systemUiCarrierConfig,
+ fakeBroadcastDispatcher,
+ mobileMappings,
+ testDispatcher,
+ logger,
+ tableLogger,
+ flags,
+ testScope.backgroundScope,
+ )
+}
- private val flags =
+abstract class MobileConnectionTelephonySmokeTestsBase : SysuiTestCase() {
+ protected lateinit var underTest: MobileConnectionRepository
+
+ protected val flags =
FakeFeatureFlagsClassic().also { it.set(Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO, true) }
- @Mock private lateinit var connectivityManager: ConnectivityManager
- @Mock private lateinit var telephonyManager: TelephonyManager
- @Mock private lateinit var logger: MobileInputLogger
- @Mock private lateinit var tableLogger: TableLogBuffer
- @Mock private lateinit var subscriptionModel: StateFlow<SubscriptionModel?>
+ @Mock protected lateinit var connectivityManager: ConnectivityManager
+ @Mock protected lateinit var telephonyManager: TelephonyManager
+ @Mock protected lateinit var logger: MobileInputLogger
+ @Mock protected lateinit var tableLogger: TableLogBuffer
+ @Mock protected lateinit var subscriptionModel: StateFlow<SubscriptionModel?>
- private val mobileMappings = FakeMobileMappingsProxy()
- private val systemUiCarrierConfig = SystemUiCarrierConfig(SUB_1_ID, testCarrierConfig())
+ protected val mobileMappings = FakeMobileMappingsProxy()
+ protected val systemUiCarrierConfig = SystemUiCarrierConfig(SUB_1_ID, testCarrierConfig())
- private val testDispatcher = UnconfinedTestDispatcher()
- private val testScope = TestScope(testDispatcher)
+ protected val testDispatcher = UnconfinedTestDispatcher()
+ protected val testScope = TestScope(testDispatcher)
+
+ abstract fun recreateRepo(): MobileConnectionRepository
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
whenever(telephonyManager.subscriptionId).thenReturn(SUB_1_ID)
- underTest =
- MobileConnectionRepositoryImpl(
- SUB_1_ID,
- context,
- subscriptionModel,
- DEFAULT_NAME,
- SEP,
- connectivityManager,
- telephonyManager,
- systemUiCarrierConfig,
- fakeBroadcastDispatcher,
- mobileMappings,
- testDispatcher,
- logger,
- tableLogger,
- flags,
- testScope.backgroundScope,
- )
+ underTest = recreateRepo()
}
@Test
@@ -329,9 +336,9 @@
}
companion object {
- private const val SUB_1_ID = 1
+ const val SUB_1_ID = 1
- private val DEFAULT_NAME = NetworkNameModel.Default("default name")
- private const val SEP = "-"
+ val DEFAULT_NAME = NetworkNameModel.Default("default name")
+ const val SEP = "-"
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosAdapterTest.kt
new file mode 100644
index 0000000..65849ae
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosAdapterTest.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.pipeline.mobile.data.repository.prod
+
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.launchKairosNetwork
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeCarrierConfigRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepositoryKairosAdapter
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runCurrent
+import org.mockito.Mockito
+import org.mockito.kotlin.mock
+
+@OptIn(ExperimentalKairosApi::class, ExperimentalCoroutinesApi::class)
+@SmallTest
+// This is required because our [SubscriptionManager.OnSubscriptionsChangedListener] uses a looper
+// to run the callback and this makes the looper place nicely with TestScope etc.
+@TestableLooper.RunWithLooper
+class MobileConnectionsRepositoryKairosAdapterTest :
+ MobileConnectionsRepositoryTest<MobileConnectionsRepositoryKairosAdapter>() {
+
+ var job: Job? = null
+ val kairosNetwork = testScope.backgroundScope.launchKairosNetwork()
+
+ override fun recreateRepo(): MobileConnectionsRepositoryKairosAdapter {
+ val carrierConfigRepo = FakeCarrierConfigRepository()
+ lateinit var connectionsRepo: MobileConnectionsRepositoryKairosImpl
+ connectionsRepo =
+ MobileConnectionsRepositoryKairosImpl(
+ connectivityRepository = connectivityRepository,
+ subscriptionManager = subscriptionManager,
+ subscriptionManagerProxy = subscriptionManagerProxy,
+ telephonyManager = telephonyManager,
+ logger = logger,
+ tableLogger = summaryLogger,
+ mobileMappingsProxy = mobileMappings,
+ broadcastDispatcher = fakeBroadcastDispatcher,
+ context = context,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
+ airplaneModeRepository = airplaneModeRepository,
+ wifiRepository = wifiRepository,
+ keyguardUpdateMonitor = updateMonitor,
+ dumpManager = mock(),
+ mobileRepoFactory = {
+ MobileConnectionRepositoryKairosFactoryImpl(
+ context = context,
+ connectionsRepo = connectionsRepo,
+ logFactory = logBufferFactory,
+ carrierConfigRepo = carrierConfigRepo,
+ telephonyManager = telephonyManager,
+ mobileRepoFactory = {
+ subId,
+ mobileLogger,
+ subscriptionModel,
+ defaultNetworkName,
+ networkNameSeparator,
+ systemUiCarrierConfig,
+ telephonyManager ->
+ MobileConnectionRepositoryKairosImpl(
+ subId = subId,
+ context = context,
+ subscriptionModel = subscriptionModel,
+ defaultNetworkName = defaultNetworkName,
+ networkNameSeparator = networkNameSeparator,
+ connectivityManager = connectivityManager,
+ telephonyManager = telephonyManager,
+ systemUiCarrierConfig = systemUiCarrierConfig,
+ broadcastDispatcher = fakeBroadcastDispatcher,
+ mobileMappingsProxy = mobileMappings,
+ bgDispatcher = testDispatcher,
+ logger = logger,
+ tableLogBuffer = mobileLogger,
+ flags = flags,
+ )
+ },
+ mergedRepoFactory =
+ CarrierMergedConnectionRepositoryKairos.Factory(
+ telephonyManager,
+ wifiRepository,
+ ),
+ )
+ },
+ )
+
+ val adapter =
+ MobileConnectionsRepositoryKairosAdapter(
+ kairosRepo = connectionsRepo,
+ kairosNetwork = kairosNetwork,
+ scope = testScope.backgroundScope,
+ connectivityRepository = connectivityRepository,
+ context = context,
+ carrierConfigRepo = carrierConfigRepo,
+ )
+
+ job?.cancel()
+ Mockito.clearInvocations(telephonyManager)
+ job =
+ testScope.backgroundScope.launch {
+ kairosNetwork.activateSpec {
+ connectionsRepo.run { activate() }
+ adapter.run { activate() }
+ }
+ }
+ testScope.runCurrent() // ensure everything is activated
+ return adapter
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index d1d6e27..c3662880 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -37,6 +37,7 @@
import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
import android.telephony.TelephonyCallback
import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
+import android.telephony.TelephonyCallback.EmergencyCallbackModeListener
import android.telephony.TelephonyManager
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
@@ -58,6 +59,7 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.carrierConfigRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.tableBufferLogName
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
@@ -78,6 +80,7 @@
import com.android.wifitrackerlib.WifiEntry
import com.android.wifitrackerlib.WifiPickerTracker
import com.google.common.truth.Truth.assertThat
+import java.time.Duration
import java.util.UUID
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
@@ -93,6 +96,7 @@
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
+import org.mockito.Mockito.atLeast
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.any
@@ -104,34 +108,311 @@
// This is required because our [SubscriptionManager.OnSubscriptionsChangedListener] uses a looper
// to run the callback and this makes the looper place nicely with TestScope etc.
@TestableLooper.RunWithLooper
-class MobileConnectionsRepositoryTest : SysuiTestCase() {
+class MobileConnectionsRepositoryImplTest :
+ MobileConnectionsRepositoryTest<MobileConnectionsRepositoryImpl>() {
+ override fun recreateRepo() =
+ MobileConnectionsRepositoryImpl(
+ connectivityRepository = connectivityRepository,
+ subscriptionManager = subscriptionManager,
+ subscriptionManagerProxy = subscriptionManagerProxy,
+ telephonyManager = telephonyManager,
+ logger = logger,
+ tableLogger = summaryLogger,
+ mobileMappingsProxy = mobileMappings,
+ broadcastDispatcher = fakeBroadcastDispatcher,
+ context = context,
+ bgDispatcher = testDispatcher,
+ scope = testScope.backgroundScope,
+ mainDispatcher = testDispatcher,
+ airplaneModeRepository = airplaneModeRepository,
+ wifiRepository = wifiRepository,
+ fullMobileRepoFactory = fullConnectionFactory,
+ keyguardUpdateMonitor = updateMonitor,
+ dumpManager = mock(),
+ )
+
+ @Test
+ fun activeDataSentBeforeSubscriptionList_subscriptionReusesActiveDataRepo() =
+ testScope.runTest {
+ val activeRepo by collectLastValue(underTest.activeMobileDataRepository)
+ collectLastValue(underTest.subscriptions)
+
+ // GIVEN active repo is updated before the subscription list updates
+ getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+ .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+
+ assertThat(activeRepo).isNotNull()
+
+ // GIVEN the subscription list is then updated which includes the active data sub id
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_2))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ // WHEN requesting a connection repository for the subscription
+ val newRepo = underTest.getRepoForSubId(SUB_2_ID)
+
+ // THEN the newly request repo has been cached and reused
+ assertThat(activeRepo).isSameInstanceAs(newRepo)
+ }
+
+ @Test
+ fun testConnectionRepository_invalidSubId_doesNotThrow() =
+ testScope.runTest {
+ underTest.getRepoForSubId(SUB_1_ID)
+ // No exception
+ }
+
+ @Test
+ fun testConnectionRepository_carrierMergedAndMobileSubs_usesCorrectRepos() =
+ testScope.runTest {
+ collectLastValue(underTest.subscriptions)
+
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ setWifiState(isCarrierMerged = true)
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1, SUB_CM))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ val carrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
+ val mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
+ assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
+ assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
+ }
+
+ @Test
+ fun testSubscriptions_subNoLongerCarrierMerged_repoUpdates() =
+ testScope.runTest {
+ collectLastValue(underTest.subscriptions)
+
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ setWifiState(isCarrierMerged = true)
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1, SUB_CM))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ val carrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
+ var mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
+ assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
+ assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
+
+ // WHEN the wifi network updates to be not carrier merged
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_ACTIVE)
+ setWifiState(isCarrierMerged = false)
+ runCurrent()
+
+ // THEN the repos update
+ val noLongerCarrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
+ mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
+ assertThat(noLongerCarrierMergedRepo.getIsCarrierMerged()).isFalse()
+ assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
+ }
+
+ @Test
+ fun testSubscriptions_subBecomesCarrierMerged_repoUpdates() =
+ testScope.runTest {
+ collectLastValue(underTest.subscriptions)
+
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_ACTIVE)
+ setWifiState(isCarrierMerged = false)
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1, SUB_CM))
+ getSubscriptionCallback().onSubscriptionsChanged()
+ runCurrent()
+
+ val notYetCarrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
+ var mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
+ assertThat(notYetCarrierMergedRepo.getIsCarrierMerged()).isFalse()
+ assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
+
+ // WHEN the wifi network updates to be carrier merged
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ setWifiState(isCarrierMerged = true)
+ runCurrent()
+
+ // THEN the repos update
+ val carrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
+ mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
+ assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
+ assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
+ }
+
+ @Test
+ @Ignore("b/333912012")
+ fun testConnectionCache_clearsInvalidSubscriptions() =
+ testScope.runTest {
+ collectLastValue(underTest.subscriptions)
+
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1, SUB_2))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ // Get repos to trigger caching
+ val repo1 = underTest.getRepoForSubId(SUB_1_ID)
+ val repo2 = underTest.getRepoForSubId(SUB_2_ID)
+
+ assertThat(underTest.getSubIdRepoCache())
+ .containsExactly(SUB_1_ID, repo1, SUB_2_ID, repo2)
+
+ // SUB_2 disappears
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ assertThat(underTest.getSubIdRepoCache()).containsExactly(SUB_1_ID, repo1)
+ }
+
+ @Test
+ @Ignore("b/333912012")
+ fun testConnectionCache_clearsInvalidSubscriptions_includingCarrierMerged() =
+ testScope.runTest {
+ collectLastValue(underTest.subscriptions)
+
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ setWifiState(isCarrierMerged = true)
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1, SUB_2, SUB_CM))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ // Get repos to trigger caching
+ val repo1 = underTest.getRepoForSubId(SUB_1_ID)
+ val repo2 = underTest.getRepoForSubId(SUB_2_ID)
+ val repoCarrierMerged = underTest.getRepoForSubId(SUB_CM_ID)
+
+ assertThat(underTest.getSubIdRepoCache())
+ .containsExactly(SUB_1_ID, repo1, SUB_2_ID, repo2, SUB_CM_ID, repoCarrierMerged)
+
+ // SUB_2 and SUB_CM disappear
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ assertThat(underTest.getSubIdRepoCache()).containsExactly(SUB_1_ID, repo1)
+ }
+
+ /** Regression test for b/261706421 */
+ @Test
+ @Ignore("b/333912012")
+ fun testConnectionsCache_clearMultipleSubscriptionsAtOnce_doesNotThrow() =
+ testScope.runTest {
+ collectLastValue(underTest.subscriptions)
+
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1, SUB_2))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ // Get repos to trigger caching
+ val repo1 = underTest.getRepoForSubId(SUB_1_ID)
+ val repo2 = underTest.getRepoForSubId(SUB_2_ID)
+
+ assertThat(underTest.getSubIdRepoCache())
+ .containsExactly(SUB_1_ID, repo1, SUB_2_ID, repo2)
+
+ // All subscriptions disappear
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList).thenReturn(listOf())
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ assertThat(underTest.getSubIdRepoCache()).isEmpty()
+ }
+
+ @Test
+ fun getRepoForSubId_activeDataSubIdIsRequestedBeforeSubscriptionsUpdate() =
+ testScope.runTest {
+ var latestActiveRepo: MobileConnectionRepository? = null
+ collectLastValue(
+ underTest.activeMobileDataSubscriptionId.filterNotNull().onEach {
+ latestActiveRepo = underTest.getRepoForSubId(it)
+ }
+ )
+
+ val latestSubscriptions by collectLastValue(underTest.subscriptions)
+
+ // Active data subscription id is sent, but no subscription change has been posted yet
+ getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+ .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+
+ // Subscriptions list is empty
+ assertThat(latestSubscriptions).isEmpty()
+ // getRepoForSubId does not throw
+ assertThat(latestActiveRepo).isNotNull()
+ }
+
+ @Test
+ fun testConnectionsCache_keepsReposCached() =
+ testScope.runTest {
+ // Collect subscriptions to start the job
+ collectLastValue(underTest.subscriptions)
+
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ val repo1_1 = underTest.getRepoForSubId(SUB_1_ID)
+
+ // All subscriptions disappear
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList).thenReturn(listOf())
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ // Sub1 comes back
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ val repo1_2 = underTest.getRepoForSubId(SUB_1_ID)
+
+ assertThat(repo1_1).isSameInstanceAs(repo1_2)
+ }
+
+ @Test
+ fun testConnectionsCache_doesNotDropReferencesThatHaveBeenRealized() =
+ testScope.runTest {
+ // Collect subscriptions to start the job
+ collectLastValue(underTest.subscriptions)
+
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ // Client grabs a reference to a repository, but doesn't keep it around
+ underTest.getRepoForSubId(SUB_1_ID)
+
+ // All subscriptions disappear
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList).thenReturn(listOf())
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ val repo1 = underTest.getRepoForSubId(SUB_1_ID)
+
+ assertThat(repo1).isNotNull()
+ }
+}
+
+abstract class MobileConnectionsRepositoryTest<T : MobileConnectionsRepository> : SysuiTestCase() {
private val kosmos = testKosmos()
- private val flags =
+ protected val flags =
FakeFeatureFlagsClassic().also { it.set(Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO, true) }
private lateinit var connectionFactory: MobileConnectionRepositoryImpl.Factory
private lateinit var carrierMergedFactory: CarrierMergedConnectionRepository.Factory
- private lateinit var fullConnectionFactory: FullMobileConnectionRepository.Factory
- private lateinit var connectivityRepository: ConnectivityRepository
- private lateinit var airplaneModeRepository: FakeAirplaneModeRepository
- private lateinit var wifiRepository: WifiRepository
+ protected lateinit var fullConnectionFactory: FullMobileConnectionRepository.Factory
+ protected lateinit var connectivityRepository: ConnectivityRepository
+ protected lateinit var airplaneModeRepository: FakeAirplaneModeRepository
+ protected lateinit var wifiRepository: WifiRepository
private lateinit var carrierConfigRepository: CarrierConfigRepository
- @Mock private lateinit var connectivityManager: ConnectivityManager
- @Mock private lateinit var subscriptionManager: SubscriptionManager
- @Mock private lateinit var telephonyManager: TelephonyManager
- @Mock private lateinit var logger: MobileInputLogger
- private val summaryLogger = logcatTableLogBuffer(kosmos, "summaryLogger")
- @Mock private lateinit var logBufferFactory: TableLogBufferFactory
- @Mock private lateinit var updateMonitor: KeyguardUpdateMonitor
+ @Mock protected lateinit var connectivityManager: ConnectivityManager
+ @Mock protected lateinit var subscriptionManager: SubscriptionManager
+ @Mock protected lateinit var telephonyManager: TelephonyManager
+ @Mock protected lateinit var logger: MobileInputLogger
+ protected val summaryLogger = logcatTableLogBuffer(kosmos, "summaryLogger")
+ @Mock protected lateinit var logBufferFactory: TableLogBufferFactory
+ @Mock protected lateinit var updateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var wifiManager: WifiManager
@Mock private lateinit var wifiPickerTrackerFactory: WifiPickerTrackerFactory
@Mock private lateinit var wifiPickerTracker: WifiPickerTracker
private val wifiTableLogBuffer = logcatTableLogBuffer(kosmos, "wifiTableLog")
- private val mobileMappings = FakeMobileMappingsProxy()
- private val subscriptionManagerProxy = FakeSubscriptionManagerProxy()
+ protected val mobileMappings = FakeMobileMappingsProxy()
+ protected val subscriptionManagerProxy = FakeSubscriptionManagerProxy()
private val mainExecutor = FakeExecutor(FakeSystemClock())
private val wifiLogBuffer = LogBuffer("wifi", maxSize = 100, logcatEchoTracker = mock())
private val wifiPickerTrackerCallback =
@@ -139,10 +420,10 @@
private val vcnTransportInfo = VcnTransportInfo.Builder().build()
private val userRepository = kosmos.fakeUserRepository
- private val testDispatcher = StandardTestDispatcher()
- private val testScope = TestScope(testDispatcher)
+ protected val testDispatcher = StandardTestDispatcher()
+ protected val testScope = TestScope(testDispatcher)
- private lateinit var underTest: MobileConnectionsRepositoryImpl
+ protected lateinit var underTest: T
@Before
fun setUp() {
@@ -237,30 +518,13 @@
carrierMergedRepoFactory = carrierMergedFactory,
)
- underTest =
- MobileConnectionsRepositoryImpl(
- connectivityRepository,
- subscriptionManager,
- subscriptionManagerProxy,
- telephonyManager,
- logger,
- summaryLogger,
- mobileMappings,
- fakeBroadcastDispatcher,
- context,
- /* bgDispatcher = */ testDispatcher,
- testScope.backgroundScope,
- /* mainDispatcher = */ testDispatcher,
- airplaneModeRepository,
- wifiRepository,
- fullConnectionFactory,
- updateMonitor,
- mock(),
- )
+ underTest = recreateRepo()
testScope.runCurrent()
}
+ abstract fun recreateRepo(): T
+
@Test
fun testSubscriptions_initiallyEmpty() =
testScope.runTest {
@@ -410,9 +674,17 @@
fun activeRepo_updatesWithActiveDataId() =
testScope.runTest {
val latest by collectLastValue(underTest.activeMobileDataRepository)
+ runCurrent()
- getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
- .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_2))
+ getSubscriptionCallbacks().forEach { it.onSubscriptionsChanged() }
+ runCurrent()
+
+ getTelephonyCallbacksForType<ActiveDataSubscriptionIdListener>().forEach {
+ it.onActiveDataSubscriptionIdChanged(SUB_2_ID)
+ }
+ runCurrent()
assertThat(latest?.subId).isEqualTo(SUB_2_ID)
}
@@ -422,6 +694,10 @@
testScope.runTest {
val latest by collectLastValue(underTest.activeMobileDataRepository)
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_2))
+ getSubscriptionCallbacks().forEach { it.onSubscriptionsChanged() }
+
getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
.onActiveDataSubscriptionIdChanged(SUB_2_ID)
@@ -437,60 +713,15 @@
/** Regression test for b/268146648. */
fun activeSubIdIsSetBeforeSubscriptionsAreUpdated_doesNotThrow() =
testScope.runTest {
- val activeRepo by collectLastValue(underTest.activeMobileDataRepository)
+ val activeRepo = collectLastValue(underTest.activeMobileDataRepository)
val subscriptions by collectLastValue(underTest.subscriptions)
- getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
- .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+ getTelephonyCallbacksForType<ActiveDataSubscriptionIdListener>().forEach {
+ it.onActiveDataSubscriptionIdChanged(SUB_2_ID)
+ }
assertThat(subscriptions).isEmpty()
- assertThat(activeRepo).isNotNull()
- }
-
- @Test
- fun getRepoForSubId_activeDataSubIdIsRequestedBeforeSubscriptionsUpdate() =
- testScope.runTest {
- var latestActiveRepo: MobileConnectionRepository? = null
- collectLastValue(
- underTest.activeMobileDataSubscriptionId.filterNotNull().onEach {
- latestActiveRepo = underTest.getRepoForSubId(it)
- }
- )
-
- val latestSubscriptions by collectLastValue(underTest.subscriptions)
-
- // Active data subscription id is sent, but no subscription change has been posted yet
- getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
- .onActiveDataSubscriptionIdChanged(SUB_2_ID)
-
- // Subscriptions list is empty
- assertThat(latestSubscriptions).isEmpty()
- // getRepoForSubId does not throw
- assertThat(latestActiveRepo).isNotNull()
- }
-
- @Test
- fun activeDataSentBeforeSubscriptionList_subscriptionReusesActiveDataRepo() =
- testScope.runTest {
- val activeRepo by collectLastValue(underTest.activeMobileDataRepository)
- collectLastValue(underTest.subscriptions)
-
- // GIVEN active repo is updated before the subscription list updates
- getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
- .onActiveDataSubscriptionIdChanged(SUB_2_ID)
-
- assertThat(activeRepo).isNotNull()
-
- // GIVEN the subscription list is then updated which includes the active data sub id
- whenever(subscriptionManager.completeActiveSubscriptionInfoList)
- .thenReturn(listOf(SUB_2))
- getSubscriptionCallback().onSubscriptionsChanged()
-
- // WHEN requesting a connection repository for the subscription
- val newRepo = underTest.getRepoForSubId(SUB_2_ID)
-
- // THEN the newly request repo has been cached and reused
- assertThat(activeRepo).isSameInstanceAs(newRepo)
+ activeRepo.invoke() // does not throw
}
@Test
@@ -501,6 +732,7 @@
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1))
getSubscriptionCallback().onSubscriptionsChanged()
+ runCurrent()
val repo1 = underTest.getRepoForSubId(SUB_1_ID)
val repo2 = underTest.getRepoForSubId(SUB_1_ID)
@@ -525,80 +757,6 @@
assertThat(repo1).isSameInstanceAs(repo2)
}
- @Test
- fun testConnectionRepository_carrierMergedAndMobileSubs_usesCorrectRepos() =
- testScope.runTest {
- collectLastValue(underTest.subscriptions)
-
- getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
- setWifiState(isCarrierMerged = true)
- whenever(subscriptionManager.completeActiveSubscriptionInfoList)
- .thenReturn(listOf(SUB_1, SUB_CM))
- getSubscriptionCallback().onSubscriptionsChanged()
-
- val carrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
- val mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
- assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
- assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
- }
-
- @Test
- fun testSubscriptions_subNoLongerCarrierMerged_repoUpdates() =
- testScope.runTest {
- collectLastValue(underTest.subscriptions)
-
- getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
- setWifiState(isCarrierMerged = true)
- whenever(subscriptionManager.completeActiveSubscriptionInfoList)
- .thenReturn(listOf(SUB_1, SUB_CM))
- getSubscriptionCallback().onSubscriptionsChanged()
-
- val carrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
- var mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
- assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
- assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
-
- // WHEN the wifi network updates to be not carrier merged
- getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_ACTIVE)
- setWifiState(isCarrierMerged = false)
- runCurrent()
-
- // THEN the repos update
- val noLongerCarrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
- mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
- assertThat(noLongerCarrierMergedRepo.getIsCarrierMerged()).isFalse()
- assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
- }
-
- @Test
- fun testSubscriptions_subBecomesCarrierMerged_repoUpdates() =
- testScope.runTest {
- collectLastValue(underTest.subscriptions)
-
- getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_ACTIVE)
- setWifiState(isCarrierMerged = false)
- whenever(subscriptionManager.completeActiveSubscriptionInfoList)
- .thenReturn(listOf(SUB_1, SUB_CM))
- getSubscriptionCallback().onSubscriptionsChanged()
- runCurrent()
-
- val notYetCarrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
- var mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
- assertThat(notYetCarrierMergedRepo.getIsCarrierMerged()).isFalse()
- assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
-
- // WHEN the wifi network updates to be carrier merged
- getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
- setWifiState(isCarrierMerged = true)
- runCurrent()
-
- // THEN the repos update
- val carrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
- mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
- assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
- assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
- }
-
@SuppressLint("UnspecifiedRegisterReceiverFlag")
@Test
fun testDeviceEmergencyCallState_eagerlyChecksState() =
@@ -674,139 +832,6 @@
}
@Test
- @Ignore("b/333912012")
- fun testConnectionCache_clearsInvalidSubscriptions() =
- testScope.runTest {
- collectLastValue(underTest.subscriptions)
-
- whenever(subscriptionManager.completeActiveSubscriptionInfoList)
- .thenReturn(listOf(SUB_1, SUB_2))
- getSubscriptionCallback().onSubscriptionsChanged()
-
- // Get repos to trigger caching
- val repo1 = underTest.getRepoForSubId(SUB_1_ID)
- val repo2 = underTest.getRepoForSubId(SUB_2_ID)
-
- assertThat(underTest.getSubIdRepoCache())
- .containsExactly(SUB_1_ID, repo1, SUB_2_ID, repo2)
-
- // SUB_2 disappears
- whenever(subscriptionManager.completeActiveSubscriptionInfoList)
- .thenReturn(listOf(SUB_1))
- getSubscriptionCallback().onSubscriptionsChanged()
-
- assertThat(underTest.getSubIdRepoCache()).containsExactly(SUB_1_ID, repo1)
- }
-
- @Test
- @Ignore("b/333912012")
- fun testConnectionCache_clearsInvalidSubscriptions_includingCarrierMerged() =
- testScope.runTest {
- collectLastValue(underTest.subscriptions)
-
- getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
- setWifiState(isCarrierMerged = true)
- whenever(subscriptionManager.completeActiveSubscriptionInfoList)
- .thenReturn(listOf(SUB_1, SUB_2, SUB_CM))
- getSubscriptionCallback().onSubscriptionsChanged()
-
- // Get repos to trigger caching
- val repo1 = underTest.getRepoForSubId(SUB_1_ID)
- val repo2 = underTest.getRepoForSubId(SUB_2_ID)
- val repoCarrierMerged = underTest.getRepoForSubId(SUB_CM_ID)
-
- assertThat(underTest.getSubIdRepoCache())
- .containsExactly(SUB_1_ID, repo1, SUB_2_ID, repo2, SUB_CM_ID, repoCarrierMerged)
-
- // SUB_2 and SUB_CM disappear
- whenever(subscriptionManager.completeActiveSubscriptionInfoList)
- .thenReturn(listOf(SUB_1))
- getSubscriptionCallback().onSubscriptionsChanged()
-
- assertThat(underTest.getSubIdRepoCache()).containsExactly(SUB_1_ID, repo1)
- }
-
- /** Regression test for b/261706421 */
- @Test
- @Ignore("b/333912012")
- fun testConnectionsCache_clearMultipleSubscriptionsAtOnce_doesNotThrow() =
- testScope.runTest {
- collectLastValue(underTest.subscriptions)
-
- whenever(subscriptionManager.completeActiveSubscriptionInfoList)
- .thenReturn(listOf(SUB_1, SUB_2))
- getSubscriptionCallback().onSubscriptionsChanged()
-
- // Get repos to trigger caching
- val repo1 = underTest.getRepoForSubId(SUB_1_ID)
- val repo2 = underTest.getRepoForSubId(SUB_2_ID)
-
- assertThat(underTest.getSubIdRepoCache())
- .containsExactly(SUB_1_ID, repo1, SUB_2_ID, repo2)
-
- // All subscriptions disappear
- whenever(subscriptionManager.completeActiveSubscriptionInfoList).thenReturn(listOf())
- getSubscriptionCallback().onSubscriptionsChanged()
-
- assertThat(underTest.getSubIdRepoCache()).isEmpty()
- }
-
- @Test
- fun testConnectionsCache_keepsReposCached() =
- testScope.runTest {
- // Collect subscriptions to start the job
- collectLastValue(underTest.subscriptions)
-
- whenever(subscriptionManager.completeActiveSubscriptionInfoList)
- .thenReturn(listOf(SUB_1))
- getSubscriptionCallback().onSubscriptionsChanged()
-
- val repo1_1 = underTest.getRepoForSubId(SUB_1_ID)
-
- // All subscriptions disappear
- whenever(subscriptionManager.completeActiveSubscriptionInfoList).thenReturn(listOf())
- getSubscriptionCallback().onSubscriptionsChanged()
-
- // Sub1 comes back
- whenever(subscriptionManager.completeActiveSubscriptionInfoList)
- .thenReturn(listOf(SUB_1))
- getSubscriptionCallback().onSubscriptionsChanged()
-
- val repo1_2 = underTest.getRepoForSubId(SUB_1_ID)
-
- assertThat(repo1_1).isSameInstanceAs(repo1_2)
- }
-
- @Test
- fun testConnectionsCache_doesNotDropReferencesThatHaveBeenRealized() =
- testScope.runTest {
- // Collect subscriptions to start the job
- collectLastValue(underTest.subscriptions)
-
- whenever(subscriptionManager.completeActiveSubscriptionInfoList)
- .thenReturn(listOf(SUB_1))
- getSubscriptionCallback().onSubscriptionsChanged()
-
- // Client grabs a reference to a repository, but doesn't keep it around
- underTest.getRepoForSubId(SUB_1_ID)
-
- // All subscriptions disappear
- whenever(subscriptionManager.completeActiveSubscriptionInfoList).thenReturn(listOf())
- getSubscriptionCallback().onSubscriptionsChanged()
-
- val repo1 = underTest.getRepoForSubId(SUB_1_ID)
-
- assertThat(repo1).isNotNull()
- }
-
- @Test
- fun testConnectionRepository_invalidSubId_doesNotThrow() =
- testScope.runTest {
- underTest.getRepoForSubId(SUB_1_ID)
- // No exception
- }
-
- @Test
fun connectionRepository_logBufferContainsSubIdInItsName() =
testScope.runTest {
collectLastValue(underTest.subscriptions)
@@ -814,6 +839,7 @@
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1, SUB_2))
getSubscriptionCallback().onSubscriptionsChanged()
+ runCurrent()
// Get repos to trigger creation
underTest.getRepoForSubId(SUB_1_ID)
@@ -848,15 +874,27 @@
fun defaultDataSubId_fetchesInitialValueOnStart() =
testScope.runTest {
subscriptionManagerProxy.defaultDataSubId = 2
+ underTest = recreateRepo()
+
val latest by collectLastValue(underTest.defaultDataSubId)
assertThat(latest).isEqualTo(2)
}
+ private fun setDefaultDataSubId(subId: Int) {
+ subscriptionManagerProxy.defaultDataSubId = subId
+ fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ context,
+ Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED).apply {
+ putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId)
+ },
+ )
+ }
+
@Test
fun defaultDataSubId_filtersOutInvalidSubIds() =
testScope.runTest {
- subscriptionManagerProxy.defaultDataSubId = INVALID_SUBSCRIPTION_ID
+ setDefaultDataSubId(INVALID_SUBSCRIPTION_ID)
val latest by collectLastValue(underTest.defaultDataSubId)
assertThat(latest).isNull()
@@ -865,15 +903,12 @@
@Test
fun defaultDataSubId_filtersOutInvalidSubIds_fromValidToInvalid() =
testScope.runTest {
- subscriptionManagerProxy.defaultDataSubId = 2
+ setDefaultDataSubId(2)
val latest by collectLastValue(underTest.defaultDataSubId)
assertThat(latest).isEqualTo(2)
- val intent =
- Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
- .putExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
- fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent)
+ setDefaultDataSubId(INVALID_SUBSCRIPTION_ID)
assertThat(latest).isNull()
}
@@ -881,7 +916,7 @@
@Test
fun defaultDataSubId_fetchesCurrentOnRestart() =
testScope.runTest {
- subscriptionManagerProxy.defaultDataSubId = 2
+ setDefaultDataSubId(2)
var latest: Int? = null
var job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
runCurrent()
@@ -894,7 +929,7 @@
latest = null
- subscriptionManagerProxy.defaultDataSubId = 1
+ setDefaultDataSubId(1)
job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
runCurrent()
@@ -1281,26 +1316,7 @@
// The initial value will be fetched when the repo is created, so we need to override
// the resources and then re-create the repo.
- underTest =
- MobileConnectionsRepositoryImpl(
- connectivityRepository,
- subscriptionManager,
- subscriptionManagerProxy,
- telephonyManager,
- logger,
- summaryLogger,
- mobileMappings,
- fakeBroadcastDispatcher,
- context,
- testDispatcher,
- testScope.backgroundScope,
- testDispatcher,
- airplaneModeRepository,
- wifiRepository,
- fullConnectionFactory,
- updateMonitor,
- mock(),
- )
+ underTest = recreateRepo()
val latest by collectLastValue(underTest.defaultDataSubRatConfig)
@@ -1428,6 +1444,12 @@
assertThat(underTest.getIsAnySimSecure()).isFalse()
whenever(updateMonitor.isSimPinSecure).thenReturn(true)
+ org.mockito.kotlin
+ .argumentCaptor<KeyguardUpdateMonitorCallback>()
+ .apply { verify(updateMonitor, atLeast(0)).registerCallback(capture()) }
+ .allValues
+ .forEach { it.onSimStateChanged(0, 0, 0) }
+ runCurrent()
assertThat(underTest.getIsAnySimSecure()).isTrue()
}
@@ -1447,19 +1469,26 @@
testScope.runTest {
whenever(telephonyManager.emergencyCallbackMode).thenReturn(true)
+ getTelephonyCallbacksForType<EmergencyCallbackModeListener>().forEach {
+ it.onCallbackModeStarted(
+ TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS,
+ Duration.ZERO,
+ 0,
+ )
+ }
runCurrent()
assertThat(underTest.isInEcmMode()).isTrue()
}
- private fun TestScope.getDefaultNetworkCallback(): ConnectivityManager.NetworkCallback {
+ protected fun TestScope.getDefaultNetworkCallback(): ConnectivityManager.NetworkCallback {
runCurrent()
val callbackCaptor = argumentCaptor<ConnectivityManager.NetworkCallback>()
verify(connectivityManager).registerDefaultNetworkCallback(callbackCaptor.capture())
return callbackCaptor.value!!
}
- private fun setWifiState(isCarrierMerged: Boolean) {
+ protected fun setWifiState(isCarrierMerged: Boolean) {
if (isCarrierMerged) {
val mergedEntry =
mock<MergedCarrierEntry>().apply {
@@ -1481,7 +1510,7 @@
wifiPickerTrackerCallback.value.onWifiEntriesChanged()
}
- private fun TestScope.getSubscriptionCallback():
+ protected fun TestScope.getSubscriptionCallback():
SubscriptionManager.OnSubscriptionsChangedListener {
runCurrent()
val callbackCaptor = argumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener>()
@@ -1490,25 +1519,39 @@
return callbackCaptor.value!!
}
- private fun TestScope.getTelephonyCallbacks(): List<TelephonyCallback> {
+ protected fun TestScope.getSubscriptionCallbacks():
+ List<SubscriptionManager.OnSubscriptionsChangedListener> {
runCurrent()
- val callbackCaptor = argumentCaptor<TelephonyCallback>()
- verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
+ val callbackCaptor = argumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener>()
+ verify(subscriptionManager, atLeast(0))
+ .addOnSubscriptionsChangedListener(any(), callbackCaptor.capture())
return callbackCaptor.allValues
}
- private inline fun <reified T> TestScope.getTelephonyCallbackForType(): T {
- val cbs = this.getTelephonyCallbacks().filterIsInstance<T>()
+ fun TestScope.getTelephonyCallbacks(): List<TelephonyCallback> {
+ runCurrent()
+ val callbackCaptor = argumentCaptor<TelephonyCallback>()
+ verify(telephonyManager, atLeast(0))
+ .registerTelephonyCallback(any(), callbackCaptor.capture())
+ return callbackCaptor.allValues
+ }
+
+ inline fun <reified T> TestScope.getTelephonyCallbackForType(): T {
+ val cbs = getTelephonyCallbacksForType<T>()
assertThat(cbs.size).isEqualTo(1)
return cbs[0]
}
+ inline fun <reified T> TestScope.getTelephonyCallbacksForType(): List<T> {
+ return getTelephonyCallbacks().filterIsInstance<T>()
+ }
+
companion object {
// Subscription 1
- private const val SUB_1_ID = 1
+ const val SUB_1_ID = 1
private const val SUB_1_NAME = "Carrier $SUB_1_ID"
private val GROUP_1 = ParcelUuid(UUID.randomUUID())
- private val SUB_1 =
+ val SUB_1 =
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_1_ID)
whenever(it.groupUuid).thenReturn(GROUP_1)
@@ -1524,10 +1567,10 @@
)
// Subscription 2
- private const val SUB_2_ID = 2
+ const val SUB_2_ID = 2
private const val SUB_2_NAME = "Carrier $SUB_2_ID"
private val GROUP_2 = ParcelUuid(UUID.randomUUID())
- private val SUB_2 =
+ val SUB_2 =
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_2_ID)
whenever(it.groupUuid).thenReturn(GROUP_2)
@@ -1552,6 +1595,7 @@
whenever(it.subscriptionId).thenReturn(SUB_3_ID_GROUPED)
whenever(it.groupUuid).thenReturn(GROUP_ID_3_4)
whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
+ whenever(it.carrierName).thenReturn("")
}
// Subscription 4
@@ -1561,17 +1605,18 @@
whenever(it.subscriptionId).thenReturn(SUB_4_ID_GROUPED)
whenever(it.groupUuid).thenReturn(GROUP_ID_3_4)
whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
+ whenever(it.carrierName).thenReturn("")
}
// Subs 3 and 4 are considered to be in the same group ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
private const val NET_ID = 123
- private val NETWORK = mock<Network>().apply { whenever(getNetId()).thenReturn(NET_ID) }
+ val NETWORK = mock<Network>().apply { whenever(getNetId()).thenReturn(NET_ID) }
// Carrier merged subscription
- private const val SUB_CM_ID = 5
+ const val SUB_CM_ID = 5
private const val SUB_CM_NAME = "Carrier $SUB_CM_ID"
- private val SUB_CM =
+ val SUB_CM =
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_CM_ID)
whenever(it.carrierName).thenReturn(SUB_CM_NAME)
@@ -1590,7 +1635,7 @@
whenever(this.isCarrierMerged).thenReturn(true)
whenever(this.subscriptionId).thenReturn(SUB_CM_ID)
}
- private val WIFI_NETWORK_CAPS_CM =
+ val WIFI_NETWORK_CAPS_CM =
mock<NetworkCapabilities>().also {
whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
whenever(it.transportInfo).thenReturn(WIFI_INFO_CM)
@@ -1602,7 +1647,7 @@
whenever(this.isPrimary).thenReturn(true)
whenever(this.isCarrierMerged).thenReturn(false)
}
- private val WIFI_NETWORK_CAPS_ACTIVE =
+ val WIFI_NETWORK_CAPS_ACTIVE =
mock<NetworkCapabilities>().also {
whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
whenever(it.transportInfo).thenReturn(WIFI_INFO_ACTIVE)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCaseExt.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCaseExt.kt
index c86ba6c..ebf89e9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCaseExt.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCaseExt.kt
@@ -19,14 +19,40 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testCase
import com.android.systemui.kosmos.useStandardTestDispatcher
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
-fun SysuiTestCase.testKosmos(): Kosmos = Kosmos().apply { testCase = this@testKosmos }
+/**
+ * This definition, which uses standard dispatcher, is eventually going away.
+ *
+ * If you are calling this method, and want the new default behavior, call `testKosmosNew`, and you
+ * will be migrated to the new behavior (unconfined dispatcher). If you want to maintain the old
+ * behavior, directly call testKosmosNew().useStandardTestDispatcher().
+ *
+ * The migration will proceed in multiple steps:
+ * 1. All calls to testKosmos will be converted to testKosmosLegacy, maybe over several CLs.
+ * 2. When there are zero references to testKosmos, it will be briefly deleted
+ * 3. A new testKosmos will be introduced that uses unconfined test dispatcher
+ * 4. All callers to testKosmosNew that have been introduced since step 1 will be migrated to this
+ * new definition of testKosmos
+ * 5. testKosmosNew will be deleted
+ * 6. Over time, test authors will be encouraged to migrate away from testKosmosLegacy
+ *
+ * For details, see go/thetiger
+ */
+// TODO(b/342622417)
+fun SysuiTestCase.testKosmos(): Kosmos = testKosmosLegacy()
+
+/**
+ * Create a new Kosmos instance using the unconfined test dispatcher. See migration notes on
+ * [testKosmos]
+ */
+fun SysuiTestCase.testKosmosNew(): Kosmos =
+ Kosmos().apply { testCase = this@testKosmosNew }.useUnconfinedTestDispatcher()
/**
* This should not be called directly. Instead, you can use:
- * - testKosmos() to use the default dispatcher (which will soon be unconfined, see go/thetiger)
- * - testKosmos().useStandardTestDispatcher() to explicitly choose the standard dispatcher
- * - testKosmos().useUnconfinedTestDispatcher() to explicitly choose the unconfined dispatcher
+ * - testKosmosNew().useStandardTestDispatcher() to explicitly choose the standard dispatcher
+ * - testKosmosNew() to explicitly choose the unconfined dispatcher (which is the new sysui default)
*
* For details, see go/thetiger
*/
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/posturing/data/repository/FakePosturingRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/posturing/data/repository/FakePosturingRepository.kt
index 8a597a6..47b1bf5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/posturing/data/repository/FakePosturingRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/posturing/data/repository/FakePosturingRepository.kt
@@ -16,18 +16,18 @@
package com.android.systemui.communal.posturing.data.repository
-import com.android.systemui.communal.posturing.shared.model.PosturedState
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
+import com.android.systemui.communal.posturing.data.model.PositionState
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.asSharedFlow
class FakePosturingRepository : PosturingRepository {
- private val _postured = MutableStateFlow<PosturedState>(PosturedState.Unknown)
+ private val _postured = MutableSharedFlow<PositionState>()
- override val posturedState: StateFlow<PosturedState> = _postured.asStateFlow()
+ override val positionState: Flow<PositionState> = _postured.asSharedFlow()
- fun setPosturedState(state: PosturedState) {
- _postured.value = state
+ suspend fun emitPositionState(state: PositionState) {
+ _postured.emit(state)
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractorKosmos.kt
index 53c9c64..792346eb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractorKosmos.kt
@@ -18,6 +18,27 @@
import com.android.systemui.communal.posturing.data.repository.posturingRepository
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.advanceTimeBy
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.runCurrent
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.log.logcatLogBuffer
+import com.android.systemui.util.sensors.asyncSensorManager
+import com.android.systemui.util.time.systemClock
val Kosmos.posturingInteractor by
- Kosmos.Fixture<PosturingInteractor> { PosturingInteractor(repository = posturingRepository) }
+ Kosmos.Fixture<PosturingInteractor> {
+ PosturingInteractor(
+ repository = posturingRepository,
+ asyncSensorManager = asyncSensorManager,
+ applicationScope = applicationCoroutineScope,
+ bgDispatcher = testDispatcher,
+ logBuffer = logcatLogBuffer("PosturingInteractor"),
+ clock = systemClock,
+ )
+ }
+
+fun Kosmos.advanceTimeBySlidingWindowAndRun() {
+ advanceTimeBy(PosturingInteractor.SLIDING_WINDOW_DURATION)
+ runCurrent()
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/cursorposition/domain/data/repository/TestCursorPositionRepositoryInstanceProvider.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/cursorposition/domain/data/repository/TestCursorPositionRepositoryInstanceProvider.kt
new file mode 100644
index 0000000..9f998f3
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/cursorposition/domain/data/repository/TestCursorPositionRepositoryInstanceProvider.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.cursorposition.domain.data.repository
+
+import android.os.Handler
+import com.android.app.displaylib.PerDisplayInstanceProviderWithTeardown
+import com.android.systemui.cursorposition.data.repository.InputEventListenerBuilder
+import com.android.systemui.cursorposition.data.repository.InputMonitorBuilder
+import com.android.systemui.cursorposition.data.repository.SingleDisplayCursorPositionRepository
+import com.android.systemui.cursorposition.data.repository.SingleDisplayCursorPositionRepositoryImpl
+
+class TestCursorPositionRepositoryInstanceProvider(
+ private val handler: Handler,
+ private val listenerBuilder: InputEventListenerBuilder,
+ private val inputMonitorBuilder: InputMonitorBuilder,
+) : PerDisplayInstanceProviderWithTeardown<SingleDisplayCursorPositionRepository> {
+
+ override fun destroyInstance(instance: SingleDisplayCursorPositionRepository) {
+ instance.destroy()
+ }
+
+ override fun createInstance(displayId: Int): SingleDisplayCursorPositionRepository {
+ return SingleDisplayCursorPositionRepositoryImpl(
+ displayId,
+ handler,
+ listenerBuilder,
+ inputMonitorBuilder,
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorKosmos.kt
index 015d4dd..19c4226 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorKosmos.kt
@@ -16,6 +16,7 @@
package com.android.systemui.deviceentry.domain.interactor
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.Kosmos
val Kosmos.authRippleInteractor by
@@ -23,5 +24,6 @@
AuthRippleInteractor(
deviceEntrySourceInteractor = deviceEntrySourceInteractor,
deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
+ keyguardInteractor = keyguardInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt
index cd4b09c..91c3da4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt
@@ -21,6 +21,7 @@
import com.android.systemui.dump.dumpManager
import com.android.systemui.keyevent.domain.interactor.keyEventInteractor
import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.util.time.systemClock
@@ -36,6 +37,7 @@
keyEventInteractor = keyEventInteractor,
logger = biometricUnlockLogger,
powerInteractor = powerInteractor,
+ keyguardInteractor = keyguardInteractor,
systemClock = systemClock,
dumpManager = dumpManager,
)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
index 739f6c2..8465345 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
@@ -20,8 +20,10 @@
import android.content.applicationContext
import android.content.res.mainResources
import android.hardware.input.fakeInputManager
+import android.os.fakeExecutorHandler
import android.view.windowManager
import com.android.systemui.broadcast.broadcastDispatcher
+import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.keyboard.shortcut.data.repository.AppLaunchDataRepository
import com.android.systemui.keyboard.shortcut.data.repository.CustomInputGesturesRepository
import com.android.systemui.keyboard.shortcut.data.repository.CustomShortcutCategoriesRepository
@@ -29,9 +31,11 @@
import com.android.systemui.keyboard.shortcut.data.repository.InputGestureDataAdapter
import com.android.systemui.keyboard.shortcut.data.repository.InputGestureMaps
import com.android.systemui.keyboard.shortcut.data.repository.ShortcutCategoriesUtils
+import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperCustomizationModeRepository
import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperInputDeviceRepository
import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperStateRepository
import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperTestHelper
+import com.android.systemui.keyboard.shortcut.data.repository.UserVisibleAppsRepository
import com.android.systemui.keyboard.shortcut.data.source.AccessibilityShortcutsSource
import com.android.systemui.keyboard.shortcut.data.source.AppCategoriesShortcutsSource
import com.android.systemui.keyboard.shortcut.data.source.CurrentAppShortcutsSource
@@ -41,7 +45,9 @@
import com.android.systemui.keyboard.shortcut.data.source.SystemShortcutsSource
import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutCustomizationInteractor
import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperCategoriesInteractor
+import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperCustomizationModeInteractor
import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperStateInteractor
+import com.android.systemui.keyboard.shortcut.fakes.FakeLauncherApps
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperExclusions
import com.android.systemui.keyboard.shortcut.ui.ShortcutCustomizationDialogStarter
import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutCustomizationViewModel
@@ -196,6 +202,14 @@
}
}
+val Kosmos.shortcutHelperCustomizationModeRepository by
+ Kosmos.Fixture { ShortcutHelperCustomizationModeRepository(shortcutHelperStateRepository) }
+
+val Kosmos.shortcutHelperCustomizationModeInteractor by
+ Kosmos.Fixture {
+ ShortcutHelperCustomizationModeInteractor(shortcutHelperCustomizationModeRepository)
+ }
+
val Kosmos.shortcutHelperViewModel by
Kosmos.Fixture {
ShortcutHelperViewModel(
@@ -206,6 +220,7 @@
testDispatcher,
shortcutHelperStateInteractor,
shortcutHelperCategoriesInteractor,
+ shortcutHelperCustomizationModeInteractor,
)
}
@@ -236,3 +251,15 @@
}
}
}
+
+val Kosmos.fakeLauncherApps by Kosmos.Fixture { FakeLauncherApps() }
+
+val Kosmos.userVisibleAppsRepository by
+ Kosmos.Fixture {
+ UserVisibleAppsRepository(
+ userTracker,
+ fakeExecutor,
+ fakeExecutorHandler,
+ fakeLauncherApps.launcherApps,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/fakes/FakeLauncherApps.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/fakes/FakeLauncherApps.kt
new file mode 100644
index 0000000..f0c4a35
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/fakes/FakeLauncherApps.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.keyboard.shortcut.fakes
+
+import android.content.ComponentName
+import android.content.pm.LauncherActivityInfo
+import android.content.pm.LauncherApps
+import android.os.UserHandle
+import org.mockito.kotlin.any
+import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.mock
+
+class FakeLauncherApps {
+
+ private val activityListPerUser: MutableMap<Int, MutableList<LauncherActivityInfo>> =
+ mutableMapOf()
+ private val callbacks: MutableList<LauncherApps.Callback> = mutableListOf()
+
+ val launcherApps: LauncherApps = mock {
+ on { getActivityList(anyOrNull(), any()) }
+ .then {
+ val userHandle = it.getArgument<UserHandle>(1)
+
+ activityListPerUser.getOrDefault(userHandle.identifier, emptyList())
+ }
+ on { registerCallback(any(), any()) }
+ .then {
+ val callback = it.getArgument<LauncherApps.Callback>(0)
+
+ callbacks.add(callback)
+ }
+ on { unregisterCallback(any()) }
+ .then {
+ val callback = it.getArgument<LauncherApps.Callback>(0)
+
+ callbacks.remove(callback)
+ }
+ }
+
+ fun installPackageForUser(packageName: String, className: String, userHandle: UserHandle) {
+ val launcherActivityInfo: LauncherActivityInfo = mock {
+ on { componentName }
+ .thenReturn(ComponentName(/* pkg= */ packageName, /* cls= */ className))
+ }
+
+ if (!activityListPerUser.containsKey(userHandle.identifier)) {
+ activityListPerUser[userHandle.identifier] = mutableListOf()
+ }
+
+ activityListPerUser[userHandle.identifier]!!.add(launcherActivityInfo)
+
+ callbacks.forEach { it.onPackageAdded(/* pkg= */ packageName, userHandle) }
+ }
+
+ fun uninstallPackageForUser(packageName: String, className: String, userHandle: UserHandle) {
+ activityListPerUser[userHandle.identifier]?.removeIf {
+ it.componentName.packageName == packageName && it.componentName.className == className
+ }
+
+ callbacks.forEach { it.onPackageRemoved(/* pkg= */ packageName, userHandle) }
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/UserActivityNotifierKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/UserActivityNotifierKosmos.kt
new file mode 100644
index 0000000..91d1501
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/UserActivityNotifierKosmos.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard
+
+import android.os.powerManager
+import com.android.keyguard.UserActivityNotifier
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.kosmos.Kosmos
+
+var Kosmos.userActivityNotifier by
+ Kosmos.Fixture {
+ UserActivityNotifier(uiBgExecutor = fakeExecutor, powerManager = powerManager)
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt
index 406b5cb..19aaa28 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt
@@ -22,14 +22,14 @@
import com.android.systemui.keyguard.data.repository.keyguardSmartspaceSection
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
-import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.shade.domain.interactor.shadeModeInteractor
val Kosmos.keyguardBlueprintInteractor by
Kosmos.Fixture {
KeyguardBlueprintInteractor(
keyguardBlueprintRepository = keyguardBlueprintRepository,
applicationScope = applicationCoroutineScope,
- shadeInteractor = shadeInteractor,
+ shadeModeInteractor = shadeModeInteractor,
configurationInteractor = configurationInteractor,
fingerprintPropertyInteractor = fingerprintPropertyInteractor,
smartspaceSection = keyguardSmartspaceSection,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelKosmos.kt
index 76e2cc8..384a071 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelKosmos.kt
@@ -19,7 +19,7 @@
import com.android.systemui.keyguard.domain.interactor.keyguardSmartspaceInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
-import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.shade.domain.interactor.shadeModeInteractor
import com.android.systemui.util.mockito.mock
val Kosmos.keyguardSmartspaceViewModel by
@@ -29,6 +29,6 @@
smartspaceController = mock(),
keyguardClockViewModel = keyguardClockViewModel,
smartspaceInteractor = keyguardSmartspaceInteractor,
- shadeInteractor = shadeInteractor,
+ shadeModeInteractor = shadeModeInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt
index 0443329..ae28022 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt
@@ -25,6 +25,7 @@
import com.android.systemui.coroutines.collectValues
import com.android.systemui.kosmos.Kosmos.Fixture
import kotlin.coroutines.CoroutineContext
+import kotlin.time.Duration
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
@@ -32,6 +33,7 @@
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import org.mockito.kotlin.verify
@@ -72,6 +74,8 @@
fun Kosmos.runCurrent() = testScope.runCurrent()
+fun Kosmos.advanceTimeBy(duration: Duration) = testScope.advanceTimeBy(duration)
+
fun <T> Kosmos.collectLastValue(flow: Flow<T>) = testScope.collectLastValue(flow)
fun <T> Kosmos.collectValues(flow: Flow<T>): FlowValue<List<T>> = testScope.collectValues(flow)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelKosmos.kt
index 2f3d3c3..ba1c598 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelKosmos.kt
@@ -17,6 +17,7 @@
package com.android.systemui.media.controls.ui.viewmodel
import android.content.applicationContext
+import com.android.internal.logging.InstanceId
import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testDispatcher
@@ -31,5 +32,9 @@
backgroundExecutor = fakeExecutor,
interactor = mediaControlInteractor,
logger = mediaUiEventLogger,
+ instanceId = InstanceId.fakeInstanceId(-1),
+ onAdded = {},
+ onRemoved = {},
+ onUpdated = {},
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
index 32a3050..d06d4ca 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
@@ -69,7 +69,6 @@
userSetupRepository = userSetupRepository,
userSwitcherInteractor = userSwitcherInteractor,
baseShadeInteractor = baseShadeInteractor,
- shadeModeInteractor = shadeModeInteractor,
)
}
var Kosmos.notificationElement: NotificationShadeElement by
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayContentViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayContentViewModelKosmos.kt
index 55e35f2..23251d2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayContentViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayContentViewModelKosmos.kt
@@ -22,6 +22,7 @@
import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayContentViewModel
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.shade.domain.interactor.shadeModeInteractor
import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModelFactory
@@ -33,6 +34,7 @@
notificationsPlaceholderViewModelFactory = notificationsPlaceholderViewModelFactory,
sceneInteractor = sceneInteractor,
shadeInteractor = shadeInteractor,
+ shadeModeInteractor = shadeModeInteractor,
disableFlagsInteractor = disableFlagsInteractor,
mediaCarouselInteractor = mediaCarouselInteractor,
activeNotificationsInteractor = activeNotificationsInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelKosmos.kt
index ab61a3e..553e876 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelKosmos.kt
@@ -22,6 +22,7 @@
import com.android.systemui.plugins.activityStarter
import com.android.systemui.statusbar.chips.call.domain.interactor.callChipInteractor
import com.android.systemui.statusbar.chips.statusBarChipsLogger
+import com.android.systemui.statusbar.chips.uievents.statusBarChipsUiEventLogger
import com.android.systemui.util.time.fakeSystemClock
val Kosmos.callChipViewModel: CallChipViewModel by
@@ -33,5 +34,6 @@
systemClock = fakeSystemClock,
activityStarter = activityStarter,
logger = statusBarChipsLogger,
+ uiEventLogger = statusBarChipsUiEventLogger,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelKosmos.kt
index c7dfd5c..7e8dfa7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelKosmos.kt
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.chips.casttootherdevice.ui.viewmodel
import android.content.applicationContext
-import com.android.systemui.animation.dialogTransitionAnimator
import com.android.systemui.animation.mockDialogTransitionAnimator
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
@@ -25,6 +24,7 @@
import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.mediaProjectionChipInteractor
import com.android.systemui.statusbar.chips.mediaprojection.ui.view.endMediaProjectionDialogHelper
import com.android.systemui.statusbar.chips.statusBarChipsLogger
+import com.android.systemui.statusbar.chips.uievents.statusBarChipsUiEventLogger
import com.android.systemui.util.time.fakeSystemClock
val Kosmos.castToOtherDeviceChipViewModel: CastToOtherDeviceChipViewModel by
@@ -38,5 +38,6 @@
endMediaProjectionDialogHelper = endMediaProjectionDialogHelper,
dialogTransitionAnimator = mockDialogTransitionAnimator,
logger = statusBarChipsLogger,
+ uiEventLogger = statusBarChipsUiEventLogger,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelKosmos.kt
index c2a6f7d..0cd83d3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelKosmos.kt
@@ -24,6 +24,7 @@
import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.screenRecordChipInteractor
import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.shareToAppChipViewModel
import com.android.systemui.statusbar.chips.statusBarChipsLogger
+import com.android.systemui.statusbar.chips.uievents.statusBarChipsUiEventLogger
import com.android.systemui.util.time.fakeSystemClock
val Kosmos.screenRecordChipViewModel: ScreenRecordChipViewModel by
@@ -37,5 +38,6 @@
dialogTransitionAnimator = mockDialogTransitionAnimator,
systemClock = fakeSystemClock,
logger = statusBarChipsLogger,
+ uiEventLogger = statusBarChipsUiEventLogger,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelKosmos.kt
index 0770009..c8d2b5d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelKosmos.kt
@@ -23,6 +23,7 @@
import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.mediaProjectionChipInteractor
import com.android.systemui.statusbar.chips.mediaprojection.ui.view.endMediaProjectionDialogHelper
import com.android.systemui.statusbar.chips.statusBarChipsLogger
+import com.android.systemui.statusbar.chips.uievents.statusBarChipsUiEventLogger
import com.android.systemui.util.time.fakeSystemClock
val Kosmos.shareToAppChipViewModel: ShareToAppChipViewModel by
@@ -35,5 +36,6 @@
endMediaProjectionDialogHelper = endMediaProjectionDialogHelper,
dialogTransitionAnimator = mockDialogTransitionAnimator,
logger = statusBarChipsLogger,
+ uiEventLogger = statusBarChipsUiEventLogger,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/uievents/StatusBarChipsUiEventLoggerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/uievents/StatusBarChipsUiEventLoggerKosmos.kt
new file mode 100644
index 0000000..a3ba29b
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/uievents/StatusBarChipsUiEventLoggerKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.uievents
+
+import com.android.internal.logging.uiEventLoggerFake
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.statusBarChipsUiEventLogger: StatusBarChipsUiEventLogger by
+ Kosmos.Fixture { StatusBarChipsUiEventLogger(uiEventLoggerFake) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorKosmos.kt
index 1a5c61a..aba4942 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorKosmos.kt
@@ -32,6 +32,7 @@
import com.android.systemui.statusbar.notification.visibilityLocationProvider
import com.android.systemui.statusbar.policy.keyguardStateController
import com.android.systemui.util.kotlin.JavaAdapter
+import org.mockito.kotlin.mock
var Kosmos.visualStabilityCoordinator: VisualStabilityCoordinator by
Kosmos.Fixture {
@@ -54,3 +55,5 @@
visualStabilityCoordinatorLogger,
)
}
+
+var Kosmos.mockVisualStabilityCoordinator: VisualStabilityCoordinator by Kosmos.Fixture { mock() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProviderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProviderKosmos.kt
new file mode 100644
index 0000000..aa30828
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProviderKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.provider
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.mockHighPriorityProvider: HighPriorityProvider by Kosmos.Fixture { mock() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt
index 4af4e80..db27e7f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt
@@ -18,6 +18,7 @@
import android.app.PendingIntent
import android.graphics.drawable.Icon
+import com.android.internal.logging.InstanceId
import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModels
import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
@@ -42,7 +43,7 @@
statusBarIcon: Icon? = null,
statusBarChipIcon: StatusBarIconView? = null,
uid: Int = 0,
- instanceId: Int? = null,
+ instanceId: InstanceId? = null,
isGroupSummary: Boolean = false,
packageName: String = "pkg",
appName: String = "appName",
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt
index 067e420..4b69970 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt
@@ -19,7 +19,9 @@
import com.android.internal.logging.metricsLogger
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl
-import com.android.systemui.statusbar.notification.collection.coordinator.visualStabilityCoordinator
+import com.android.systemui.statusbar.notification.collection.coordinator.mockVisualStabilityCoordinator
+import com.android.systemui.statusbar.notification.collection.provider.mockHighPriorityProvider
+import com.android.systemui.statusbar.notification.headsup.mockHeadsUpManager
import com.android.systemui.statusbar.notification.mockNotificationActivityStarter
import com.android.systemui.statusbar.notification.people.peopleNotificationIdentifier
import com.android.systemui.statusbar.notification.row.icon.notificationIconStyleProvider
@@ -31,7 +33,9 @@
metricsLogger,
peopleNotificationIdentifier,
notificationIconStyleProvider,
- visualStabilityCoordinator,
+ mockVisualStabilityCoordinator,
mockNotificationActionClickManager,
+ mockHighPriorityProvider,
+ mockHeadsUpManager,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
index 6a674ca..b6acf47 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
@@ -60,6 +60,7 @@
import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl
@@ -376,6 +377,8 @@
Mockito.mock(NotificationIconStyleProvider::class.java),
Mockito.mock(VisualStabilityCoordinator::class.java),
Mockito.mock(NotificationActionClickManager::class.java),
+ Mockito.mock(HighPriorityProvider::class.java),
+ Mockito.mock(HeadsUpManager::class.java),
)
.create(entry)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallTestHelper.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallTestHelper.kt
index e5e1a83..bc0bb75 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallTestHelper.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallTestHelper.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone.ongoingcall.shared.model
import android.app.PendingIntent
+import com.android.internal.logging.InstanceId
import com.android.systemui.activity.data.repository.activityManagerRepository
import com.android.systemui.activity.data.repository.fake
import com.android.systemui.kosmos.Kosmos
@@ -41,6 +42,7 @@
appName: String = "",
promotedContent: PromotedNotificationContentModels? = null,
isAppVisible: Boolean = false,
+ instanceId: InstanceId? = null,
) =
OngoingCallModel.InCall(
startTimeMs,
@@ -50,6 +52,7 @@
appName,
promotedContent,
isAppVisible,
+ instanceId,
)
object OngoingCallTestHelper {
@@ -82,6 +85,7 @@
uid: Int = DEFAULT_UID,
appName: String = "Fake name",
isAppVisible: Boolean = false,
+ instanceId: InstanceId? = null,
) {
if (StatusBarChipsModernization.isEnabled) {
activityManagerRepository.fake.startingIsAppVisibleValue = isAppVisible
@@ -95,6 +99,7 @@
promotedContent = promotedContent,
uid = uid,
appName = appName,
+ instanceId = instanceId,
)
)
} else {
@@ -107,6 +112,7 @@
appName = appName,
promotedContent = promotedContent,
isAppVisible = isAppVisible,
+ instanceId = instanceId,
)
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
index 5c4deaa..0c088cc0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
@@ -29,6 +29,7 @@
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.shareToAppChipViewModel
import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
+import com.android.systemui.statusbar.chips.uievents.statusBarChipsUiEventLogger
import com.android.systemui.statusbar.events.domain.interactor.systemStatusEventAnimationInteractor
import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.statusBarPopupChipsViewModelFactory
import com.android.systemui.statusbar.layout.ui.viewmodel.multiDisplayStatusBarContentInsetsViewModelStore
@@ -69,6 +70,7 @@
backgroundScope,
testDispatcher,
{ shadeDisplaysInteractor },
+ uiEventLogger = statusBarChipsUiEventLogger,
)
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogCsdWarningInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogCsdWarningInteractorKosmos.kt
new file mode 100644
index 0000000..fc7fc0f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogCsdWarningInteractorKosmos.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.volume.dialog.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.volume.dialog.shared.model.CsdWarningConfigModel
+
+val Kosmos.volumeDialogCsdWarningInteractor: VolumeDialogCsdWarningInteractor by
+ Kosmos.Fixture { VolumeDialogCsdWarningInteractor(volumeDialogStateInteractor) }
+
+val Kosmos.csdWarningConfigModel: CsdWarningConfigModel by
+ Kosmos.Fixture { CsdWarningConfigModel(emptyList()) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModelKosmos.kt
new file mode 100644
index 0000000..5a58599
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModelKosmos.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.volume.dialog.ui.viewmodel
+
+import com.android.internal.logging.uiEventLogger
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.backgroundScope
+import com.android.systemui.volume.dialog.domain.interactor.csdWarningConfigModel
+import com.android.systemui.volume.dialog.domain.interactor.volumeDialogCsdWarningInteractor
+import com.android.systemui.volume.dialog.domain.interactor.volumeDialogSafetyWarningInteractor
+import com.android.systemui.volume.dialog.domain.interactor.volumeDialogVisibilityInteractor
+import com.android.systemui.volume.dialog.shared.volumeDialogLogger
+import com.android.systemui.volume.dialog.volumeDialog
+
+val Kosmos.volumeDialogPluginViewModel: VolumeDialogPluginViewModel by
+ Kosmos.Fixture {
+ VolumeDialogPluginViewModel(
+ backgroundScope,
+ volumeDialogVisibilityInteractor,
+ volumeDialogSafetyWarningInteractor,
+ volumeDialogCsdWarningInteractor,
+ { volumeDialog },
+ volumeDialogLogger,
+ csdWarningConfigModel,
+ uiEventLogger,
+ )
+ }
diff --git a/ravenwood/tools/hoststubgen/README.md b/ravenwood/tools/hoststubgen/README.md
index 615e767..9f72611 100644
--- a/ravenwood/tools/hoststubgen/README.md
+++ b/ravenwood/tools/hoststubgen/README.md
@@ -17,62 +17,3 @@
- More Android specific build files and code are stored in `frameworks/base/Ravenwood.bp`
`frameworks/base/ravenwood`.
-
-## Directories and files
-
-- `src/`
-
- HostStubGen tool source code.
-
-- `annotations-src/` See `Android.bp`.
-- `helper-framework-buildtime-src/` See `Android.bp`.
-- `helper-framework-runtime-src/` See `Android.bp`.
-- `helper-runtime-src/` See `Android.bp`.
-
-- `test-tiny-framework/` See `README.md` in it.
-
-- `scripts`
- - `dump-jar.sh`
-
- A script to dump the content of `*.class` and `*.jar` files.
-
- - `run-all-tests.sh`
-
- Run all tests. Many tests may fail, but at least this should run til the end.
- (It should print `run-all-tests.sh finished` at the end)
-
-## Build and run
-
-### Building `HostStubGen` binary
-
-```
-m hoststubgen
-```
-
-### Run the tests
-
-- Run all relevant tests and test scripts. All of it is expected to pass, and it'll print
- "Ready to submit" at the end.
-
- However, because some of the script it executes depend on internal file paths to Soong's
- intermediate directory, some of it might fail when something changes in the build system.
-
- We need proper build system integration to fix them.
-```
-$ ./scripts/run-all-tests.sh
-```
-
-- See also `README.md` in `test-*` directories.
-
-## TODOs, etc
-
- - Make sure the parent's visibility is not smaller than the member's.
-
-- @HostSideTestNativeSubstitutionClass should automatically add class-keep to the substitute class.
- (or at least check it.)
-
- - The `HostStubGenTest-framework-test-host-test-lib` jar somehow contain all ASM classes? Figure out where the dependency is coming from.
-
-- At some point, we can move or delete all Android specific code to `frameworks/base/ravenwood`.
- - `helper-framework-*-src` should be moved to `frameworks/base/ravenwood`
- - `test-framework` should be deleted.
diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
index f8bb526..760999f 100644
--- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
+++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
@@ -60,7 +60,7 @@
}
return p.withReason(policy.reason)
- .wrapReason("class-wide in $className")
+ .wrapReason("class-wide in $className", policy.statsLabelOverride)
}
// If the class's policy is remove, then remove it.
if (policy.policy == FilterPolicy.Remove) {
diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
index 7358a0b..e082bbb 100644
--- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
+++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
@@ -41,7 +41,7 @@
data class FilterPolicyWithReason (
val policy: FilterPolicy,
val reason: String = "",
- private val statsLabelOverride: StatsLabel? = null
+ val statsLabelOverride: StatsLabel? = null
) {
/**
* Return a new [FilterPolicy] with an updated reason, while keeping the original reason
@@ -51,7 +51,7 @@
return FilterPolicyWithReason(
policy,
"$reason [inner-reason: ${this.reason}]",
- statsLabelOverride = statsLabelOverride,
+ statsLabelOverride = statsLabelOverride ?: this.statsLabelOverride,
)
}
diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
index 97fc353..cdcea4c 100644
--- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
+++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
@@ -528,7 +528,8 @@
)
}
val p = policy.withReason(
- "$FILTER_REASON (special-class AIDL)"
+ "$FILTER_REASON (special-class AIDL)",
+ StatsLabel.SupportedButBoring,
)
processor.onSpecialClassPolicy(classType, p)
aidlPolicy = p
@@ -541,7 +542,8 @@
)
}
val p = policy.withReason(
- "$FILTER_REASON (special-class feature flags)"
+ "$FILTER_REASON (special-class feature flags)",
+ StatsLabel.SupportedButBoring,
)
processor.onSpecialClassPolicy(classType, p)
featureFlagsPolicy = p
@@ -554,7 +556,8 @@
)
}
val p = policy.withReason(
- "$FILTER_REASON (special-class sysprops)"
+ "$FILTER_REASON (special-class sysprops)",
+ StatsLabel.SupportedButBoring,
)
processor.onSpecialClassPolicy(classType, p)
syspropsPolicy = p
@@ -567,7 +570,8 @@
)
}
val p = policy.withReason(
- "$FILTER_REASON (special-class R file)"
+ "$FILTER_REASON (special-class R file)",
+ StatsLabel.SupportedButBoring,
)
processor.onSpecialClassPolicy(classType, p)
rFilePolicy = p
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/README.md b/ravenwood/tools/hoststubgen/test-tiny-framework/README.md
deleted file mode 100644
index 344b4e9..0000000
--- a/ravenwood/tools/hoststubgen/test-tiny-framework/README.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# HostStubGen: tiny-framework test
-
-This directory contains a small classes that "simulates" framework.jar, and tests against it.
-
-This test is agnostic to Android, and it doesn't use any android framework code or knowledge.
-
-## How to run
-
-- With `atest`. This is the proper way to run it, but `atest` has known problems that may
- affect the result. If you see weird problems, try the next `run-ravenwood-test` command.
-
-```
-$ atest hoststubgen-test-tiny-test
-```
-
-- `run-test-manually.sh` also run the test, but it builds the stub/impl jars and the test without
- using the build system. This is useful for debugging the tool.
-
-```
-$ ./run-test-manually.sh
-```
\ No newline at end of file
diff --git a/services/Android.bp b/services/Android.bp
index efd35ce..8657bfc 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -181,7 +181,7 @@
conditions_default: {
dex_preopt: {
app_image: true,
- profile: "art-profile",
+ profile: ":art-profile-combined",
},
},
},
@@ -391,9 +391,14 @@
src: ":services",
}
-filegroup {
- name: "art-profile",
- srcs: ["art-profile"],
+genrule {
+ name: "art-profile-combined",
+ srcs: [
+ "art-profile",
+ "art-profile-extra",
+ ],
+ out: ["art-profile-combined"],
+ cmd: "cat $(location art-profile) $(location art-profile-extra) > $(location art-profile-combined)",
}
// API stub
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 47aa8f5..aae8879 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -1942,14 +1942,9 @@
}
public void notifyGesture(AccessibilityGestureEvent gestureEvent) {
- if (android.view.accessibility.Flags.copyEventsForGestureDetection()) {
- // We will use this event async, so copy it because it contains MotionEvents.
- mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_GESTURE,
- gestureEvent.copyForAsync()).sendToTarget();
- } else {
- mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_GESTURE,
- gestureEvent).sendToTarget();
- }
+ // We will use this event async, so copy it because it contains MotionEvents.
+ mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_GESTURE,
+ gestureEvent.copyForAsync()).sendToTarget();
}
public void notifySystemActionsChangedLocked() {
@@ -2426,9 +2421,7 @@
case MSG_ON_GESTURE: {
if (message.obj instanceof AccessibilityGestureEvent gesture) {
notifyGestureInternal(gesture);
- if (android.view.accessibility.Flags.copyEventsForGestureDetection()) {
- gesture.recycle();
- }
+ gesture.recycle();
}
} break;
case MSG_CLEAR_ACCESSIBILITY_CACHE: {
diff --git a/services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java b/services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java
index edcf574..8cf94b4 100644
--- a/services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/HearingDevicePhoneCallNotificationController.java
@@ -160,24 +160,16 @@
mHearingDevice = null;
}
if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
- if (com.android.server.accessibility.Flags.hearingInputChangeWhenCommDevice()) {
- AudioDeviceInfo commDevice = mAudioManager.getCommunicationDevice();
- if (commDevice == null) {
- return;
- }
- mHearingDevice = getSupportedInputHearingDeviceInfo(List.of(commDevice));
- if (mHearingDevice != null) {
- showNotificationIfNeeded();
- } else {
- addOnCommunicationDeviceChangedListenerIfNeeded(mCommDeviceChangedExecutor,
- mCommDeviceChangedListener);
- }
+ AudioDeviceInfo commDevice = mAudioManager.getCommunicationDevice();
+ if (commDevice == null) {
+ return;
+ }
+ mHearingDevice = getSupportedInputHearingDeviceInfo(List.of(commDevice));
+ if (mHearingDevice != null) {
+ showNotificationIfNeeded();
} else {
- mHearingDevice = getSupportedInputHearingDeviceInfo(
- mAudioManager.getAvailableCommunicationDevices());
- if (mHearingDevice != null) {
- showNotificationIfNeeded();
- }
+ addOnCommunicationDeviceChangedListenerIfNeeded(mCommDeviceChangedExecutor,
+ mCommDeviceChangedListener);
}
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureMatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureMatcher.java
index 3668eef..62b6b85 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureMatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureMatcher.java
@@ -336,13 +336,8 @@
// Recycle the old event first if necessary, to handle duplicate calls to post.
recycleEvent();
mTargetState = state;
- if (android.view.accessibility.Flags.copyEventsForGestureDetection()) {
- mEvent = event.copy();
- mRawEvent = rawEvent.copy();
- } else {
- mEvent = event;
- mRawEvent = rawEvent;
- }
+ mEvent = event.copy();
+ mRawEvent = rawEvent.copy();
mPolicyFlags = policyFlags;
mHandler.postDelayed(this, delay);
if (DEBUG) {
@@ -379,15 +374,13 @@
}
private void recycleEvent() {
- if (android.view.accessibility.Flags.copyEventsForGestureDetection()) {
- if (mEvent == null || mRawEvent == null) {
- return;
- }
- mEvent.recycle();
- mRawEvent.recycle();
- mEvent = null;
- mRawEvent = null;
+ if (mEvent == null || mRawEvent == null) {
+ return;
}
+ mEvent.recycle();
+ mRawEvent.recycle();
+ mEvent = null;
+ mRawEvent = null;
}
}
diff --git a/services/art-profile-extra b/services/art-profile-extra
new file mode 100644
index 0000000..5436241
--- /dev/null
+++ b/services/art-profile-extra
@@ -0,0 +1 @@
+HSPLcom/android/server/am/ActivityManagerService$LocalService;->checkContentProviderAccess(Ljava/lang/String;I)Ljava/lang/String;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 5395d2a..c15915b 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -790,7 +790,7 @@
"SHORT_FGS_TIMEOUT");
this.mServiceFGAnrTimer = new ServiceAnrTimer(service,
ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG,
- "SERVICE_FOREGROUND_TIMEOUT");
+ "SERVICE_FOREGROUND_TIMEOUT", new AnrTimer.Args().extend(true));
}
void systemServicesReady() {
@@ -7702,6 +7702,11 @@
super(Objects.requireNonNull(am).mHandler, msg, label);
}
+ ServiceAnrTimer(ActivityManagerService am, int msg, String label,
+ @NonNull AnrTimer.Args args) {
+ super(Objects.requireNonNull(am).mHandler, msg, label, args);
+ }
+
@Override
public int getPid(@NonNull ServiceRecord service) {
return (service.app != null) ? service.app.getPid() : 0;
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index 225c7ca..83db027 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -2264,8 +2264,8 @@
final int idleTime = mProcessCpuTracker.getLastIdleTime();
bstats.addCpuStatsLocked(totalUTime, totalSTime, userTime,
systemTime, iowaitTime, irqTime, softIrqTime, idleTime);
+ bstats.finishAddingCpuStatsLocked();
}
- bstats.finishAddingCpuStatsLocked();
}
if (mLastWriteTime < (now - BATTERY_STATS_TIME)) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 5ff6999..6b4a99c 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -211,7 +211,6 @@
private static final int POWER_STATS_QUERY_TIMEOUT_MILLIS = 2000;
private static final String DEVICE_CONFIG_NAMESPACE = "backstage_power";
private static final String MIN_CONSUMED_POWER_THRESHOLD_KEY = "min_consumed_power_threshold";
- private static final String EMPTY = "Empty";
private final HandlerThread mHandlerThread;
private final Handler mHandler;
@@ -336,55 +335,6 @@
}
}
- @Override
- public String getSubsystemLowPowerStats() {
- synchronized (mPowerStatsLock) {
- if (mPowerStatsInternal == null || mEntityNames.isEmpty() || mStateNames.isEmpty()) {
- return EMPTY;
- }
- }
-
- final StateResidencyResult[] results;
- try {
- results = mPowerStatsInternal.getStateResidencyAsync(new int[0])
- .get(POWER_STATS_QUERY_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
- } catch (Exception e) {
- Slog.e(TAG, "Failed to getStateResidencyAsync", e);
- return EMPTY;
- }
-
- if (results == null || results.length == 0) return EMPTY;
-
- int charsLeft = MAX_LOW_POWER_STATS_SIZE;
- StringBuilder builder = new StringBuilder("SubsystemPowerState");
- for (int i = 0; i < results.length; i++) {
- final StateResidencyResult result = results[i];
- StringBuilder subsystemBuilder = new StringBuilder();
- subsystemBuilder.append(" subsystem_" + i);
- subsystemBuilder.append(" name=" + mEntityNames.get(result.id));
-
- for (int j = 0; j < result.stateResidencyData.length; j++) {
- final StateResidency stateResidency = result.stateResidencyData[j];
- subsystemBuilder.append(" state_" + j);
- subsystemBuilder.append(" name=" + mStateNames.get(result.id).get(
- stateResidency.id));
- subsystemBuilder.append(" time=" + stateResidency.totalTimeInStateMs);
- subsystemBuilder.append(" count=" + stateResidency.totalStateEntryCount);
- subsystemBuilder.append(" last entry=" + stateResidency.lastEntryTimestampMs);
- }
-
- if (subsystemBuilder.length() <= charsLeft) {
- charsLeft -= subsystemBuilder.length();
- builder.append(subsystemBuilder);
- } else {
- Slog.e(TAG, "getSubsystemLowPowerStats: buffer not enough");
- break;
- }
- }
-
- return builder.toString();
- }
-
private ConnectivityManager.NetworkCallback mNetworkCallback =
new ConnectivityManager.NetworkCallback() {
@Override
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index c2ed4d5..4eadab2 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -317,8 +317,6 @@
private final String[] mDeviceConfigScopes;
- private final String[] mDeviceConfigAconfigScopes;
-
private final ContentResolver mContentResolver;
@VisibleForTesting
@@ -329,7 +327,6 @@
mContentResolver = contentResolver;
mGlobalSettings = globalSettings;
mDeviceConfigScopes = deviceConfigScopes;
- mDeviceConfigAconfigScopes = deviceConfigAconfigScopes;
}
@VisibleForTesting
@@ -375,36 +372,6 @@
return;
}
setProperty(propertyName, properties.getString(key, null));
-
- // for legacy namespaces, they can also be used for trunk stable
- // purposes. so push flag also into trunk stable slot in sys prop,
- // later all legacy usage will be refactored and the sync to old
- // sys prop slot can be removed.
- String aconfigPropertyName = makeAconfigFlagPropertyName(scope, key);
- if (aconfigPropertyName == null) {
- logErr("unable to construct system property for " + scope + "/"
- + key);
- return;
- }
- setProperty(aconfigPropertyName, properties.getString(key, null));
- }
- });
- }
-
- for (String deviceConfigAconfigScope : mDeviceConfigAconfigScopes) {
- DeviceConfig.addOnPropertiesChangedListener(
- deviceConfigAconfigScope,
- AsyncTask.THREAD_POOL_EXECUTOR,
- (DeviceConfig.Properties properties) -> {
- String scope = properties.getNamespace();
- for (String key : properties.getKeyset()) {
- String aconfigPropertyName = makeAconfigFlagPropertyName(scope, key);
- if (aconfigPropertyName == null) {
- logErr("unable to construct system property for " + scope + "/"
- + key);
- return;
- }
- setProperty(aconfigPropertyName, properties.getString(key, null));
}
});
}
@@ -420,34 +387,6 @@
stageFlagsInNewStorage(properties);
return;
}
-
- for (String flagName : properties.getKeyset()) {
- String flagValue = properties.getString(flagName, null);
- if (flagName == null || flagValue == null) {
- continue;
- }
-
- int idx = flagName.indexOf(NAMESPACE_REBOOT_STAGING_DELIMITER);
- if (idx == -1 || idx == flagName.length() - 1 || idx == 0) {
- logErr("invalid staged flag: " + flagName);
- continue;
- }
-
- String actualNamespace = flagName.substring(0, idx);
- String actualFlagName = flagName.substring(idx+1);
- String propertyName = "next_boot." + makeAconfigFlagPropertyName(
- actualNamespace, actualFlagName);
-
- if (Flags.supportLocalOverridesSysprops()) {
- // Don't propagate if there is a local override.
- String overrideName = actualNamespace + ":" + actualFlagName;
- if (DeviceConfig.getProperty(NAMESPACE_LOCAL_OVERRIDES, overrideName) != null) {
- continue;
- }
- }
- setProperty(propertyName, flagValue);
- }
-
});
// add prop sync callback for flag local overrides
@@ -459,42 +398,6 @@
setLocalOverridesInNewStorage(properties);
return;
}
-
- if (Flags.supportLocalOverridesSysprops()) {
- String overridesNamespace = properties.getNamespace();
- for (String key : properties.getKeyset()) {
- String realNamespace = key.split(":")[0];
- String realFlagName = key.split(":")[1];
- String aconfigPropertyName =
- makeAconfigFlagPropertyName(realNamespace, realFlagName);
- if (aconfigPropertyName == null) {
- logErr("unable to construct system property for " + realNamespace + "/"
- + key);
- return;
- }
-
- if (properties.getString(key, null) == null) {
- String deviceConfigValue =
- DeviceConfig.getProperty(realNamespace, realFlagName);
- String stagedDeviceConfigValue =
- DeviceConfig.getProperty(NAMESPACE_REBOOT_STAGING,
- realNamespace + "*" + realFlagName);
-
- setProperty(aconfigPropertyName, deviceConfigValue);
- if (stagedDeviceConfigValue == null) {
- setProperty("next_boot." + aconfigPropertyName, deviceConfigValue);
- } else {
- setProperty("next_boot." + aconfigPropertyName, stagedDeviceConfigValue);
- }
- } else {
- // Otherwise, propagate the override to sysprops.
- setProperty(aconfigPropertyName, properties.getString(key, null));
- // If there's a staged value, make sure it's the override value.
- setProperty("next_boot." + aconfigPropertyName,
- properties.getString(key, null));
- }
- }
- }
});
}
@@ -822,28 +725,6 @@
sendAconfigdRequests(requests);
}
- /**
- * system property name constructing rule for aconfig flags:
- * "persist.device_config.aconfig_flags.[category_name].[flag_name]".
- * If the name contains invalid characters or substrings for system property name,
- * will return null.
- * @param categoryName
- * @param flagName
- * @return
- */
- @VisibleForTesting
- static String makeAconfigFlagPropertyName(String categoryName, String flagName) {
- String propertyName = SYSTEM_PROPERTY_PREFIX + "aconfig_flags." +
- categoryName + "." + flagName;
-
- if (!propertyName.matches(SYSTEM_PROPERTY_VALID_CHARACTERS_REGEX)
- || propertyName.contains(SYSTEM_PROPERTY_INVALID_SUBSTRING)) {
- return null;
- }
-
- return propertyName;
- }
-
private void setProperty(String key, String value) {
// Check if need to clear the property
if (value == null) {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 5ecac22..2e229ca 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -55,7 +55,6 @@
import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM;
import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM_OPS;
import static android.app.AppOpsManager.SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE;
-import static android.app.AppOpsManager.UID_STATE_NONEXISTENT;
import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES;
import static android.app.AppOpsManager._NUM_OP;
import static android.app.AppOpsManager.extractFlagsFromKey;
@@ -464,7 +463,19 @@
Clock.SYSTEM_CLOCK, mConstants);
mUidStateTracker.addUidStateChangedCallback(new HandlerExecutor(mHandler),
- this::onUidStateChanged);
+ new AppOpsUidStateTracker.UidStateChangedCallback() {
+ @Override
+ public void onUidStateChanged(int uid, int uidState,
+ boolean foregroundModeMayChange) {
+ AppOpsService.this
+ .onUidStateChanged(uid, uidState, foregroundModeMayChange);
+ }
+
+ @Override
+ public void onUidProcessDeath(int uid) {
+ AppOpsService.this.onUidProcessDeath(uid);
+ }
+ });
}
return mUidStateTracker;
}
@@ -1500,9 +1511,6 @@
// The callback method from AppOpsUidStateTracker
private void onUidStateChanged(int uid, int state, boolean foregroundModeMayChange) {
synchronized (this) {
- if (state == UID_STATE_NONEXISTENT) {
- onUidProcessDeathLocked(uid);
- }
UidState uidState = getUidStateLocked(uid, false);
boolean hasForegroundWatchers = false;
@@ -1590,11 +1598,6 @@
}
}
- if (state == UID_STATE_NONEXISTENT) {
- // For UID_STATE_NONEXISTENT, we don't call onUidStateChanged for AttributedOps
- return;
- }
-
if (uidState != null) {
int numPkgs = uidState.pkgOps.size();
for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
@@ -1619,31 +1622,32 @@
}
}
- @GuardedBy("this")
- private void onUidProcessDeathLocked(int uid) {
- if (!mUidStates.contains(uid) || !Flags.finishRunningOpsForKilledPackages()) {
- return;
- }
- final SparseLongArray chainsToFinish = new SparseLongArray();
- doForAllAttributedOpsInUidLocked(uid, (attributedOp) -> {
- attributedOp.doForAllInProgressStartOpEvents((event) -> {
- if (event == null) {
- return;
- }
- int chainId = event.getAttributionChainId();
- if (chainId != ATTRIBUTION_CHAIN_ID_NONE) {
- long currentEarliestStartTime =
- chainsToFinish.get(chainId, Long.MAX_VALUE);
- if (event.getStartTime() < currentEarliestStartTime) {
- // Store the earliest chain link we're finishing, so that we can go back
- // and finish any links in the chain that started after this one
- chainsToFinish.put(chainId, event.getStartTime());
+ private void onUidProcessDeath(int uid) {
+ synchronized (this) {
+ if (!mUidStates.contains(uid) || !Flags.finishRunningOpsForKilledPackages()) {
+ return;
+ }
+ final SparseLongArray chainsToFinish = new SparseLongArray();
+ doForAllAttributedOpsInUidLocked(uid, (attributedOp) -> {
+ attributedOp.doForAllInProgressStartOpEvents((event) -> {
+ if (event == null) {
+ return;
}
- }
- attributedOp.finished(event.getClientId());
+ int chainId = event.getAttributionChainId();
+ if (chainId != ATTRIBUTION_CHAIN_ID_NONE) {
+ long currentEarliestStartTime =
+ chainsToFinish.get(chainId, Long.MAX_VALUE);
+ if (event.getStartTime() < currentEarliestStartTime) {
+ // Store the earliest chain link we're finishing, so that we can go back
+ // and finish any links in the chain that started after this one
+ chainsToFinish.put(chainId, event.getStartTime());
+ }
+ }
+ attributedOp.finished(event.getClientId());
+ });
});
- });
- finishChainsLocked(chainsToFinish);
+ finishChainsLocked(chainsToFinish);
+ }
}
@GuardedBy("this")
diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java b/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java
index 268b286..9bd7299 100644
--- a/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java
+++ b/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java
@@ -19,6 +19,7 @@
import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
@@ -27,8 +28,10 @@
import static android.app.AppOpsManager.UID_STATE_CACHED;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
+import static android.app.AppOpsManager.UID_STATE_NONEXISTENT;
import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
import static android.app.AppOpsManager.UID_STATE_TOP;
+import static android.permission.flags.Flags.finishRunningOpsForKilledPackages;
import android.annotation.CallbackExecutor;
import android.util.SparseArray;
@@ -68,6 +71,14 @@
return UID_STATE_BACKGROUND;
}
+ if (finishRunningOpsForKilledPackages()) {
+ if (procState < PROCESS_STATE_NONEXISTENT) {
+ return UID_STATE_CACHED;
+ }
+
+ return UID_STATE_NONEXISTENT;
+ }
+
// UID_STATE_NONEXISTENT is deliberately excluded here
return UID_STATE_CACHED;
}
@@ -119,6 +130,8 @@
* evaluated result may have changed.
*/
void onUidStateChanged(int uid, int uidState, boolean foregroundModeMayChange);
+
+ void onUidProcessDeath(int uid);
}
void dumpUidState(PrintWriter pw, int uid, long nowElapsed);
diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
index 6f8c241..1a1077a 100644
--- a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
+++ b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
@@ -21,7 +21,6 @@
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
-import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityManager.ProcessCapability;
import static android.app.AppOpsManager.MIN_PRIORITY_UID_STATE;
import static android.app.AppOpsManager.MODE_ALLOWED;
@@ -32,6 +31,7 @@
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.UID_STATE_CACHED;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
import static android.app.AppOpsManager.UID_STATE_NONEXISTENT;
@@ -75,7 +75,6 @@
private SparseBooleanArray mAppWidgetVisible = new SparseBooleanArray();
private SparseBooleanArray mPendingAppWidgetVisible = new SparseBooleanArray();
private SparseLongArray mPendingCommitTime = new SparseLongArray();
- private SparseBooleanArray mPendingGone = new SparseBooleanArray();
private ArrayMap<UidStateChangedCallback, Executor>
mUidStateChangedCallbacks = new ArrayMap<>();
@@ -221,11 +220,12 @@
public void updateUidProcState(int uid, int procState, int capability) {
int uidState = processStateToUidState(procState);
- int prevUidState = mUidStates.get(uid, AppOpsManager.MIN_PRIORITY_UID_STATE);
+ int prevUidState = mUidStates.get(uid, AppOpsManager.UID_STATE_NONEXISTENT);
int prevCapability = mCapability.get(uid, PROCESS_CAPABILITY_NONE);
- int pendingUidState = mPendingUidStates.get(uid, MIN_PRIORITY_UID_STATE);
+ int pendingUidState = mPendingUidStates.get(uid, UID_STATE_NONEXISTENT);
int pendingCapability = mPendingCapability.get(uid, PROCESS_CAPABILITY_NONE);
long pendingStateCommitTime = mPendingCommitTime.get(uid, 0);
+
if ((pendingStateCommitTime == 0
&& (uidState != prevUidState || capability != prevCapability))
|| (pendingStateCommitTime != 0
@@ -239,8 +239,7 @@
boolean hasLostCapability = (prevCapability & ~capability) != 0;
- if (procState == PROCESS_STATE_NONEXISTENT) {
- mPendingGone.put(uid, true);
+ if (uidState == UID_STATE_NONEXISTENT) {
commitUidPendingState(uid);
} else if (uidState < prevUidState) {
// We are moving to a more important state, or the new state may be in the
@@ -342,7 +341,7 @@
private void commitUidPendingState(int uid) {
- int uidState = mUidStates.get(uid, MIN_PRIORITY_UID_STATE);
+ int uidState = mUidStates.get(uid, UID_STATE_NONEXISTENT);
int capability = mCapability.get(uid, PROCESS_CAPABILITY_NONE);
boolean appWidgetVisible = mAppWidgetVisible.get(uid, false);
@@ -350,18 +349,23 @@
int pendingCapability = mPendingCapability.get(uid, capability);
boolean pendingAppWidgetVisible = mPendingAppWidgetVisible.get(uid, appWidgetVisible);
- boolean foregroundChange = uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
- != pendingUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
+ // UID_STATE_NONEXISTENT is a state that isn't used outside of this class, nonexistent
+ // processes have always been represented as CACHED
+ int externalUidState = Math.min(uidState, UID_STATE_CACHED);
+ int externalPendingUidState = Math.min(pendingUidState, UID_STATE_CACHED);
+
+ boolean foregroundChange = externalUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
+ != externalPendingUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
|| capability != pendingCapability
|| appWidgetVisible != pendingAppWidgetVisible;
- if (uidState != pendingUidState
+ if (externalUidState != externalPendingUidState
|| capability != pendingCapability
|| appWidgetVisible != pendingAppWidgetVisible) {
if (foregroundChange) {
// To save on memory usage, log only interesting changes.
- mEventLog.logCommitUidState(uid, pendingUidState, pendingCapability,
+ mEventLog.logCommitUidState(uid, externalPendingUidState, pendingCapability,
pendingAppWidgetVisible, appWidgetVisible != pendingAppWidgetVisible);
}
@@ -370,24 +374,23 @@
Executor executor = mUidStateChangedCallbacks.valueAt(i);
executor.execute(PooledLambda.obtainRunnable(
- UidStateChangedCallback::onUidStateChanged, cb, uid, pendingUidState,
- foregroundChange));
+ UidStateChangedCallback::onUidStateChanged, cb, uid,
+ externalPendingUidState, foregroundChange));
}
}
- if (mPendingGone.get(uid, false)) {
+ if (pendingUidState == UID_STATE_NONEXISTENT && uidState != pendingUidState) {
mUidStates.delete(uid);
mCapability.delete(uid);
mAppWidgetVisible.delete(uid);
- mPendingGone.delete(uid);
if (finishRunningOpsForKilledPackages()) {
for (int i = 0; i < mUidStateChangedCallbacks.size(); i++) {
UidStateChangedCallback cb = mUidStateChangedCallbacks.keyAt(i);
Executor executor = mUidStateChangedCallbacks.valueAt(i);
+ // If foregroundness changed it should be handled in earlier callback invocation
executor.execute(PooledLambda.obtainRunnable(
- UidStateChangedCallback::onUidStateChanged, cb, uid,
- UID_STATE_NONEXISTENT, foregroundChange));
+ UidStateChangedCallback::onUidProcessDeath, cb, uid));
}
}
} else {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index a8bb523..b1acfe8 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4190,7 +4190,13 @@
Log.d(TAG, "adjustStreamVolume postSetHearingAidVolumeIndex index="
+ newIndex + " stream=" + streamType);
}
- mDeviceBroker.postSetHearingAidVolumeIndex(newIndex, streamType);
+ int haIndex;
+ final VolumeStreamState vss = getVssForStreamOrDefault(streamType);
+ synchronized (mVolumeStateLock) {
+ haIndex = (int) (vss.getMinIndex() + (newIndex - vss.getMinIndex())
+ / vss.getIndexStepFactor());
+ }
+ mDeviceBroker.postSetHearingAidVolumeIndex(haIndex, streamType);
}
}
@@ -4460,18 +4466,12 @@
private final AudioVolumeChangeHandler mAudioVolumeChangeHandler;
/** @see AudioManager#registerVolumeGroupCallback(executor, callback) */
- @android.annotation.EnforcePermission(
- android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
public void registerAudioVolumeCallback(IAudioVolumeChangeDispatcher callback) {
- super.registerAudioVolumeCallback_enforcePermission();
mAudioVolumeChangeHandler.registerListener(callback);
}
/** @see AudioManager#unregisterVolumeGroupCallback(callback) */
- @android.annotation.EnforcePermission(
- android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
public void unregisterAudioVolumeCallback(IAudioVolumeChangeDispatcher callback) {
- super.unregisterAudioVolumeCallback_enforcePermission();
mAudioVolumeChangeHandler.unregisterListener(callback);
}
@@ -5149,7 +5149,13 @@
mDeviceBroker.postSetLeAudioVolumeIndex(index * 10,
getVssForStreamOrDefault(streamType).getMaxIndex(), streamType);
} else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
- mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType);
+ int haIndex = index * 10;
+ final VolumeStreamState vss = getVssForStreamOrDefault(streamType);
+ synchronized (mVolumeStateLock) {
+ haIndex = (int) (vss.getMinIndex()
+ + (haIndex - vss.getMinIndex()) / vss.getIndexStepFactor());
+ }
+ mDeviceBroker.postSetHearingAidVolumeIndex(haIndex, streamType);
} else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)) {
mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index);
} else {
@@ -5280,7 +5286,13 @@
&& streamType == getBluetoothContextualVolumeStream()) {
Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index
+ " stream=" + streamType);
- mDeviceBroker.postSetHearingAidVolumeIndex(index, streamType);
+ int haIndex;
+ final VolumeStreamState vss = getVssForStreamOrDefault(streamType);
+ synchronized (mVolumeStateLock) {
+ haIndex = (int) (vss.getMinIndex()
+ + (index - vss.getMinIndex()) / vss.getIndexStepFactor());
+ }
+ mDeviceBroker.postSetHearingAidVolumeIndex(haIndex, streamType);
}
synchronized (mHdmiClientLock) {
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 05fc6bc..c2500c8 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -559,6 +559,9 @@
@Override
public void onKeepClearAreasChanged(int displayId, List<Rect> restricted,
List<Rect> unrestricted) { }
+
+ @Override
+ public void onDesktopModeEligibleChanged(int displayId) { }
}
diff --git a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
index b4df1f7..569a426 100644
--- a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
+++ b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
@@ -111,13 +111,14 @@
* @param info The display info
*/
void onDisplayAdded(DisplayInfo info) {
- if (!isDisplayAllowedInTopology(info)) {
+ if (!isDisplayAllowedInTopology(info, /* shouldLog= */ true)) {
return;
}
synchronized (mSyncRoot) {
addDisplayIdMappingLocked(info);
mDensities.put(info.displayId, info.logicalDensityDpi);
mTopology.addDisplay(info.displayId, getWidth(info), getHeight(info));
+ Slog.i(TAG, "Display " + info.displayId + " added, new topology: " + mTopology);
restoreTopologyLocked();
sendTopologyUpdateLocked();
}
@@ -128,7 +129,7 @@
* @param info The new display info
*/
void onDisplayChanged(DisplayInfo info) {
- if (!isDisplayAllowedInTopology(info)) {
+ if (!isDisplayAllowedInTopology(info, /* shouldLog= */ false)) {
return;
}
synchronized (mSyncRoot) {
@@ -149,6 +150,7 @@
synchronized (mSyncRoot) {
mDensities.delete(displayId);
if (mTopology.removeDisplay(displayId)) {
+ Slog.i(TAG, "Display " + displayId + " removed, new topology: " + mTopology);
removeDisplayIdMappingLocked(displayId);
restoreTopologyLocked();
sendTopologyUpdateLocked();
@@ -249,22 +251,28 @@
return pxToDp(info.logicalHeight, info.logicalDensityDpi);
}
- private boolean isDisplayAllowedInTopology(DisplayInfo info) {
+ private boolean isDisplayAllowedInTopology(DisplayInfo info, boolean shouldLog) {
if (info.type != Display.TYPE_INTERNAL && info.type != Display.TYPE_EXTERNAL
&& info.type != Display.TYPE_OVERLAY) {
- Slog.d(TAG, "Display " + info.displayId + " not allowed in topology because "
- + "type is not INTERNAL, EXTERNAL or OVERLAY");
+ if (shouldLog) {
+ Slog.d(TAG, "Display " + info.displayId + " not allowed in topology because "
+ + "type is not INTERNAL, EXTERNAL or OVERLAY");
+ }
return false;
}
if (info.type == Display.TYPE_INTERNAL && info.displayId != Display.DEFAULT_DISPLAY) {
- Slog.d(TAG, "Display " + info.displayId + " not allowed in topology because "
- + "it is a non-default internal display");
+ if (shouldLog) {
+ Slog.d(TAG, "Display " + info.displayId + " not allowed in topology because "
+ + "it is a non-default internal display");
+ }
return false;
}
if ((info.type == Display.TYPE_EXTERNAL || info.type == Display.TYPE_OVERLAY)
&& !mIsExtendedDisplayAllowed.getAsBoolean()) {
- Slog.d(TAG, "Display " + info.displayId + " not allowed in topology because "
- + "type is EXTERNAL or OVERLAY and !mIsExtendedDisplayAllowed");
+ if (shouldLog) {
+ Slog.d(TAG, "Display " + info.displayId + " not allowed in topology because "
+ + "type is EXTERNAL or OVERLAY and !mIsExtendedDisplayAllowed");
+ }
return false;
}
return true;
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 60b7fca..228e6f1 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -130,6 +130,14 @@
private static final String OVERLAY_DISPLAY_FLAG_FIXED_CONTENT_MODE =
"fixed_content_mode";
+ /**
+ * When this flag is set, disables support for moving and resizing the overlay window.
+ * As the window is made non-touchable, this also makes it possible to directly interact with
+ * the content underneath.
+ */
+ private static final String OVERLAY_DISPLAY_FLAG_DISABLE_WINDOW_INTERACTION =
+ "disable_window_interaction";
+
// Gravity flags to decide where the overlay should be shown.
private static final String GRAVITY_TOP_LEFT = "gravity_top_left";
private static final String GRAVITY_BOTTOM_RIGHT = "gravity_bottom_right";
@@ -571,9 +579,9 @@
@Override
public void run() {
OverlayMode mode = mModes.get(mActiveMode);
- OverlayDisplayWindow window = new OverlayDisplayWindow(getContext(),
- mName, mode.mWidth, mode.mHeight, mode.mDensityDpi, mGravity,
- mFlags.mSecure, OverlayDisplayHandle.this);
+ OverlayDisplayWindow window = new OverlayDisplayWindow(getContext(), mName,
+ mode.mWidth, mode.mHeight, mode.mDensityDpi, mGravity, mFlags.mSecure,
+ mFlags.mDisableWindowInteraction, OverlayDisplayHandle.this);
window.show();
synchronized (getSyncRoot()) {
@@ -655,6 +663,9 @@
/** See {@link #OVERLAY_DISPLAY_FLAG_FIXED_CONTENT_MODE}. */
final boolean mFixedContentMode;
+ /** See {@link #OVERLAY_DISPLAY_FLAG_DISABLE_WINDOW_INTERACTION}. */
+ final boolean mDisableWindowInteraction;
+
final int mGravity;
OverlayFlags(
@@ -662,11 +673,13 @@
boolean ownContentOnly,
boolean shouldShowSystemDecorations,
boolean fixedContentMode,
+ boolean disableWindowInteraction,
int gravity) {
mSecure = secure;
mOwnContentOnly = ownContentOnly;
mShouldShowSystemDecorations = shouldShowSystemDecorations;
mFixedContentMode = fixedContentMode;
+ mDisableWindowInteraction = disableWindowInteraction;
mGravity = gravity;
}
@@ -677,6 +690,7 @@
false /* ownContentOnly */,
false /* shouldShowSystemDecorations */,
false /* fixedContentMode */,
+ false /* disableWindowInteraction */,
Gravity.NO_GRAVITY);
}
@@ -684,6 +698,7 @@
boolean ownContentOnly = false;
boolean shouldShowSystemDecorations = false;
boolean fixedContentMode = false;
+ boolean disableWindowInteraction = false;
int gravity = Gravity.NO_GRAVITY;
for (String flag: flagString.split(FLAG_SPLITTER)) {
if (OVERLAY_DISPLAY_FLAG_SECURE.equals(flag)) {
@@ -694,12 +709,14 @@
shouldShowSystemDecorations = true;
} else if (OVERLAY_DISPLAY_FLAG_FIXED_CONTENT_MODE.equals(flag)) {
fixedContentMode = true;
+ } else if (OVERLAY_DISPLAY_FLAG_DISABLE_WINDOW_INTERACTION.equals(flag)) {
+ disableWindowInteraction = true;
} else {
gravity = parseOverlayGravity(flag);
}
}
return new OverlayFlags(secure, ownContentOnly, shouldShowSystemDecorations,
- fixedContentMode, gravity);
+ fixedContentMode, disableWindowInteraction, gravity);
}
@Override
@@ -709,6 +726,7 @@
.append(", ownContentOnly=").append(mOwnContentOnly)
.append(", shouldShowSystemDecorations=").append(mShouldShowSystemDecorations)
.append(", fixedContentMode=").append(mFixedContentMode)
+ .append(", disableWindowInteraction=").append(mDisableWindowInteraction)
.append(", gravity").append(Gravity.toString(mGravity))
.append("}")
.toString();
diff --git a/services/core/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
index 3fd58e8..523bbfa 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
@@ -69,6 +69,7 @@
private int mDensityDpi;
private final int mGravity;
private final boolean mSecure;
+ private final boolean mDisableWindowInteraction;
private final Listener mListener;
private String mTitle;
@@ -96,15 +97,15 @@
private float mLiveTranslationY;
private float mLiveScale = 1.0f;
- public OverlayDisplayWindow(Context context, String name,
- int width, int height, int densityDpi, int gravity, boolean secure,
- Listener listener) {
+ OverlayDisplayWindow(Context context, String name, int width, int height, int densityDpi,
+ int gravity, boolean secure, boolean disableWindowInteraction, Listener listener) {
// Workaround device freeze (b/38372997)
ThreadedRenderer.disableVsync();
mContext = context;
mName = name;
mGravity = gravity;
mSecure = secure;
+ mDisableWindowInteraction = disableWindowInteraction;
mListener = listener;
mDisplayManager = (DisplayManager)context.getSystemService(
@@ -226,8 +227,10 @@
if (mSecure) {
mWindowParams.flags |= WindowManager.LayoutParams.FLAG_SECURE;
}
- if (DISABLE_MOVE_AND_RESIZE) {
+ if (DISABLE_MOVE_AND_RESIZE || mDisableWindowInteraction) {
mWindowParams.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ mWindowParams.privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
}
mWindowParams.privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
diff --git a/services/core/java/com/android/server/input/InputManagerInternal.java b/services/core/java/com/android/server/input/InputManagerInternal.java
index 1ace41c..2660db4 100644
--- a/services/core/java/com/android/server/input/InputManagerInternal.java
+++ b/services/core/java/com/android/server/input/InputManagerInternal.java
@@ -104,11 +104,16 @@
* @param fromChannelToken The channel token of a window that has an active touch gesture.
* @param toChannelToken The channel token of the window that should receive the gesture in
* place of the first.
+ * @param transferEntireGesture Whether the entire gesture (including subsequent POINTER_DOWN
+ * events) should be transferred. This should always be set to
+ * 'false' unless you have the permission from the input team to
+ * set it to true. This behaviour will be removed in future
+ * versions.
* @return True if the transfer was successful. False if the specified windows don't exist, or
* if the source window is not actively receiving a touch gesture at the time of the request.
*/
public abstract boolean transferTouchGesture(@NonNull IBinder fromChannelToken,
- @NonNull IBinder toChannelToken);
+ @NonNull IBinder toChannelToken, boolean transferEntireGesture);
/**
* Gets the current position of the mouse cursor.
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index fa18d96..f2ededa 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -25,6 +25,7 @@
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static com.android.hardware.input.Flags.enableCustomizableInputGestures;
+import static com.android.hardware.input.Flags.fixSearchModifierFallbacks;
import static com.android.hardware.input.Flags.keyEventActivityDetection;
import static com.android.hardware.input.Flags.touchpadVisualizer;
import static com.android.hardware.input.Flags.useKeyGestureEventHandler;
@@ -1369,7 +1370,7 @@
public boolean startDragAndDrop(@NonNull IBinder fromChannelToken,
@NonNull IBinder dragAndDropChannelToken) {
return mNative.transferTouchGesture(fromChannelToken, dragAndDropChannelToken,
- true /* isDragDrop */);
+ true /* isDragDrop */, false /* transferEntireGesture */);
}
/**
@@ -1393,11 +1394,11 @@
* if the source window is not actively receiving a touch gesture at the time of the request.
*/
public boolean transferTouchGesture(@NonNull IBinder fromChannelToken,
- @NonNull IBinder toChannelToken) {
+ @NonNull IBinder toChannelToken, boolean transferEntireGesture) {
Objects.requireNonNull(fromChannelToken);
Objects.requireNonNull(toChannelToken);
return mNative.transferTouchGesture(fromChannelToken, toChannelToken,
- false /* isDragDrop */);
+ false /* isDragDrop */, transferEntireGesture);
}
@Override // Binder call
@@ -2659,6 +2660,8 @@
@SuppressWarnings("unused")
@VisibleForTesting
long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
+ final long keyNotConsumedGoFallback = -2;
+ final long keyConsumed = -1;
final long keyNotConsumed = 0;
long value = keyNotConsumed;
// TODO(b/358569822) Remove below once we have nicer API for listening to shortcuts
@@ -2673,6 +2676,16 @@
value = mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event,
policyFlags);
}
+ if (fixSearchModifierFallbacks() && value == keyNotConsumed && event.isMetaPressed()) {
+ // If the key has not been consumed and includes the meta key, do not send the event
+ // to the app and attempt to generate a fallback.
+ final KeyCharacterMap kcm = event.getKeyCharacterMap();
+ final KeyCharacterMap.FallbackAction fallbackAction =
+ kcm.getFallbackAction(event.getKeyCode(), event.getMetaState());
+ if (fallbackAction != null) {
+ return keyNotConsumedGoFallback;
+ }
+ }
return value;
}
@@ -3316,9 +3329,10 @@
* @param token the window token that's about to receive this event
* @param event the key event that's being dispatched
* @param policyFlags the policy flags
- * @return negative value if the key should be skipped (not sent to the app). 0 if the key
- * should proceed getting dispatched to the app. positive value to indicate the additional
- * time delay, in nanoseconds, to wait before sending this key to the app.
+ * @return -1 if the key should be skipped (not sent to the app). -2 if the key should not
+ * be sent to the app, but it should still generate a fallback.
+ * 0 if the key should proceed getting dispatched to the app. positive value to indicate the
+ * additional time delay, in nanoseconds, to wait before sending this key to the app.
*/
long interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags);
@@ -3689,8 +3703,9 @@
@Override
public boolean transferTouchGesture(@NonNull IBinder fromChannelToken,
- @NonNull IBinder toChannelToken) {
- return InputManagerService.this.transferTouchGesture(fromChannelToken, toChannelToken);
+ @NonNull IBinder toChannelToken, boolean transferEntireGesture) {
+ return InputManagerService.this.transferTouchGesture(
+ fromChannelToken, toChannelToken, transferEntireGesture);
}
@Override
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index 32409d3..ccf1a2c 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -116,7 +116,7 @@
void setMinTimeBetweenUserActivityPokes(long millis);
boolean transferTouchGesture(IBinder fromChannelToken, IBinder toChannelToken,
- boolean isDragDrop);
+ boolean isDragDrop, boolean transferEntireGesture);
/**
* Transfer the current touch gesture to the window identified by 'destChannelToken' positioned
@@ -420,7 +420,7 @@
@Override
public native boolean transferTouchGesture(IBinder fromChannelToken, IBinder toChannelToken,
- boolean isDragDrop);
+ boolean isDragDrop, boolean transferEntireGesture);
@Override
@Deprecated
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 2066dbc..7ff41e3 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -5800,7 +5800,8 @@
return false;
}
}
- return mInputManagerInternal.transferTouchGesture(sourceInputToken, curHostInputToken);
+ return mInputManagerInternal.transferTouchGesture(
+ sourceInputToken, curHostInputToken, /* transferEntireGesture */ false);
}
@Override
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 6780866..6dff2d8 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -475,7 +475,8 @@
FUSED_PROVIDER,
ACTION_FUSED_PROVIDER,
com.android.internal.R.bool.config_enableFusedLocationOverlay,
- com.android.internal.R.string.config_fusedLocationProviderPackageName);
+ com.android.internal.R.string.config_fusedLocationProviderPackageName,
+ com.android.internal.R.bool.config_fusedLocationOverlayUnstableFallback);
if (fusedProvider != null) {
LocationProviderManager fusedManager = new LocationProviderManager(mContext, mInjector,
FUSED_PROVIDER, mPassiveManager);
@@ -498,14 +499,13 @@
com.android.internal.R.bool.config_useGnssHardwareProvider);
AbstractLocationProvider gnssProvider = null;
if (!useGnssHardwareProvider) {
- // TODO: Create a separate config_enableGnssLocationOverlay config resource
- // if we want to selectively enable a GNSS overlay but disable a fused overlay.
gnssProvider = ProxyLocationProvider.create(
mContext,
GPS_PROVIDER,
ACTION_GNSS_PROVIDER,
- com.android.internal.R.bool.config_enableFusedLocationOverlay,
- com.android.internal.R.string.config_gnssLocationProviderPackageName);
+ com.android.internal.R.bool.config_enableGnssLocationOverlay,
+ com.android.internal.R.string.config_gnssLocationProviderPackageName,
+ com.android.internal.R.bool.config_gnssLocationOverlayUnstableFallback);
}
if (gnssProvider == null) {
gnssProvider = mGnssManagerService.getGnssLocationProvider();
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
index bbf7732..7059c83 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
@@ -44,6 +44,7 @@
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import java.util.Collection;
import java.util.HashSet;
@@ -53,6 +54,9 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
@@ -71,6 +75,9 @@
/** The duration of wakelocks acquired during HAL callbacks */
private static final long WAKELOCK_TIMEOUT_MILLIS = 5 * 1000;
+ /** The timeout of open session request */
+ @VisibleForTesting static final long OPEN_SESSION_REQUEST_TIMEOUT_SECONDS = 10;
+
/*
* Internal interface used to invoke client callbacks.
*/
@@ -81,6 +88,9 @@
/** The context of the service. */
private final Context mContext;
+ /** The shared executor service for handling session operation timeout. */
+ private final ScheduledExecutorService mSessionTimeoutExecutor;
+
/** The proxy to talk to the Context Hub HAL for endpoint communication. */
private final IEndpointCommunication mHubInterface;
@@ -119,6 +129,8 @@
private SessionState mSessionState = SessionState.PENDING;
+ private ScheduledFuture<?> mSessionOpenTimeoutFuture;
+
private final boolean mRemoteInitiated;
/**
@@ -151,6 +163,17 @@
mSessionState = state;
}
+ public void setSessionOpenTimeoutFuture(ScheduledFuture<?> future) {
+ mSessionOpenTimeoutFuture = future;
+ }
+
+ public void cancelSessionOpenTimeoutFuture() {
+ if (mSessionOpenTimeoutFuture != null) {
+ mSessionOpenTimeoutFuture.cancel(false);
+ }
+ mSessionOpenTimeoutFuture = null;
+ }
+
public boolean isActive() {
return mSessionState == SessionState.ACTIVE;
}
@@ -240,7 +263,8 @@
@NonNull IContextHubEndpointCallback callback,
String packageName,
String attributionTag,
- ContextHubTransactionManager transactionManager) {
+ ContextHubTransactionManager transactionManager,
+ ScheduledExecutorService sessionTimeoutExecutor) {
mContext = context;
mHubInterface = hubInterface;
mEndpointManager = endpointManager;
@@ -250,6 +274,7 @@
mPackageName = packageName;
mAttributionTag = attributionTag;
mTransactionManager = transactionManager;
+ mSessionTimeoutExecutor = sessionTimeoutExecutor;
mPid = Binder.getCallingPid();
mUid = Binder.getCallingUid();
@@ -352,6 +377,7 @@
}
try {
mHubInterface.endpointSessionOpenComplete(sessionId);
+ info.cancelSessionOpenTimeoutFuture();
info.setSessionState(Session.SessionState.ACTIVE);
} catch (RemoteException | IllegalArgumentException | UnsupportedOperationException e) {
Log.e(TAG, "Exception while calling endpointSessionOpenComplete", e);
@@ -636,9 +662,10 @@
}
// Check & handle error cases for duplicated session id.
- final boolean existingSession;
- final boolean existingSessionActive;
synchronized (mOpenSessionLock) {
+ final boolean existingSession;
+ final boolean existingSessionActive;
+
if (hasSessionId(sessionId)) {
existingSession = true;
existingSessionActive = mSessionMap.get(sessionId).isActive();
@@ -652,19 +679,23 @@
} else {
existingSession = false;
existingSessionActive = false;
- mSessionMap.put(sessionId, new Session(initiator, true));
+ Session pendingSession = new Session(initiator, true);
+ pendingSession.setSessionOpenTimeoutFuture(
+ mSessionTimeoutExecutor.schedule(
+ () -> onEndpointSessionOpenRequestTimeout(sessionId),
+ OPEN_SESSION_REQUEST_TIMEOUT_SECONDS,
+ TimeUnit.SECONDS));
+ mSessionMap.put(sessionId, pendingSession);
}
- }
- if (existingSession) {
- if (existingSessionActive) {
- // Existing session is already active, call onSessionOpenComplete.
- openSessionRequestComplete(sessionId);
+ if (existingSession) {
+ if (existingSessionActive) {
+ // Existing session is already active, call onSessionOpenComplete.
+ openSessionRequestComplete(sessionId);
+ }
+ // Silence this request. The session open timeout future will handle clean up.
return Optional.empty();
}
- // Reject the session open request for now. Consider invalidating previous pending
- // session open request based on timeout.
- return Optional.of(Reason.OPEN_ENDPOINT_SESSION_REQUEST_REJECTED);
}
boolean success =
@@ -679,6 +710,20 @@
return success ? Optional.empty() : Optional.of(reason);
}
+ private void onEndpointSessionOpenRequestTimeout(int sessionId) {
+ synchronized (mOpenSessionLock) {
+ Session s = mSessionMap.get(sessionId);
+ if (s == null || s.isActive()) {
+ return;
+ }
+ Log.w(
+ TAG,
+ "onEndpointSessionOpenRequestTimeout: " + "clean up session, id: " + sessionId);
+ cleanupSessionResources(sessionId);
+ mEndpointManager.halCloseEndpointSessionNoThrow(sessionId, Reason.TIMEOUT);
+ }
+ }
+
private byte onMessageReceivedInternal(int sessionId, HubMessage message) {
synchronized (mOpenSessionLock) {
if (!isSessionActive(sessionId)) {
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java
index e156159..0dc1b83 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java
@@ -46,6 +46,8 @@
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.function.Consumer;
/**
@@ -112,6 +114,9 @@
/** The interface for endpoint communication (retrieved from HAL in init()) */
private IEndpointCommunication mHubInterface = null;
+ /** Thread pool executor for handling timeout */
+ private final ScheduledExecutorService mSessionTimeoutExecutor;
+
/*
* The list of previous registration records.
*/
@@ -154,15 +159,31 @@
}
}
+ @VisibleForTesting
+ ContextHubEndpointManager(
+ Context context,
+ IContextHubWrapper contextHubProxy,
+ HubInfoRegistry hubInfoRegistry,
+ ContextHubTransactionManager transactionManager,
+ ScheduledExecutorService scheduledExecutorService) {
+ mContext = context;
+ mContextHubProxy = contextHubProxy;
+ mHubInfoRegistry = hubInfoRegistry;
+ mTransactionManager = transactionManager;
+ mSessionTimeoutExecutor = scheduledExecutorService;
+ }
+
/* package */ ContextHubEndpointManager(
Context context,
IContextHubWrapper contextHubProxy,
HubInfoRegistry hubInfoRegistry,
ContextHubTransactionManager transactionManager) {
- mContext = context;
- mContextHubProxy = contextHubProxy;
- mHubInfoRegistry = hubInfoRegistry;
- mTransactionManager = transactionManager;
+ this(
+ context,
+ contextHubProxy,
+ hubInfoRegistry,
+ transactionManager,
+ new ScheduledThreadPoolExecutor(1));
}
/**
@@ -264,7 +285,8 @@
callback,
packageName,
attributionTag,
- mTransactionManager);
+ mTransactionManager,
+ mSessionTimeoutExecutor);
broker.register();
mEndpointMap.put(endpointId, broker);
diff --git a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
index 8fdc22b..a52b948 100644
--- a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
@@ -77,6 +77,22 @@
}
}
+ /**
+ * Creates and registers this proxy. If no suitable service is available for the proxy, returns
+ * null.
+ */
+ @Nullable
+ public static ProxyLocationProvider create(Context context, String provider, String action,
+ int enableOverlayResId, int nonOverlayPackageResId, int unstableOverlayFallbackResId) {
+ ProxyLocationProvider proxy = new ProxyLocationProvider(context, provider, action,
+ enableOverlayResId, nonOverlayPackageResId, unstableOverlayFallbackResId);
+ if (proxy.checkServiceResolves()) {
+ return proxy;
+ } else {
+ return null;
+ }
+ }
+
final Object mLock = new Object();
final Context mContext;
@@ -111,6 +127,24 @@
mRequest = ProviderRequest.EMPTY_REQUEST;
}
+ private ProxyLocationProvider(Context context, String provider, String action,
+ int enableOverlayResId, int nonOverlayPackageResId, int unstableOverlayFallbackResId) {
+ // safe to use direct executor since our locks are not acquired in a code path invoked by
+ // our owning provider
+ super(DIRECT_EXECUTOR, null, null, Collections.emptySet());
+
+ mContext = context;
+ boolean unstableFallbackEnabled =
+ context.getResources().getBoolean(unstableOverlayFallbackResId);
+ mServiceWatcher = ServiceWatcher.create(context, provider, unstableFallbackEnabled,
+ CurrentUserServiceSupplier.createFromConfig(context, action, enableOverlayResId,
+ nonOverlayPackageResId), this);
+ mName = provider;
+
+ mProxy = null;
+ mRequest = ProviderRequest.EMPTY_REQUEST;
+ }
+
private boolean checkServiceResolves() {
return mServiceWatcher.checkServiceResolves();
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 988924d..e4e81ac 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -25,7 +25,6 @@
import static android.media.MediaRouter2.SCANNING_STATE_WHILE_INTERACTIVE;
import static android.media.MediaRouter2Utils.getOriginalId;
import static android.media.MediaRouter2Utils.getProviderId;
-
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION;
import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_DESELECT_ROUTE;
@@ -78,14 +77,12 @@
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
-
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.media.flags.Flags;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
import com.android.server.statusbar.StatusBarManagerInternal;
-
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -3857,6 +3854,16 @@
&& activelyScanningPackages.equals(mUserRecord.mActivelyScanningPackages)) {
return false;
}
+
+ var oldShouldPerformActiveScan =
+ mUserRecord.mCompositeDiscoveryPreference.shouldPerformActiveScan();
+ var newShouldPerformActiveScan = newPreference.shouldPerformActiveScan();
+ if (oldShouldPerformActiveScan != newShouldPerformActiveScan) {
+ // State access is synchronized with service.mLock.
+ // Linter still fails due to b/323906305#comment3
+ mMediaRouterMetricLogger.updateScanningState(newShouldPerformActiveScan);
+ }
+
mUserRecord.mCompositeDiscoveryPreference = newPreference;
mUserRecord.mActivelyScanningPackages = activelyScanningPackages;
}
diff --git a/services/core/java/com/android/server/media/MediaRouterMetricLogger.java b/services/core/java/com/android/server/media/MediaRouterMetricLogger.java
index 56d2a1b..dc94ff2 100644
--- a/services/core/java/com/android/server/media/MediaRouterMetricLogger.java
+++ b/services/core/java/com/android/server/media/MediaRouterMetricLogger.java
@@ -16,6 +16,8 @@
package com.android.server.media;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SCANNING_STARTED;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SCANNING_STOPPED;
import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_FAILED_TO_REROUTE_SYSTEM_MEDIA;
import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_COMMAND;
import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_NETWORK_ERROR;
@@ -114,6 +116,33 @@
}
/**
+ * Logs the overall scanning state.
+ *
+ * @param isScanning The scanning state for the user.
+ */
+ public void updateScanningState(boolean isScanning) {
+ if (!isScanning) {
+ logScanningStopped();
+ } else {
+ logScanningStarted();
+ }
+ }
+
+ /** Logs the scanning started event. */
+ private void logScanningStarted() {
+ logMediaRouterEvent(
+ MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SCANNING_STARTED,
+ MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
+ }
+
+ /** Logs the scanning stopped event. */
+ private void logScanningStopped() {
+ logMediaRouterEvent(
+ MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SCANNING_STOPPED,
+ MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
+ }
+
+ /**
* Converts a reason code from {@link MediaRoute2ProviderService} to a result code for logging.
*
* @param reason The reason code from {@link MediaRoute2ProviderService}.
diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java
index 9a09807..f4fe8e12 100644
--- a/services/core/java/com/android/server/media/quality/MediaQualityService.java
+++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java
@@ -444,7 +444,7 @@
public SoundProfile createSoundProfile(SoundProfile sp, int userId) {
if ((sp.getPackageName() != null && !sp.getPackageName().isEmpty()
&& !incomingPackageEqualsCallingUidPackage(sp.getPackageName()))
- && !hasGlobalPictureQualityServicePermission()) {
+ && !hasGlobalSoundQualityServicePermission()) {
mMqManagerNotifier.notifyOnSoundProfileError(null, SoundProfile.ERROR_NO_PERMISSION,
Binder.getCallingUid(), Binder.getCallingPid());
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index 52ddb80..695bf61 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -82,4 +82,11 @@
byte[] getBackupPayload(int user, BackupRestoreEventLogger logger);
void applyRestore(byte[] payload, int user, BackupRestoreEventLogger logger);
+
+ /**
+ * Notifies NotificationManager that the system decorations should be removed from the display.
+ *
+ * @param displayId display ID
+ */
+ void onDisplayRemoveSystemDecorations(int displayId);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 06fc9b0..c1e46a6 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1877,73 +1877,35 @@
}
};
- private void unclassifyNotificationsForUser(final int userId) {
- if (DBG) {
- Slog.v(TAG, "unclassifyForUser: " + userId);
- }
- unclassifyNotificationsFiltered((r) -> r.getUserId() == userId);
+ private void applyNotificationUpdateForUser(final int userId,
+ NotificationUpdate notificationUpdate) {
+ applyUpdateForNotificationsFiltered((r) -> r.getUserId() == userId,
+ notificationUpdate);
}
- private void unclassifyNotificationsForUid(final int userId, @NonNull final String pkg) {
- if (DBG) {
- Slog.v(TAG, "unclassifyForUid userId: " + userId + " pkg: " + pkg);
- }
- unclassifyNotificationsFiltered((r) ->
+ private void applyNotificationUpdateForUid(final int userId, @NonNull final String pkg,
+ NotificationUpdate notificationUpdate) {
+ applyUpdateForNotificationsFiltered((r) ->
r.getUserId() == userId
- && Objects.equals(r.getSbn().getPackageName(), pkg));
+ && Objects.equals(r.getSbn().getPackageName(), pkg),
+ notificationUpdate);
}
- private void unclassifyNotificationsForUserAndType(final int userId,
- final @Types int bundleType) {
- if (DBG) {
- Slog.v(TAG,
- "unclassifyForUserAndType userId: " + userId + " bundleType: " + bundleType);
- }
+ private void applyNotificationUpdateForUserAndChannelType(final int userId,
+ final @Types int bundleType, NotificationUpdate notificationUpdate) {
final String bundleChannelId = NotificationChannel.getChannelIdForBundleType(bundleType);
- unclassifyNotificationsFiltered((r) ->
+ applyUpdateForNotificationsFiltered((r) ->
r.getUserId() == userId
&& r.getChannel() != null
- && Objects.equals(bundleChannelId, r.getChannel().getId()));
+ && Objects.equals(bundleChannelId, r.getChannel().getId()),
+ notificationUpdate);
}
- private void unclassifyNotificationsFiltered(Predicate<NotificationRecord> filter) {
- if (!(notificationClassificationUi() && notificationRegroupOnClassification())) {
- return;
- }
- synchronized (mNotificationLock) {
- for (int i = 0; i < mEnqueuedNotifications.size(); i++) {
- final NotificationRecord r = mEnqueuedNotifications.get(i);
- if (filter.test(r)) {
- unclassifyNotificationLocked(r);
- }
- }
-
- for (int i = 0; i < mNotificationList.size(); i++) {
- final NotificationRecord r = mNotificationList.get(i);
- if (filter.test(r)) {
- unclassifyNotificationLocked(r);
- }
- }
- }
- }
-
- @GuardedBy("mNotificationLock")
- private void unclassifyNotificationLocked(@NonNull final NotificationRecord r) {
- if (DBG) {
- Slog.v(TAG, "unclassifyNotification: " + r);
- }
- // Only NotificationRecord's mChannel is updated when bundled, the Notification
- // mChannelId will always be the original channel.
- String origChannelId = r.getNotification().getChannelId();
- NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel(
- r.getSbn().getPackageName(), r.getUid(), origChannelId, false);
- String currChannelId = r.getChannel().getId();
- boolean isClassified = NotificationChannel.SYSTEM_RESERVED_IDS.contains(currChannelId);
- if (originalChannel != null && !origChannelId.equals(currChannelId) && isClassified) {
- r.updateNotificationChannel(originalChannel);
- mGroupHelper.onNotificationUnbundled(r,
- GroupHelper.isOriginalGroupSummaryPresent(r, mSummaryByGroupKey));
- }
+ private void applyNotificationUpdateForUserAndType(final int userId,
+ final @Types int bundleType, NotificationUpdate notificationUpdate) {
+ applyUpdateForNotificationsFiltered(
+ (r) -> r.getUserId() == userId && r.getBundleType() == bundleType,
+ notificationUpdate);
}
@VisibleForTesting
@@ -1956,7 +1918,7 @@
if (r == null) {
return;
}
- unclassifyNotificationLocked(r);
+ unclassifyNotificationLocked(r, true);
}
}
@@ -1974,50 +1936,36 @@
}
}
- private void reclassifyNotificationsFiltered(Predicate<NotificationRecord> filter) {
- if (!(notificationClassificationUi() && notificationRegroupOnClassification())) {
- return;
+ @GuardedBy("mNotificationLock")
+ private void unclassifyNotificationLocked(@NonNull final NotificationRecord r,
+ boolean isPosted) {
+ if (DBG) {
+ Slog.v(TAG, "unclassifyNotification: " + r);
}
- synchronized (mNotificationLock) {
- for (int i = 0; i < mEnqueuedNotifications.size(); i++) {
- final NotificationRecord r = mEnqueuedNotifications.get(i);
- if (filter.test(r)) {
- reclassifyNotificationLocked(r, false);
- }
- }
-
- for (int i = 0; i < mNotificationList.size(); i++) {
- final NotificationRecord r = mNotificationList.get(i);
- if (filter.test(r)) {
- reclassifyNotificationLocked(r, true);
- }
- }
+ // Only NotificationRecord's mChannel is updated when bundled, the Notification
+ // mChannelId will always be the original channel.
+ String origChannelId = r.getNotification().getChannelId();
+ NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel(
+ r.getSbn().getPackageName(), r.getUid(), origChannelId, false);
+ String currChannelId = r.getChannel().getId();
+ boolean isClassified = NotificationChannel.SYSTEM_RESERVED_IDS.contains(currChannelId);
+ if (originalChannel != null && !origChannelId.equals(currChannelId) && isClassified) {
+ r.updateNotificationChannel(originalChannel);
+ mGroupHelper.onNotificationUnbundled(r,
+ GroupHelper.isOriginalGroupSummaryPresent(r, mSummaryByGroupKey));
}
}
- private void reclassifyNotificationsForUserAndType(final int userId,
- final @Types int bundleType) {
- if (DBG) {
- Slog.v(TAG, "reclassifyNotificationsForUserAndType userId: " + userId + " bundleType: "
- + bundleType);
- }
- reclassifyNotificationsFiltered(
- (r) -> r.getUserId() == userId && r.getBundleType() == bundleType);
- }
+ @GuardedBy("mNotificationLock")
+ private void unsummarizeNotificationLocked(@NonNull final NotificationRecord r,
+ boolean isPosted) {
+ Bundle signals = new Bundle();
+ signals.putString(KEY_SUMMARIZATION, null);
+ Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "",
+ r.getSbn().getUserId());
+ r.addAdjustment(adjustment);
+ mRankingHandler.requestSort();
- private void reclassifyNotificationsForUid(final int userId, final String pkg) {
- if (DBG) {
- Slog.v(TAG, "reclassifyNotificationsForUid userId: " + userId + " pkg: " + pkg);
- }
- reclassifyNotificationsFiltered((r) ->
- r.getUserId() == userId && Objects.equals(r.getSbn().getPackageName(), pkg));
- }
-
- private void reclassifyNotificationsForUser(final int userId) {
- if (DBG) {
- Slog.v(TAG, "reclassifyAllNotificationsForUser: " + userId);
- }
- reclassifyNotificationsFiltered((r) -> r.getUserId() == userId);
}
@GuardedBy("mNotificationLock")
@@ -2043,6 +1991,33 @@
}
}
+ /**
+ * Given a filter and a function to update a notification record, runs that function on all
+ * enqueued and posted notifications that match the filter
+ */
+ private void applyUpdateForNotificationsFiltered(Predicate<NotificationRecord> filter,
+ NotificationUpdate notificationUpdate) {
+ synchronized (mNotificationLock) {
+ for (int i = 0; i < mEnqueuedNotifications.size(); i++) {
+ final NotificationRecord r = mEnqueuedNotifications.get(i);
+ if (filter.test(r)) {
+ notificationUpdate.apply(r, false);
+ }
+ }
+
+ for (int i = 0; i < mNotificationList.size(); i++) {
+ final NotificationRecord r = mNotificationList.get(i);
+ if (filter.test(r)) {
+ notificationUpdate.apply(r, true);
+ }
+ }
+ }
+ }
+
+ private interface NotificationUpdate {
+ void apply(NotificationRecord r, boolean isPosted);
+ }
+
NotificationManagerPrivate mNotificationManagerPrivate = new NotificationManagerPrivate() {
@Nullable
@Override
@@ -4475,9 +4450,11 @@
public void allowAssistantAdjustment(String adjustmentType) {
checkCallerIsSystemOrSystemUiOrShell();
mAssistants.allowAdjustmentType(adjustmentType);
+ int userId = UserHandle.getUserId(Binder.getCallingUid());
if ((notificationClassificationUi() && notificationRegroupOnClassification())) {
if (KEY_TYPE.equals(adjustmentType)) {
- reclassifyNotificationsForUser(UserHandle.getUserId(Binder.getCallingUid()));
+ applyNotificationUpdateForUser(userId,
+ NotificationManagerService.this::reclassifyNotificationLocked);
}
}
handleSavePolicyFile();
@@ -4488,9 +4465,17 @@
public void disallowAssistantAdjustment(String adjustmentType) {
checkCallerIsSystemOrSystemUiOrShell();
mAssistants.disallowAdjustmentType(adjustmentType);
+ int userId = UserHandle.getUserId(Binder.getCallingUid());
if ((notificationClassificationUi() && notificationRegroupOnClassification())) {
if (KEY_TYPE.equals(adjustmentType)) {
- unclassifyNotificationsForUser(UserHandle.getUserId(Binder.getCallingUid()));
+ applyNotificationUpdateForUser(userId,
+ NotificationManagerService.this::unclassifyNotificationLocked);
+ }
+ }
+ if (nmSummarizationUi() || nmSummarization()) {
+ if (KEY_SUMMARIZATION.equals(adjustmentType)) {
+ applyNotificationUpdateForUser(userId,
+ NotificationManagerService.this::unsummarizeNotificationLocked);
}
}
handleSavePolicyFile();
@@ -4539,11 +4524,13 @@
mAssistants.setAssistantAdjustmentKeyTypeState(type, enabled);
if ((notificationClassificationUi() && notificationRegroupOnClassification())) {
if (enabled) {
- reclassifyNotificationsForUserAndType(
- UserHandle.getUserId(Binder.getCallingUid()), type);
+ applyNotificationUpdateForUserAndType(
+ UserHandle.getUserId(Binder.getCallingUid()), type,
+ NotificationManagerService.this::reclassifyNotificationLocked);
} else {
- unclassifyNotificationsForUserAndType(
- UserHandle.getUserId(Binder.getCallingUid()), type);
+ applyNotificationUpdateForUserAndChannelType(
+ UserHandle.getUserId(Binder.getCallingUid()), type,
+ NotificationManagerService.this::unclassifyNotificationLocked);
}
}
handleSavePolicyFile();
@@ -4569,11 +4556,17 @@
if (notificationClassificationUi() && notificationRegroupOnClassification()
&& key.equals(KEY_TYPE)) {
if (enabled) {
- reclassifyNotificationsForUid(UserHandle.getUserId(Binder.getCallingUid()),
- pkg);
+ applyNotificationUpdateForUid(UserHandle.getUserId(Binder.getCallingUid()),
+ pkg, NotificationManagerService.this::reclassifyNotificationLocked);
} else {
- unclassifyNotificationsForUid(UserHandle.getUserId(Binder.getCallingUid()),
- pkg);
+ applyNotificationUpdateForUid(UserHandle.getUserId(Binder.getCallingUid()),
+ pkg, NotificationManagerService.this::unclassifyNotificationLocked);
+ }
+ }
+ if (nmSummarization() || nmSummarizationUi()) {
+ if (KEY_SUMMARIZATION.equals(key) && !enabled) {
+ applyNotificationUpdateForUid(UserHandle.getUserId(Binder.getCallingUid()),
+ pkg, NotificationManagerService.this::unsummarizeNotificationLocked);
}
}
handleSavePolicyFile();
@@ -8214,6 +8207,18 @@
// This can also throw IllegalStateException if called too late.
mZenModeHelper.setDeviceEffectsApplier(applier);
}
+
+ @Override
+ public void onDisplayRemoveSystemDecorations(int displayId) {
+ synchronized (mToastQueue) {
+ for (int i = mToastQueue.size() - 1; i >= 0; i--) {
+ final ToastRecord toast = mToastQueue.get(i);
+ if (toast.displayId == displayId) {
+ cancelToastLocked(i);
+ }
+ }
+ }
+ }
};
private static boolean isBigPictureWithBitmapOrIcon(Notification n) {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index cec5a93..700f6faf 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -999,7 +999,7 @@
return null;
}
- public String getSummarization() {
+ public @Nullable String getSummarization() {
if ((android.app.Flags.nmSummarizationUi() || android.app.Flags.nmSummarization())) {
return mSummarization;
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 2dd6798..5160319 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -379,9 +379,10 @@
public List<UserHandle> getUserProfiles() {
int[] userIds;
if (!canAccessHiddenProfile(getCallingUid(), getCallingPid())) {
- userIds = mUm.getProfileIdsExcludingHidden(getCallingUserId(), /* enabled= */ true);
+ userIds = mUserManagerInternal.getProfileIdsExcludingHidden(getCallingUserId(),
+ /* enabled= */ true);
} else {
- userIds = mUm.getEnabledProfileIds(getCallingUserId());
+ userIds = mUserManagerInternal.getProfileIds(getCallingUserId(), true);
}
final List<UserHandle> result = new ArrayList<>(userIds.length);
for (int userId : userIds) {
@@ -398,9 +399,10 @@
int[] userIds;
if (!canAccessHiddenProfile(callingUid, Binder.getCallingPid())) {
- userIds = mUm.getProfileIdsExcludingHidden(getCallingUserId(), /* enabled= */ true);
+ userIds = mUserManagerInternal.getProfileIdsExcludingHidden(getCallingUserId(),
+ /* enabled= */ true);
} else {
- userIds = mUm.getEnabledProfileIds(getCallingUserId());
+ userIds = mUserManagerInternal.getProfileIds(getCallingUserId(), true);
}
final long token = Binder.clearCallingIdentity();
@@ -503,16 +505,11 @@
return true;
}
- long ident = injectClearCallingIdentity();
- try {
- final UserInfo callingUserInfo = mUm.getUserInfo(callingUserId);
- if (callingUserInfo != null && callingUserInfo.isProfile()) {
- Slog.w(TAG, message + " for another profile "
- + targetUserId + " from " + callingUserId + " not allowed");
- return false;
- }
- } finally {
- injectRestoreCallingIdentity(ident);
+ final UserInfo callingUserInfo = mUserManagerInternal.getUserInfo(callingUserId);
+ if (callingUserInfo != null && callingUserInfo.isProfile()) {
+ Slog.w(TAG, message + " for another profile "
+ + targetUserId + " from " + callingUserId + " not allowed");
+ return false;
}
if (isHiddenProfile(UserHandle.of(targetUserId))
@@ -529,9 +526,9 @@
return false;
}
- long identity = injectClearCallingIdentity();
try {
- UserProperties properties = mUm.getUserProperties(targetUser);
+ UserProperties properties = mUserManagerInternal
+ .getUserProperties(targetUser.getIdentifier());
if (properties == null) {
return false;
}
@@ -540,8 +537,6 @@
== UserProperties.PROFILE_API_VISIBILITY_HIDDEN;
} catch (IllegalArgumentException e) {
return false;
- } finally {
- injectRestoreCallingIdentity(identity);
}
}
@@ -686,7 +681,7 @@
final int callingUid = injectBinderCallingUid();
final long ident = injectClearCallingIdentity();
try {
- if (mUm.getUserInfo(user.getIdentifier()).isManagedProfile()) {
+ if (mUserManagerInternal.getUserInfo(user.getIdentifier()).isManagedProfile()) {
// Managed profile should not show hidden apps
return launcherActivities;
}
@@ -1713,7 +1708,7 @@
}
final long identity = Binder.clearCallingIdentity();
try {
- String userType = mUm.getUserInfo(user.getIdentifier()).userType;
+ String userType = mUserManagerInternal.getUserInfo(user.getIdentifier()).userType;
Set<String> preInstalledPackages = mUm.getPreInstallableSystemPackages(userType);
if (preInstalledPackages == null) {
return new ArrayList<>();
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index af788ea..e00d80f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -3107,8 +3107,17 @@
mInternalProgress = 0.5f;
computeProgressLocked(true);
}
+ final File libDir = new File(stageDir, NativeLibraryHelper.LIB_DIR_NAME);
+ if (!mayInheritNativeLibs()) {
+ // Start from a clean slate
+ NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
+ }
+ // Skip native libraries processing for archival installation.
+ if (isArchivedInstallation()) {
+ return;
+ }
extractNativeLibraries(
- mPackageLite, stageDir, params.abiOverride, mayInheritNativeLibs());
+ mPackageLite, libDir, params.abiOverride);
}
}
}
@@ -4505,21 +4514,10 @@
Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
}
- private void extractNativeLibraries(PackageLite packageLite, File packageDir,
- String abiOverride, boolean inherit)
+ private void extractNativeLibraries(PackageLite packageLite, File libDir,
+ String abiOverride)
throws PackageManagerException {
Objects.requireNonNull(packageLite);
- final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
- if (!inherit) {
- // Start from a clean slate
- NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
- }
-
- // Skip native libraries processing for archival installation.
- if (isArchivedInstallation()) {
- return;
- }
-
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(packageLite);
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index f88681d..41ce4fa 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SpecialUsers.CanBeNULL;
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.LauncherUserInfo;
@@ -367,6 +368,21 @@
public abstract @NonNull int[] getProfileIds(@UserIdInt int userId, boolean enabledOnly);
/**
+ * Returns a list of the users that are associated with the specified user, including the user
+ * itself. This includes the user, its profiles, its parent, and its parent's other profiles,
+ * as applicable.
+ *
+ * <p>Note that this includes only profile types that are not hidden.
+ *
+ * @param userId id of the user to return profiles for
+ * @param enabledOnly whether return only {@link UserInfo#isEnabled() enabled} profiles
+ * @return A non-empty array of ids of profiles associated with the specified user if the user
+ * exists. Otherwise, an empty array.
+ */
+ public abstract @NonNull int[] getProfileIdsExcludingHidden(@UserIdInt int userId,
+ boolean enabledOnly);
+
+ /**
* Checks if the {@code callingUserId} and {@code targetUserId} are same or in same group
* and that the {@code callingUserId} is not a profile and {@code targetUserId} is enabled.
*
@@ -620,11 +636,17 @@
* Returns the user id of the communal profile, or {@link android.os.UserHandle#USER_NULL}
* if there is no such user.
*/
- public abstract @UserIdInt int getCommunalProfileId();
+ public abstract @CanBeNULL @UserIdInt int getCommunalProfileId();
/**
- * Checks whether to show a notification for sounds (e.g., alarms, timers, etc.) from
- * background users.
+ * Returns the user id of the supervising profile, or {@link android.os.UserHandle#USER_NULL} if
+ * there is no such user.
+ */
+ public abstract @CanBeNULL @UserIdInt int getSupervisingProfileId();
+
+ /**
+ * Checks whether to show a notification for sounds (e.g., alarms, timers, etc.) from background
+ * users.
*/
public static boolean shouldShowNotificationForBackgroundUserSounds() {
return Flags.addUiForSoundsFromBackgroundUsers() && Resources.getSystem().getBoolean(
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 33a7e74..0ea9af4 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1530,6 +1530,20 @@
return UserHandle.USER_NULL;
}
+ /** Returns the currently-designated supervising profile, or USER_NULL if not present. */
+ private @CanBeNULL @UserIdInt int getSupervisingProfileId() {
+ synchronized (mUsersLock) {
+ final int userSize = mUsers.size();
+ for (int i = 0; i < userSize; i++) {
+ final UserInfo user = mUsers.valueAt(i).info;
+ if (user.isSupervisingProfile() && !mRemovingUserIds.get(user.id)) {
+ return user.id;
+ }
+ }
+ }
+ return UserHandle.USER_NULL;
+ }
+
public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
return getUsers(/*excludePartial= */ true, excludeDying, /* excludePreCreated= */
true);
@@ -8035,6 +8049,14 @@
}
@Override
+ public int[] getProfileIdsExcludingHidden(@UserIdInt int userId, boolean enabledOnly) {
+ synchronized (mUsersLock) {
+ return getProfileIdsLU(userId, null /* userType */, enabledOnly, /* excludeHidden */
+ true).toArray();
+ }
+ }
+
+ @Override
public @Nullable LauncherUserInfo getLauncherUserInfo(@UserIdInt int userId) {
UserInfo userInfo;
synchronized (mUsersLock) {
@@ -8348,10 +8370,14 @@
}
@Override
- public @UserIdInt int getCommunalProfileId() {
+ public @CanBeNULL @UserIdInt int getCommunalProfileId() {
return getCommunalProfileIdUnchecked();
}
+ @Override
+ public @CanBeNULL @UserIdInt int getSupervisingProfileId() {
+ return UserManagerService.this.getSupervisingProfileId();
+ }
} // class LocalService
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 2744721..8cf0481 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -86,6 +86,7 @@
import static com.android.hardware.input.Flags.enableNew25q2Keycodes;
import static com.android.hardware.input.Flags.enableTalkbackAndMagnifierKeyGestures;
import static com.android.hardware.input.Flags.enableVoiceAccessKeyGestures;
+import static com.android.hardware.input.Flags.fixSearchModifierFallbacks;
import static com.android.hardware.input.Flags.inputManagerLifecycleSupport;
import static com.android.hardware.input.Flags.keyboardA11yShortcutControl;
import static com.android.hardware.input.Flags.modifierShortcutDump;
@@ -4181,6 +4182,13 @@
return true;
}
+ if (fixSearchModifierFallbacks()) {
+ // Pass event as unhandled to give other services, e.g. InputManagerService, the
+ // opportunity to determine if the event can be modified, e.g. generating a fallback for
+ // meta/search events.
+ return false;
+ }
+
// Reserve all the META modifier combos for system behavior
return (metaState & KeyEvent.META_META_ON) != 0;
}
@@ -4625,6 +4633,9 @@
@SuppressLint("MissingPermission")
private void injectBackGesture(long downtime) {
+ if (mActivityTaskManagerInternal.requestBackGesture()) {
+ return;
+ }
// Create and inject down event
KeyEvent downEvent = new KeyEvent(downtime, downtime, KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */,
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 3eac4b5..bef5058 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -130,12 +130,12 @@
import com.android.internal.util.Preconditions;
import com.android.server.EventLogTags;
import com.android.server.LockGuard;
+import com.android.server.PackageWatchdog;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.UiThread;
import com.android.server.Watchdog;
import com.android.server.am.BatteryStatsService;
-import com.android.server.crashrecovery.CrashRecoveryHelper;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight;
@@ -4113,7 +4113,7 @@
}
}
if (mHandler == null || !mSystemReady) {
- if (CrashRecoveryHelper.isRecoveryTriggeredReboot()) {
+ if (PackageWatchdog.isRecoveryTriggeredReboot()) {
// If we're stuck in a really low-level reboot loop, and a
// rescue party is trying to prompt the user for a factory data
// reset, we must GET TO DA CHOPPA!
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index d209ea9..4ae1b4e 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -59,7 +59,7 @@
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.crashrecovery.CrashRecoveryHelper;
+import com.android.server.PackageWatchdog;
import com.android.server.LocalServices;
import com.android.server.statusbar.StatusBarManagerInternal;
@@ -339,7 +339,7 @@
com.android.internal.R.string.reboot_to_update_reboot));
}
} else if (mReason != null && mReason.equals(PowerManager.REBOOT_RECOVERY)) {
- if (CrashRecoveryHelper.isRecoveryTriggeredReboot()) {
+ if (PackageWatchdog.isRecoveryTriggeredReboot()) {
// We're not actually doing a factory reset yet; we're rebooting
// to ask the user if they'd like to reset, so give them a less
// scary dialog message.
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 5ee9b7d..46c497d 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -176,7 +176,9 @@
try {
final HeadroomCallbackData data;
synchronized (mTemperatureWatcher.mSamples) {
- Slog.d(TAG, "Updating skin threshold: " + threshold);
+ if (DEBUG) {
+ Slog.d(TAG, "Updating skin threshold: " + threshold);
+ }
mTemperatureWatcher.updateTemperatureThresholdLocked(threshold, true);
data = mTemperatureWatcher.getHeadroomCallbackDataLocked();
}
@@ -454,7 +456,9 @@
&& temperature.getType() == Temperature.TYPE_SKIN) {
final HeadroomCallbackData data;
synchronized (mTemperatureWatcher.mSamples) {
- Slog.d(TAG, "Updating new temperature: " + temperature);
+ if (DEBUG) {
+ Slog.d(TAG, "Updating new temperature: " + temperature);
+ }
mTemperatureWatcher.updateTemperatureSampleLocked(System.currentTimeMillis(),
temperature);
mTemperatureWatcher.mCachedHeadrooms.clear();
@@ -1878,6 +1882,7 @@
@VisibleForTesting
long mInactivityThresholdMillis = INACTIVITY_THRESHOLD_MILLIS;
+ @GuardedBy("mSamples")
private final Handler mHandler = BackgroundThread.getHandler();
/**
@@ -1900,6 +1905,9 @@
@GuardedBy("mSamples")
private long mLastForecastCallTimeMillis = 0;
+ private final Runnable mGetAndUpdateTemperatureSamplesRunnable =
+ this::getAndUpdateTemperatureSamples;
+
void getAndUpdateThresholds() {
List<TemperatureThreshold> thresholds =
mHalWrapper.getTemperatureThresholds(true, Temperature.TYPE_SKIN);
@@ -1930,7 +1938,9 @@
return;
}
if (override) {
- Slog.d(TAG, "Headroom cache cleared on threshold update " + threshold);
+ if (DEBUG) {
+ Slog.d(TAG, "Headroom cache cleared on threshold update " + threshold);
+ }
mCachedHeadrooms.clear();
Arrays.fill(mHeadroomThresholds, Float.NaN);
}
@@ -1962,7 +1972,7 @@
< mInactivityThresholdMillis) {
// Trigger this again after a second as long as forecast has been called more
// recently than the inactivity timeout
- mHandler.postDelayed(this::getAndUpdateTemperatureSamples, 1000);
+ mHandler.postDelayed(mGetAndUpdateTemperatureSamplesRunnable, 1000);
} else {
// Otherwise, we've been idle for at least 10 seconds, so we should
// shut down
@@ -1974,6 +1984,9 @@
long now = SystemClock.elapsedRealtime();
final List<Temperature> temperatures = mHalWrapper.getCurrentTemperatures(true,
Temperature.TYPE_SKIN);
+ if (DEBUG) {
+ Slog.d(TAG, "Thermal HAL getCurrentTemperatures result: " + temperatures);
+ }
for (Temperature temperature : temperatures) {
updateTemperatureSampleLocked(now, temperature);
}
@@ -2080,10 +2093,16 @@
}
synchronized (mSamples) {
mLastForecastCallTimeMillis = SystemClock.elapsedRealtime();
- if (mSamples.isEmpty()) {
+ if (!mHandler.hasCallbacks(mGetAndUpdateTemperatureSamplesRunnable)) {
+ if (DEBUG) {
+ Slog.d(TAG, "No temperature update callback, scheduling one");
+ }
getAndUpdateTemperatureSamples();
+ } else {
+ if (DEBUG) {
+ Slog.d(TAG, "Temperature update callback already exists");
+ }
}
-
// If somehow things take much longer than expected or there are no temperatures
// to sample, return early
if (mSamples.isEmpty()) {
@@ -2103,8 +2122,11 @@
Binder.getCallingUid(),
FrameworkStatsLog.THERMAL_HEADROOM_CALLED__API_STATUS__SUCCESS,
headroom, forecastSeconds);
- Slog.d(TAG, "Headroom forecast in " + forecastSeconds + "s served from cache: "
- + headroom);
+ if (DEBUG) {
+ Slog.d(TAG,
+ "Headroom forecast in " + forecastSeconds + "s served from cache: "
+ + headroom);
+ }
return headroom;
}
@@ -2133,7 +2155,10 @@
Binder.getCallingUid(),
FrameworkStatsLog.THERMAL_HEADROOM_CALLED__API_STATUS__SUCCESS,
headroom, 0);
- Slog.d(TAG, "Headroom forecast in 0s served from cache: " + headroom);
+ if (DEBUG) {
+ Slog.d(TAG,
+ "Headroom forecast in 0s served from cache: " + headroom);
+ }
return headroom;
}
// Don't try to forecast, just use the latest one we have
@@ -2182,7 +2207,9 @@
getForecast(DEFAULT_FORECAST_SECONDS),
DEFAULT_FORECAST_SECONDS,
Arrays.copyOf(mHeadroomThresholds, mHeadroomThresholds.length));
- Slog.d(TAG, "New headroom callback data: " + data);
+ if (DEBUG) {
+ Slog.d(TAG, "New headroom callback data: " + data);
+ }
return data;
}
diff --git a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
index f90da64..a9896e9 100644
--- a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
@@ -272,15 +272,6 @@
mHandler.removeMessages(SYNC_WAKELOCK_CHANGE);
}
- @Override
- public void scheduleSyncDueToBatteryLevelChange(long delayMillis) {
- synchronized (BatteryExternalStatsWorker.this) {
- scheduleDelayedSyncLocked(SYNC_BATTERY_LEVEL_CHANGE,
- () -> scheduleSync("battery-level", UPDATE_ALL),
- delayMillis);
- }
- }
-
@GuardedBy("this")
private void cancelSyncDueToBatteryLevelChangeLocked() {
mHandler.removeMessages(SYNC_BATTERY_LEVEL_CHANGE);
diff --git a/services/core/java/com/android/server/power/stats/BatteryHistoryDirectory.java b/services/core/java/com/android/server/power/stats/BatteryHistoryDirectory.java
index 7cd9bdb..b4ca784 100644
--- a/services/core/java/com/android/server/power/stats/BatteryHistoryDirectory.java
+++ b/services/core/java/com/android/server/power/stats/BatteryHistoryDirectory.java
@@ -505,7 +505,9 @@
for (int i = 0; i < mHistoryFiles.size(); i++) {
size += (int) mHistoryFiles.get(i).atomicFile.getBaseFile().length();
}
- while (size > mMaxHistorySize) {
+ // Trim until the directory size is within the limit or there is just one most
+ // recent file left in the directory
+ while (size > mMaxHistorySize && mHistoryFiles.size() > 1) {
BatteryHistoryFile oldest = mHistoryFiles.get(0);
int length = (int) oldest.atomicFile.getBaseFile().length();
oldest.atomicFile.delete();
diff --git a/services/core/java/com/android/server/power/stats/BatteryHistoryStepDetailsProvider.java b/services/core/java/com/android/server/power/stats/BatteryHistoryStepDetailsProvider.java
new file mode 100644
index 0000000..cd76125
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/BatteryHistoryStepDetailsProvider.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import android.hardware.power.stats.PowerEntity;
+import android.hardware.power.stats.State;
+import android.hardware.power.stats.StateResidency;
+import android.hardware.power.stats.StateResidencyResult;
+import android.os.BatteryStats;
+import android.power.PowerStatsInternal;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.server.LocalServices;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+class BatteryHistoryStepDetailsProvider {
+ public static final String TAG = "BatteryHistoryStepDetails";
+ private static final boolean DEBUG = false;
+
+ private static final int POWER_STATS_QUERY_TIMEOUT_MILLIS = 2000;
+ private static final int MAX_LOW_POWER_STATS_SIZE = 32768;
+
+ private final BatteryStatsImpl mBatteryStats;
+
+ private final BatteryStats.HistoryStepDetails mDetails = new BatteryStats.HistoryStepDetails();
+
+ private boolean mHasHistoryStepDetails;
+
+ /**
+ * Total time (in milliseconds) spent executing in user code.
+ */
+ private long mLastStepCpuUserTimeMs;
+ private long mCurStepCpuUserTimeMs;
+ /**
+ * Total time (in milliseconds) spent executing in kernel code.
+ */
+ private long mLastStepCpuSystemTimeMs;
+ private long mCurStepCpuSystemTimeMs;
+ /**
+ * Times from /proc/stat (but measured in milliseconds).
+ */
+ private long mLastStepStatUserTimeMs;
+ private long mLastStepStatSystemTimeMs;
+ private long mLastStepStatIOWaitTimeMs;
+ private long mLastStepStatIrqTimeMs;
+ private long mLastStepStatSoftIrqTimeMs;
+ private long mLastStepStatIdleTimeMs;
+ private long mCurStepStatUserTimeMs;
+ private long mCurStepStatSystemTimeMs;
+ private long mCurStepStatIOWaitTimeMs;
+ private long mCurStepStatIrqTimeMs;
+ private long mCurStepStatSoftIrqTimeMs;
+ private long mCurStepStatIdleTimeMs;
+
+ private PowerStatsInternal mPowerStatsInternal;
+ private final Map<Integer, String> mEntityNames = new HashMap<>();
+ private final Map<Integer, Map<Integer, String>> mStateNames = new HashMap<>();
+
+ BatteryHistoryStepDetailsProvider(BatteryStatsImpl batteryStats) {
+ mBatteryStats = batteryStats;
+ }
+
+ void onSystemReady() {
+ mPowerStatsInternal = LocalServices.getService(PowerStatsInternal.class);
+ if (mPowerStatsInternal != null) {
+ populatePowerEntityMaps();
+ }
+ }
+
+ void requestUpdate() {
+ mBatteryStats.mHandler.post(this::update);
+ }
+
+ void update() {
+ mHasHistoryStepDetails = false;
+ mBatteryStats.updateCpuDetails();
+ calculateHistoryStepDetails();
+ updateStateResidency();
+ mBatteryStats.getHistory().recordHistoryStepDetails(mDetails,
+ mBatteryStats.mClock.elapsedRealtime(),
+ mBatteryStats.mClock.uptimeMillis());
+ }
+
+ private void calculateHistoryStepDetails() {
+ if (!mHasHistoryStepDetails) {
+ return;
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG, "Step stats last: user=" + mLastStepCpuUserTimeMs + " sys="
+ + mLastStepStatSystemTimeMs + " io=" + mLastStepStatIOWaitTimeMs
+ + " irq=" + mLastStepStatIrqTimeMs + " sirq="
+ + mLastStepStatSoftIrqTimeMs + " idle=" + mLastStepStatIdleTimeMs);
+ Slog.d(TAG, "Step stats cur: user=" + mCurStepCpuUserTimeMs + " sys="
+ + mCurStepStatSystemTimeMs + " io=" + mCurStepStatIOWaitTimeMs
+ + " irq=" + mCurStepStatIrqTimeMs + " sirq="
+ + mCurStepStatSoftIrqTimeMs + " idle=" + mCurStepStatIdleTimeMs);
+ }
+ mDetails.userTime = (int) (mCurStepCpuUserTimeMs - mLastStepCpuUserTimeMs);
+ mDetails.systemTime = (int) (mCurStepCpuSystemTimeMs - mLastStepCpuSystemTimeMs);
+ mDetails.statUserTime = (int) (mCurStepStatUserTimeMs - mLastStepStatUserTimeMs);
+ mDetails.statSystemTime =
+ (int) (mCurStepStatSystemTimeMs - mLastStepStatSystemTimeMs);
+ mDetails.statIOWaitTime =
+ (int) (mCurStepStatIOWaitTimeMs - mLastStepStatIOWaitTimeMs);
+ mDetails.statIrqTime = (int) (mCurStepStatIrqTimeMs - mLastStepStatIrqTimeMs);
+ mDetails.statSoftIrqTime =
+ (int) (mCurStepStatSoftIrqTimeMs - mLastStepStatSoftIrqTimeMs);
+ mDetails.statIdlTime = (int) (mCurStepStatIdleTimeMs - mLastStepStatIdleTimeMs);
+ mDetails.appCpuUid1 = mDetails.appCpuUid2 = mDetails.appCpuUid3 = -1;
+ mDetails.appCpuUTime1 = mDetails.appCpuUTime2 = mDetails.appCpuUTime3 = 0;
+ mDetails.appCpuSTime1 = mDetails.appCpuSTime2 = mDetails.appCpuSTime3 = 0;
+ SparseArray<? extends BatteryStats.Uid> uidStats = mBatteryStats.getUidStats();
+ final int uidCount = uidStats.size();
+ for (int i = 0; i < uidCount; i++) {
+ final BatteryStatsImpl.Uid uid = (BatteryStatsImpl.Uid) uidStats.valueAt(i);
+ final int totalUTimeMs =
+ (int) (uid.mCurStepUserTimeMs - uid.mLastStepUserTimeMs);
+ final int totalSTimeMs =
+ (int) (uid.mCurStepSystemTimeMs - uid.mLastStepSystemTimeMs);
+ final int totalTimeMs = totalUTimeMs + totalSTimeMs;
+ uid.mLastStepUserTimeMs = uid.mCurStepUserTimeMs;
+ uid.mLastStepSystemTimeMs = uid.mCurStepSystemTimeMs;
+ if (totalTimeMs <= (mDetails.appCpuUTime3 + mDetails.appCpuSTime3)) {
+ continue;
+ }
+ if (totalTimeMs <= (mDetails.appCpuUTime2 + mDetails.appCpuSTime2)) {
+ mDetails.appCpuUid3 = uid.mUid;
+ mDetails.appCpuUTime3 = totalUTimeMs;
+ mDetails.appCpuSTime3 = totalSTimeMs;
+ } else {
+ mDetails.appCpuUid3 = mDetails.appCpuUid2;
+ mDetails.appCpuUTime3 = mDetails.appCpuUTime2;
+ mDetails.appCpuSTime3 = mDetails.appCpuSTime2;
+ if (totalTimeMs <= (mDetails.appCpuUTime1 + mDetails.appCpuSTime1)) {
+ mDetails.appCpuUid2 = uid.mUid;
+ mDetails.appCpuUTime2 = totalUTimeMs;
+ mDetails.appCpuSTime2 = totalSTimeMs;
+ } else {
+ mDetails.appCpuUid2 = mDetails.appCpuUid1;
+ mDetails.appCpuUTime2 = mDetails.appCpuUTime1;
+ mDetails.appCpuSTime2 = mDetails.appCpuSTime1;
+ mDetails.appCpuUid1 = uid.mUid;
+ mDetails.appCpuUTime1 = totalUTimeMs;
+ mDetails.appCpuSTime1 = totalSTimeMs;
+ }
+ }
+ }
+ mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs;
+ mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs;
+ mLastStepStatUserTimeMs = mCurStepStatUserTimeMs;
+ mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs;
+ mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs;
+ mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs;
+ mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs;
+ mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs;
+ }
+
+ public void addCpuStats(int totalUTimeMs, int totalSTimeMs, int statUserTimeMs,
+ int statSystemTimeMs, int statIOWaitTimeMs, int statIrqTimeMs,
+ int statSoftIrqTimeMs, int statIdleTimeMs) {
+ if (DEBUG) {
+ Slog.d(TAG, "Adding cpu: tuser=" + totalUTimeMs + " tsys=" + totalSTimeMs
+ + " user=" + statUserTimeMs + " sys=" + statSystemTimeMs
+ + " io=" + statIOWaitTimeMs + " irq=" + statIrqTimeMs
+ + " sirq=" + statSoftIrqTimeMs + " idle=" + statIdleTimeMs);
+ }
+ mCurStepCpuUserTimeMs += totalUTimeMs;
+ mCurStepCpuSystemTimeMs += totalSTimeMs;
+ mCurStepStatUserTimeMs += statUserTimeMs;
+ mCurStepStatSystemTimeMs += statSystemTimeMs;
+ mCurStepStatIOWaitTimeMs += statIOWaitTimeMs;
+ mCurStepStatIrqTimeMs += statIrqTimeMs;
+ mCurStepStatSoftIrqTimeMs += statSoftIrqTimeMs;
+ mCurStepStatIdleTimeMs += statIdleTimeMs;
+ }
+
+ public void finishAddingCpuLocked() {
+ mHasHistoryStepDetails = true;
+ }
+
+ public void reset() {
+ mHasHistoryStepDetails = false;
+ mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs = 0;
+ mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs = 0;
+ mLastStepStatUserTimeMs = mCurStepStatUserTimeMs = 0;
+ mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs = 0;
+ mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs = 0;
+ mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs = 0;
+ mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs = 0;
+ mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs = 0;
+ }
+
+ private void updateStateResidency() {
+ mDetails.statSubsystemPowerState = null;
+
+ if (mPowerStatsInternal == null || mEntityNames.isEmpty() || mStateNames.isEmpty()) {
+ return;
+ }
+
+ final StateResidencyResult[] results;
+ try {
+ results = mPowerStatsInternal.getStateResidencyAsync(new int[0])
+ .get(POWER_STATS_QUERY_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to getStateResidencyAsync", e);
+ return;
+ }
+
+ if (results == null || results.length == 0) {
+ return;
+ }
+
+ StringBuilder builder = new StringBuilder("SubsystemPowerState");
+ for (int i = 0; i < results.length; i++) {
+ final StateResidencyResult result = results[i];
+ int length = builder.length();
+ builder.append(" subsystem_").append(i);
+ builder.append(" name=").append(mEntityNames.get(result.id));
+
+ for (int j = 0; j < result.stateResidencyData.length; j++) {
+ final StateResidency stateResidency = result.stateResidencyData[j];
+ builder.append(" state_").append(j);
+ builder.append(" name=").append(mStateNames.get(result.id).get(
+ stateResidency.id));
+ builder.append(" time=").append(stateResidency.totalTimeInStateMs);
+ builder.append(" count=").append(stateResidency.totalStateEntryCount);
+ builder.append(" last entry=").append(stateResidency.lastEntryTimestampMs);
+ }
+
+ if (builder.length() > MAX_LOW_POWER_STATS_SIZE) {
+ Slog.e(TAG, "updateStateResidency: buffer not enough");
+ builder.setLength(length);
+ break;
+ }
+ }
+
+ mDetails.statSubsystemPowerState = builder.toString();
+ }
+
+ private void populatePowerEntityMaps() {
+ PowerEntity[] entities = mPowerStatsInternal.getPowerEntityInfo();
+ if (entities == null) {
+ return;
+ }
+
+ for (final PowerEntity entity : entities) {
+ Map<Integer, String> states = new HashMap<>();
+ for (int j = 0; j < entity.states.length; j++) {
+ final State state = entity.states[j];
+ states.put(state.id, state.name);
+ }
+
+ mEntityNames.put(entity.id, entity.name);
+ mStateNames.put(entity.id, states);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 2cf6b7e..0af5080 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -117,7 +117,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BatteryStatsHistory;
-import com.android.internal.os.BatteryStatsHistory.HistoryStepDetailsCalculator;
import com.android.internal.os.BatteryStatsHistoryIterator;
import com.android.internal.os.BinderCallsStats;
import com.android.internal.os.BinderTransactionNameResolver;
@@ -653,7 +652,6 @@
public interface PlatformIdleStateCallback {
public void fillLowPowerStats(RpmStats rpmStats);
- public String getSubsystemLowPowerStats();
}
/** interface to update rail information for power monitor */
@@ -1065,10 +1063,6 @@
*/
void cancelCpuSyncDueToWakelockChange();
- /**
- * Schedules a sync caused by the battery level change
- */
- void scheduleSyncDueToBatteryLevelChange(long delayMillis);
/** Schedule removal of UIDs corresponding to a removed user */
void scheduleCleanupDueToRemovedUser(int userId);
/** Schedule a sync because of a process state change */
@@ -1131,8 +1125,8 @@
private boolean mShuttingDown;
private final HistoryEventTracker mActiveEvents = new HistoryEventTracker();
- private final HistoryStepDetailsCalculatorImpl mStepDetailsCalculator =
- new HistoryStepDetailsCalculatorImpl();
+ private final BatteryHistoryStepDetailsProvider mStepDetailsProvider =
+ new BatteryHistoryStepDetailsProvider(this);
private boolean mHaveBatteryLevel = false;
private boolean mBatteryPluggedIn;
@@ -4553,184 +4547,6 @@
return kmt;
}
- private class HistoryStepDetailsCalculatorImpl implements HistoryStepDetailsCalculator {
- private final HistoryStepDetails mDetails = new HistoryStepDetails();
-
- private boolean mHasHistoryStepDetails;
- private boolean mUpdateRequested;
-
- /**
- * Total time (in milliseconds) spent executing in user code.
- */
- private long mLastStepCpuUserTimeMs;
- private long mCurStepCpuUserTimeMs;
- /**
- * Total time (in milliseconds) spent executing in kernel code.
- */
- private long mLastStepCpuSystemTimeMs;
- private long mCurStepCpuSystemTimeMs;
- /**
- * Times from /proc/stat (but measured in milliseconds).
- */
- private long mLastStepStatUserTimeMs;
- private long mLastStepStatSystemTimeMs;
- private long mLastStepStatIOWaitTimeMs;
- private long mLastStepStatIrqTimeMs;
- private long mLastStepStatSoftIrqTimeMs;
- private long mLastStepStatIdleTimeMs;
- private long mCurStepStatUserTimeMs;
- private long mCurStepStatSystemTimeMs;
- private long mCurStepStatIOWaitTimeMs;
- private long mCurStepStatIrqTimeMs;
- private long mCurStepStatSoftIrqTimeMs;
- private long mCurStepStatIdleTimeMs;
-
- @Override
- public HistoryStepDetails getHistoryStepDetails() {
- if (!mUpdateRequested) {
- mUpdateRequested = true;
- // Perform a CPU update right after we do this collection, so we have started
- // collecting good data for the next step.
- requestImmediateCpuUpdate();
-
- if (mPlatformIdleStateCallback != null) {
- mDetails.statSubsystemPowerState =
- mPlatformIdleStateCallback.getSubsystemLowPowerStats();
- if (DEBUG) {
- Slog.i(TAG,
- "WRITE SubsystemPowerState:" + mDetails.statSubsystemPowerState);
- }
- }
- }
-
- if (!mHasHistoryStepDetails) {
- // We are not generating a delta, so all we need to do is reset the stats
- // we will later be doing a delta from.
- final int uidCount = mUidStats.size();
- for (int i = 0; i < uidCount; i++) {
- final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
- uid.mLastStepUserTimeMs = uid.mCurStepUserTimeMs;
- uid.mLastStepSystemTimeMs = uid.mCurStepSystemTimeMs;
- }
- mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs;
- mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs;
- mLastStepStatUserTimeMs = mCurStepStatUserTimeMs;
- mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs;
- mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs;
- mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs;
- mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs;
- mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs;
- return null;
- } else {
- if (DEBUG) {
- Slog.d(TAG, "Step stats last: user=" + mLastStepCpuUserTimeMs + " sys="
- + mLastStepStatSystemTimeMs + " io=" + mLastStepStatIOWaitTimeMs
- + " irq=" + mLastStepStatIrqTimeMs + " sirq="
- + mLastStepStatSoftIrqTimeMs + " idle=" + mLastStepStatIdleTimeMs);
- Slog.d(TAG, "Step stats cur: user=" + mCurStepCpuUserTimeMs + " sys="
- + mCurStepStatSystemTimeMs + " io=" + mCurStepStatIOWaitTimeMs
- + " irq=" + mCurStepStatIrqTimeMs + " sirq="
- + mCurStepStatSoftIrqTimeMs + " idle=" + mCurStepStatIdleTimeMs);
- }
- mDetails.userTime = (int) (mCurStepCpuUserTimeMs - mLastStepCpuUserTimeMs);
- mDetails.systemTime = (int) (mCurStepCpuSystemTimeMs - mLastStepCpuSystemTimeMs);
- mDetails.statUserTime = (int) (mCurStepStatUserTimeMs - mLastStepStatUserTimeMs);
- mDetails.statSystemTime =
- (int) (mCurStepStatSystemTimeMs - mLastStepStatSystemTimeMs);
- mDetails.statIOWaitTime =
- (int) (mCurStepStatIOWaitTimeMs - mLastStepStatIOWaitTimeMs);
- mDetails.statIrqTime = (int) (mCurStepStatIrqTimeMs - mLastStepStatIrqTimeMs);
- mDetails.statSoftIrqTime =
- (int) (mCurStepStatSoftIrqTimeMs - mLastStepStatSoftIrqTimeMs);
- mDetails.statIdlTime = (int) (mCurStepStatIdleTimeMs - mLastStepStatIdleTimeMs);
- mDetails.appCpuUid1 = mDetails.appCpuUid2 = mDetails.appCpuUid3 = -1;
- mDetails.appCpuUTime1 = mDetails.appCpuUTime2 = mDetails.appCpuUTime3 = 0;
- mDetails.appCpuSTime1 = mDetails.appCpuSTime2 = mDetails.appCpuSTime3 = 0;
- final int uidCount = mUidStats.size();
- for (int i = 0; i < uidCount; i++) {
- final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
- final int totalUTimeMs =
- (int) (uid.mCurStepUserTimeMs - uid.mLastStepUserTimeMs);
- final int totalSTimeMs =
- (int) (uid.mCurStepSystemTimeMs - uid.mLastStepSystemTimeMs);
- final int totalTimeMs = totalUTimeMs + totalSTimeMs;
- uid.mLastStepUserTimeMs = uid.mCurStepUserTimeMs;
- uid.mLastStepSystemTimeMs = uid.mCurStepSystemTimeMs;
- if (totalTimeMs <= (mDetails.appCpuUTime3 + mDetails.appCpuSTime3)) {
- continue;
- }
- if (totalTimeMs <= (mDetails.appCpuUTime2 + mDetails.appCpuSTime2)) {
- mDetails.appCpuUid3 = uid.mUid;
- mDetails.appCpuUTime3 = totalUTimeMs;
- mDetails.appCpuSTime3 = totalSTimeMs;
- } else {
- mDetails.appCpuUid3 = mDetails.appCpuUid2;
- mDetails.appCpuUTime3 = mDetails.appCpuUTime2;
- mDetails.appCpuSTime3 = mDetails.appCpuSTime2;
- if (totalTimeMs <= (mDetails.appCpuUTime1 + mDetails.appCpuSTime1)) {
- mDetails.appCpuUid2 = uid.mUid;
- mDetails.appCpuUTime2 = totalUTimeMs;
- mDetails.appCpuSTime2 = totalSTimeMs;
- } else {
- mDetails.appCpuUid2 = mDetails.appCpuUid1;
- mDetails.appCpuUTime2 = mDetails.appCpuUTime1;
- mDetails.appCpuSTime2 = mDetails.appCpuSTime1;
- mDetails.appCpuUid1 = uid.mUid;
- mDetails.appCpuUTime1 = totalUTimeMs;
- mDetails.appCpuSTime1 = totalSTimeMs;
- }
- }
- }
- mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs;
- mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs;
- mLastStepStatUserTimeMs = mCurStepStatUserTimeMs;
- mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs;
- mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs;
- mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs;
- mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs;
- mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs;
- return mDetails;
- }
- }
-
- public void addCpuStats(int totalUTimeMs, int totalSTimeMs, int statUserTimeMs,
- int statSystemTimeMs, int statIOWaitTimeMs, int statIrqTimeMs,
- int statSoftIrqTimeMs, int statIdleTimeMs) {
- if (DEBUG) {
- Slog.d(TAG, "Adding cpu: tuser=" + totalUTimeMs + " tsys=" + totalSTimeMs
- + " user=" + statUserTimeMs + " sys=" + statSystemTimeMs
- + " io=" + statIOWaitTimeMs + " irq=" + statIrqTimeMs
- + " sirq=" + statSoftIrqTimeMs + " idle=" + statIdleTimeMs);
- }
- mCurStepCpuUserTimeMs += totalUTimeMs;
- mCurStepCpuSystemTimeMs += totalSTimeMs;
- mCurStepStatUserTimeMs += statUserTimeMs;
- mCurStepStatSystemTimeMs += statSystemTimeMs;
- mCurStepStatIOWaitTimeMs += statIOWaitTimeMs;
- mCurStepStatIrqTimeMs += statIrqTimeMs;
- mCurStepStatSoftIrqTimeMs += statSoftIrqTimeMs;
- mCurStepStatIdleTimeMs += statIdleTimeMs;
- }
-
- public void finishAddingCpuLocked() {
- mHasHistoryStepDetails = true;
- mUpdateRequested = false;
- }
-
- @Override
- public void clear() {
- mHasHistoryStepDetails = false;
- mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs = 0;
- mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs = 0;
- mLastStepStatUserTimeMs = mCurStepStatUserTimeMs = 0;
- mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs = 0;
- mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs = 0;
- mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs = 0;
- mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs = 0;
- mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs = 0;
- }
- }
-
@GuardedBy("this")
@Override
public void commitCurrentHistoryBatchLocked() {
@@ -5557,7 +5373,7 @@
public void addCpuStatsLocked(int totalUTimeMs, int totalSTimeMs, int statUserTimeMs,
int statSystemTimeMs, int statIOWaitTimeMs, int statIrqTimeMs,
int statSoftIrqTimeMs, int statIdleTimeMs) {
- mStepDetailsCalculator.addCpuStats(totalUTimeMs, totalSTimeMs, statUserTimeMs,
+ mStepDetailsProvider.addCpuStats(totalUTimeMs, totalSTimeMs, statUserTimeMs,
statSystemTimeMs, statIOWaitTimeMs, statIrqTimeMs,
statSoftIrqTimeMs, statIdleTimeMs);
}
@@ -5567,7 +5383,7 @@
*/
@GuardedBy("this")
public void finishAddingCpuStatsLocked() {
- mStepDetailsCalculator.finishAddingCpuLocked();
+ mStepDetailsProvider.finishAddingCpuLocked();
}
public void noteProcessDiedLocked(int uid, int pid) {
@@ -11515,8 +11331,7 @@
mBatteryHistoryDirectory = batteryHistoryDirectory;
mHistory = new BatteryStatsHistory(null /* historyBuffer */, mConstants.MAX_HISTORY_BUFFER,
- mBatteryHistoryDirectory, mStepDetailsCalculator, mClock, mMonotonicClock,
- traceDelegate, eventLogger);
+ mBatteryHistoryDirectory, mClock, mMonotonicClock, traceDelegate, eventLogger);
mCpuPowerStatsCollector = new CpuPowerStatsCollector(mPowerStatsCollectorInjector);
mCpuPowerStatsCollector.addConsumer(this::recordPowerStats);
@@ -11723,6 +11538,12 @@
mCallback = cb;
}
+ void updateCpuDetails() {
+ if (mCallback != null) {
+ mCallback.batteryNeedsCpuUpdate();
+ }
+ }
+
public void setRadioScanningTimeoutLocked(long timeoutUs) {
if (mPhoneSignalScanningTimer != null) {
mPhoneSignalScanningTimer.setTimeout(timeoutUs);
@@ -12343,6 +12164,8 @@
mWakeupReasonStats.clear();
}
+ mStepDetailsProvider.reset();
+
if (mTmpRailStats != null) {
mTmpRailStats.reset();
}
@@ -14948,6 +14771,8 @@
mCpuUidFreqTimeReader.onSystemReady();
}
+ mStepDetailsProvider.onSystemReady();
+
mPowerStatsCollectorInjector.setContext(context);
mCpuPowerStatsCollector.setEnabled(
@@ -15270,6 +15095,7 @@
reportChangesToStatsLog(status, plugType, level);
+ boolean requestStepDetails = false;
final boolean onBattery = isOnBattery(plugType, status);
if (!mHaveBatteryLevel) {
mHaveBatteryLevel = true;
@@ -15289,6 +15115,7 @@
mMaxChargeStepLevel = mMinDischargeStepLevel =
mLastChargeStepLevel = mLastDischargeStepLevel = level;
+ requestStepDetails = true;
} else if (mBatteryLevel != level || mOnBattery != onBattery) {
recordDailyStatsIfNeededLocked(level >= 100 && onBattery, currentTimeMs);
}
@@ -15332,16 +15159,13 @@
}
mBatteryChargeUah = chargeUah;
setOnBatteryLocked(elapsedRealtimeMs, uptimeMs, onBattery, oldStatus, level, chargeUah);
+ requestStepDetails = true;
} else {
boolean changed = false;
if (mBatteryLevel != level) {
mBatteryLevel = level;
changed = true;
-
- // TODO(adamlesinski): Schedule the creation of a HistoryStepDetails record
- // which will pull external stats.
- mExternalSync.scheduleSyncDueToBatteryLevelChange(
- mConstants.BATTERY_LEVEL_COLLECTION_DELAY_MS);
+ requestStepDetails = true;
}
if (mBatteryStatus != status) {
mBatteryStatus = status;
@@ -15462,6 +15286,9 @@
if (mAccumulateBatteryUsageStats) {
mBatteryUsageStatsProvider.accumulateBatteryUsageStatsAsync(this, mHandler);
}
+ if (requestStepDetails) {
+ mStepDetailsProvider.requestUpdate();
+ }
}
public static boolean isOnBattery(int plugType, int status) {
diff --git a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
index 8c3b7c6..3ece07c 100644
--- a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
+++ b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
@@ -17,6 +17,7 @@
package com.android.server.security.advancedprotection;
import static android.provider.Settings.Secure.ADVANCED_PROTECTION_MODE;
+import static android.provider.Settings.Secure.AAPM_USB_DATA_PROTECTION;
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import android.Manifest;
@@ -69,6 +70,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
/** @hide */
public class AdvancedProtectionService extends IAdvancedProtectionService.Stub {
@@ -129,7 +131,10 @@
Slog.e(TAG, "Failed to initialize DisallowCellular2g", e);
}
}
- if (android.security.Flags.aapmFeatureUsbDataProtection()) {
+ if (android.security.Flags.aapmFeatureUsbDataProtection()
+ // Usb data protection is enabled by default
+ && mStore.retrieveInt(AAPM_USB_DATA_PROTECTION, AdvancedProtectionStore.ON)
+ == AdvancedProtectionStore.ON) {
try {
mHooks.add(new UsbDataAdvancedProtectionHook(mContext, enabled));
} catch (Exception e) {
@@ -183,7 +188,7 @@
// Without permission check
private boolean isAdvancedProtectionEnabledInternal() {
- return mStore.retrieve();
+ return mStore.retrieveAdvancedProtectionModeEnabled();
}
@Override
@@ -217,7 +222,7 @@
try {
synchronized (mCallbacks) {
if (enabled != isAdvancedProtectionEnabledInternal()) {
- mStore.store(enabled);
+ mStore.storeAdvancedProtectionModeEnabled(enabled);
sendModeChanged(enabled);
logAdvancedProtectionEnabled(enabled);
}
@@ -227,6 +232,34 @@
}
}
+ public void setUsbDataProtectionEnabled(boolean enabled) {
+ int value = enabled ? AdvancedProtectionStore.ON
+ : AdvancedProtectionStore.OFF;
+ setAdvancedProtectionSubSettingInt(AAPM_USB_DATA_PROTECTION, value);
+ }
+
+ private void setAdvancedProtectionSubSettingInt(String key, int value) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mCallbacks) {
+ mStore.storeInt(key, value);
+ Slog.i(TAG, "Advanced protection: subsetting" + key + " is " + value);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ public boolean isUsbDataProtectionEnabled() {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mStore.retrieveInt(AAPM_USB_DATA_PROTECTION, AdvancedProtectionStore.ON)
+ == AdvancedProtectionStore.ON;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
@Override
@EnforcePermission(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE)
public void logDialogShown(@FeatureId int featureId, @SupportDialogType int type,
@@ -419,8 +452,8 @@
@VisibleForTesting
static class AdvancedProtectionStore {
private final Context mContext;
- private static final int APM_ON = 1;
- private static final int APM_OFF = 0;
+ static final int ON = 1;
+ static final int OFF = 0;
private final UserManagerInternal mUserManager;
AdvancedProtectionStore(@NonNull Context context) {
@@ -428,15 +461,26 @@
mUserManager = LocalServices.getService(UserManagerInternal.class);
}
- void store(boolean enabled) {
+ void storeAdvancedProtectionModeEnabled(boolean enabled) {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
- ADVANCED_PROTECTION_MODE, enabled ? APM_ON : APM_OFF,
+ ADVANCED_PROTECTION_MODE, enabled ? ON : OFF,
mUserManager.getMainUserId());
}
- boolean retrieve() {
+ boolean retrieveAdvancedProtectionModeEnabled() {
return Settings.Secure.getIntForUser(mContext.getContentResolver(),
- ADVANCED_PROTECTION_MODE, APM_OFF, mUserManager.getMainUserId()) == APM_ON;
+ ADVANCED_PROTECTION_MODE, OFF, mUserManager.getMainUserId()) == ON;
+ }
+
+ void storeInt(String key, int value) {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ key, value,
+ mUserManager.getMainUserId());
+ }
+
+ int retrieveInt(String key, int defaultValue) {
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ key, defaultValue, mUserManager.getMainUserId());
}
}
diff --git a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionShellCommand.java b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionShellCommand.java
index 42505ad..ae17a45 100644
--- a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionShellCommand.java
+++ b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionShellCommand.java
@@ -45,6 +45,10 @@
return setProtectionEnabled();
case "is-protection-enabled":
return isProtectionEnabled(pw);
+ case "set-usb-data-protection-enabled":
+ return setUsbDataProtectedEnabled();
+ case "is-usb-data-protection-enabled":
+ return isUsbDataProtectedEnabled(pw);
}
} catch (RemoteException e) {
pw.println("Remote exception: " + e);
@@ -64,6 +68,10 @@
pw.println(" Print this help text.");
pw.println(" set-protection-enabled [true|false]");
pw.println(" is-protection-enabled");
+ if(android.security.Flags.aapmFeatureUsbDataProtection()) {
+ pw.println(" set-usb-data-protection-enabled [true|false]");
+ pw.println(" is-usb-data-protection-enabled");
+ }
}
@SuppressLint("AndroidFrameworkRequiresPermission")
@@ -79,4 +87,22 @@
pw.println(protectionMode);
return 0;
}
+
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ private int setUsbDataProtectedEnabled() throws RemoteException {
+ if(android.security.Flags.aapmFeatureUsbDataProtection()) {
+ String protectionMode = getNextArgRequired();
+ mService.setUsbDataProtectionEnabled(Boolean.parseBoolean(protectionMode));
+ }
+ return 0;
+ }
+
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ private int isUsbDataProtectedEnabled(@NonNull PrintWriter pw) throws RemoteException {
+ if(android.security.Flags.aapmFeatureUsbDataProtection()) {
+ boolean protectionMode = mService.isUsbDataProtectionEnabled();
+ pw.println(protectionMode);
+ }
+ return 0;
+ }
}
diff --git a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
index 70fc6ba..ee173a2 100644
--- a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
+++ b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
@@ -131,6 +131,10 @@
mCache = cache;
}
+ void setSnapshotReleaser(Consumer<HardwareBuffer> releaser) {
+ mCache.setSafeSnapshotReleaser(releaser);
+ }
+
void setSnapshotEnabled(boolean enabled) {
mSnapshotEnabled = enabled;
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b9ab863..1d724733 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -98,7 +98,6 @@
import static android.os.Build.VERSION_CODES.O;
import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.Process.SYSTEM_UID;
-import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15;
import static android.view.WindowManager.ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15;
@@ -109,7 +108,6 @@
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED;
import static android.view.WindowManager.PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING;
-import static android.view.WindowManager.TRANSIT_OLD_UNSET;
import static android.view.WindowManager.TRANSIT_RELAUNCH;
import static android.view.WindowManager.hasWindowExtensionsEnabled;
import static android.window.TransitionInfo.FLAGS_IS_OCCLUDED_NO_ANIMATION;
@@ -117,9 +115,7 @@
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ADD_REMOVE;
-import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ANIM;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_APP_TRANSITIONS;
-import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_APP_TRANSITIONS_ANIM;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_CONFIGURATION;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_CONTAINERS;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_FOCUS;
@@ -135,8 +131,6 @@
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.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;
import static com.android.server.wm.ActivityRecord.State.DESTROYING;
import static com.android.server.wm.ActivityRecord.State.FINISHING;
@@ -364,7 +358,6 @@
import com.android.server.uri.NeededUriGrants;
import com.android.server.uri.UriPermissionOwner;
import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot;
-import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.WindowManagerService.H;
import com.android.window.flags.Flags;
@@ -1434,7 +1427,7 @@
// precede the configuration change from the resize.)
mLastReportedPictureInPictureMode = inPictureInPictureMode;
mLastReportedMultiWindowMode = inPictureInPictureMode;
- if (!isPip2ExperimentEnabled()) {
+ if (forceUpdate || !isPip2ExperimentEnabled()) {
// PiP2 should handle sending out the configuration as a part of Shell Transitions.
ensureActivityConfiguration(true /* ignoreVisibility */);
}
@@ -6367,6 +6360,15 @@
isSuccessful = false;
}
if (isSuccessful) {
+ final int lastReportedWinMode = mLastReportedConfiguration.getMergedConfiguration()
+ .windowConfiguration.getWindowingMode();
+ if (isPip2ExperimentEnabled()
+ && lastReportedWinMode == WINDOWING_MODE_PINNED && !inPinnedWindowingMode()) {
+ // If an activity that was previously reported as pinned has a different windowing
+ // mode, then send the latest activity configuration even if this activity is
+ // stopping. This ensures that app gets onPictureInPictureModeChanged after onStop.
+ updatePictureInPictureMode(null /* targetRootTaskBounds */, true /* forceUpdate */);
+ }
mAtmService.mH.postDelayed(mStopTimeoutRunnable, STOP_TIMEOUT);
} else {
// Just in case, assume it to be stopped.
@@ -7199,40 +7201,6 @@
return candidate;
}
- @Override
- public SurfaceControl getAnimationLeashParent() {
- // For transitions in the root pinned task (menu activity) we just let them occur as a child
- // of the root pinned task.
- // All normal app transitions take place in an animation layer which is below the root
- // pinned task but may be above the parent tasks of the given animating apps by default.
- // When a new hierarchical animation is enabled, we just let them occur as a child of the
- // parent task, i.e. the hierarchy of the surfaces is unchanged.
- if (inPinnedWindowingMode()) {
- return getRootTask().getSurfaceControl();
- } else {
- return super.getAnimationLeashParent();
- }
- }
-
- @VisibleForTesting
- boolean shouldAnimate() {
- return task == null || task.shouldAnimate();
- }
-
- /**
- * Creates a layer to apply crop to an animation.
- */
- private SurfaceControl createAnimationBoundsLayer(Transaction t) {
- ProtoLog.i(WM_DEBUG_APP_TRANSITIONS_ANIM, "Creating animation bounds layer");
- final SurfaceControl.Builder builder = makeAnimationLeash()
- .setParent(getAnimationLeashParent())
- .setName(getSurfaceControl() + " - animation-bounds")
- .setCallsite("ActivityRecord.createAnimationBoundsLayer");
- final SurfaceControl boundsLayer = builder.build();
- t.show(boundsLayer);
- return boundsLayer;
- }
-
boolean isTransitionForward() {
return (mStartingData != null && mStartingData.mIsTransitionForward)
|| mDisplayContent.isNextTransitionForward();
@@ -7244,25 +7212,6 @@
}
@Override
- public void onLeashAnimationStarting(Transaction t, SurfaceControl leash) {
- // If the animation needs to be cropped then an animation bounds layer is created as a
- // child of the root pinned task or animation layer. The leash is then reparented to this
- // new layer.
- if (mNeedsAnimationBoundsLayer) {
- mTmpRect.setEmpty();
- task.getBounds(mTmpRect);
- mAnimationBoundsLayer = createAnimationBoundsLayer(t);
-
- // Crop to root task bounds.
- t.setLayer(leash, 0);
- t.setLayer(mAnimationBoundsLayer, getLastLayer());
-
- // Reparent leash to animation bounds layer.
- t.reparent(leash, mAnimationBoundsLayer);
- }
- }
-
- @Override
boolean showSurfaceOnCreation() {
return false;
}
@@ -7301,74 +7250,6 @@
return mLastSurfaceShowing;
}
- @Override
- public void onAnimationLeashLost(Transaction t) {
- super.onAnimationLeashLost(t);
- if (mAnimationBoundsLayer != null) {
- t.remove(mAnimationBoundsLayer);
- mAnimationBoundsLayer = null;
- }
-
- mNeedsAnimationBoundsLayer = false;
- }
-
- @Override
- protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
- super.onAnimationFinished(type, anim);
-
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AR#onAnimationFinished");
- mTransit = TRANSIT_OLD_UNSET;
- mTransitFlags = 0;
-
- setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER,
- "ActivityRecord");
-
- setClientVisible(isVisible() || mVisibleRequested);
-
- getDisplayContent().computeImeTargetIfNeeded(this);
-
- ProtoLog.v(WM_DEBUG_ANIM, "Animation done in %s"
- + ": reportedVisible=%b okToDisplay=%b okToAnimate=%b startingDisplayed=%b",
- this, reportedVisible, okToDisplay(), okToAnimate(),
- isStartingWindowDisplayed());
-
- // WindowState.onExitAnimationDone might modify the children list, so make a copy and then
- // traverse the copy.
- final ArrayList<WindowState> children = new ArrayList<>(mChildren);
- children.forEach(WindowState::onExitAnimationDone);
- // The starting window could transfer to another activity after app transition started, in
- // that case the latest top activity might not receive exit animation done callback if the
- // starting window didn't applied exit animation success. Notify animation finish to the
- // starting window if needed.
- if (task != null && startingMoved) {
- final WindowState transferredStarting = task.getWindow(w ->
- w.mAttrs.type == TYPE_APPLICATION_STARTING);
- if (transferredStarting != null && transferredStarting.mAnimatingExit
- && !transferredStarting.isSelfAnimating(0 /* flags */,
- ANIMATION_TYPE_WINDOW_ANIMATION)) {
- transferredStarting.onExitAnimationDone();
- }
- }
-
- scheduleAnimation();
-
- // Schedule to handle the stopping and finishing activities which the animation is done
- // because the activities which were animating have not been stopped yet.
- mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- }
-
- void clearAnimatingFlags() {
- boolean wallpaperMightChange = false;
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState win = mChildren.get(i);
- wallpaperMightChange |= win.clearAnimatingFlags();
- }
- if (wallpaperMightChange) {
- requestUpdateWallpaperIfNeeded();
- }
- }
-
public @TransitionOldType int getTransit() {
return mTransit;
}
diff --git a/services/core/java/com/android/server/wm/ActivitySnapshotCache.java b/services/core/java/com/android/server/wm/ActivitySnapshotCache.java
index ed07afd..a0e5372 100644
--- a/services/core/java/com/android/server/wm/ActivitySnapshotCache.java
+++ b/services/core/java/com/android/server/wm/ActivitySnapshotCache.java
@@ -31,6 +31,7 @@
void putSnapshot(ActivityRecord ar, TaskSnapshot snapshot) {
final int hasCode = System.identityHashCode(ar);
snapshot.addReference(TaskSnapshot.REFERENCE_CACHE);
+ snapshot.setSafeRelease(mSafeSnapshotReleaser);
synchronized (mLock) {
final CacheEntry entry = mRunningCache.get(hasCode);
if (entry != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 21b730e..7123a7c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -803,4 +803,10 @@
/** Returns whether assist data is allowed. */
public abstract boolean isAssistDataAllowed();
+
+ /**
+ * Delegate back gesture request from shell.
+ * Returns true if the back gesture request was successful, false otherwise.
+ */
+ public abstract boolean requestBackGesture();
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 46d24b0..a0c38dd 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1892,6 +1892,18 @@
}
}
+ @Override
+ public void registerBackGestureDelegate(RemoteCallback requestObserver) {
+ mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
+ "registerBackGestureDelegate()");
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ mBackNavigationController.registerBackGestureDelegate(requestObserver);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
/**
* Public API to check if the client is allowed to start an activity on specified display.
*
@@ -7571,6 +7583,11 @@
public boolean isAssistDataAllowed() {
return ActivityTaskManagerService.this.isAssistDataAllowed();
}
+
+ @Override
+ public boolean requestBackGesture() {
+ return mBackNavigationController.requestBackGesture();
+ }
}
/** Cache the return value for {@link #isPip2ExperimentEnabled()} */
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 0e14f83..05b109c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -78,6 +78,7 @@
import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_SUPERVISOR_TASK_MSG;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+import static com.android.server.wm.ActivityTaskManagerService.isPip2ExperimentEnabled;
import static com.android.server.wm.ClientLifecycleManager.shouldDispatchLaunchActivityItemIndependently;
import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_ALLOWLISTED;
import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE;
@@ -1687,9 +1688,13 @@
*/
rootTask.cancelAnimation();
rootTask.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */);
- rootTask.ensureActivitiesVisible(null /* starting */);
- activityIdleInternal(null /* idleActivity */, false /* fromTimeout */,
- true /* processPausingActivities */, null /* configuration */);
+ if (!isPip2ExperimentEnabled()) {
+ // In PiP2, as the transition finishes the lifecycle updates will be sent to the app
+ // along with the configuration changes as a part of the transition lifecycle.
+ rootTask.ensureActivitiesVisible(null /* starting */);
+ activityIdleInternal(null /* idleActivity */, false /* fromTimeout */,
+ true /* processPausingActivities */, null /* configuration */);
+ }
if (rootTask.getParent() == null) {
// The activities in the task may already be finishing. Then the task could be removed
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index dfe323c..819e4ab 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -85,6 +85,7 @@
private boolean mShowWallpaper;
private Runnable mPendingAnimation;
private final NavigationMonitor mNavigationMonitor = new NavigationMonitor();
+ private RemoteCallback mGestureRequest;
private AnimationHandler mAnimationHandler;
@@ -113,6 +114,35 @@
mNavigationMonitor.onEmbeddedWindowGestureTransferred(host);
}
+ void registerBackGestureDelegate(@NonNull RemoteCallback requestObserver) {
+ if (!sPredictBackEnable) {
+ return;
+ }
+ synchronized (mWindowManagerService.mGlobalLock) {
+ mGestureRequest = requestObserver;
+ try {
+ requestObserver.getInterface().asBinder().linkToDeath(() -> {
+ synchronized (mWindowManagerService.mGlobalLock) {
+ mGestureRequest = null;
+ }
+ }, 0 /* flags */);
+ } catch (RemoteException r) {
+ Slog.e(TAG, "Failed to link to death");
+ mGestureRequest = null;
+ }
+ }
+ }
+
+ boolean requestBackGesture() {
+ synchronized (mWindowManagerService.mGlobalLock) {
+ if (mGestureRequest == null) {
+ return false;
+ }
+ mGestureRequest.sendResult(null);
+ return true;
+ }
+ }
+
/**
* Set up the necessary leashes and build a {@link BackNavigationInfo} instance for an upcoming
* back gesture animation.
diff --git a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
index 03ba1a5..61e8e09 100644
--- a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
@@ -21,7 +21,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
@@ -242,20 +241,18 @@
@NonNull Task launchingTask) {
if (existingTaskActivity == null || launchingActivity == null) return false;
return (existingTaskActivity.packageName == launchingActivity.packageName)
- && isLaunchingNewTask(launchingActivity.launchMode,
- launchingTask.getBaseIntent().getFlags())
+ && isLaunchingNewSingleTask(launchingActivity.launchMode)
&& isClosingExitingInstance(launchingTask.getBaseIntent().getFlags());
}
/**
- * Returns true if the launch mode or intent will result in a new task being created for the
+ * Returns true if the launch mode will result in a single new task being created for the
* activity.
*/
- private boolean isLaunchingNewTask(int launchMode, int intentFlags) {
+ private boolean isLaunchingNewSingleTask(int launchMode) {
return launchMode == LAUNCH_SINGLE_TASK
|| launchMode == LAUNCH_SINGLE_INSTANCE
- || launchMode == LAUNCH_SINGLE_INSTANCE_PER_TASK
- || (intentFlags & FLAG_ACTIVITY_NEW_TASK) != 0;
+ || launchMode == LAUNCH_SINGLE_INSTANCE_PER_TASK;
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2f9242f..16caec8 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4982,22 +4982,6 @@
return win != null;
}
- /**
- * Callbacks when the given type of {@link WindowContainer} animation finished running in the
- * hierarchy.
- */
- void onWindowAnimationFinished(@NonNull WindowContainer wc, int type) {
- if (mImeScreenshot != null) {
- ProtoLog.i(WM_DEBUG_IME,
- "onWindowAnimationFinished, wc=%s, type=%s, imeSnapshot=%s, target=%s",
- wc, SurfaceAnimator.animationTypeToString(type), mImeScreenshot,
- mImeScreenshot.getImeTarget());
- }
- if ((type & WindowState.EXIT_ANIMATING_TYPES) != 0) {
- removeImeSurfaceByTarget(wc);
- }
- }
-
// TODO: Super unexpected long method that should be broken down...
void applySurfaceChangesTransaction() {
final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 313b77e..dbae9c4 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -137,6 +137,7 @@
import com.android.internal.widget.PointerLocationView;
import com.android.server.LocalServices;
import com.android.server.UiThread;
+import com.android.server.notification.NotificationManagerInternal;
import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
import com.android.server.statusbar.StatusBarManagerInternal;
@@ -1881,6 +1882,9 @@
final boolean isSystemDecorationsSupported =
mDisplayContent.isSystemDecorationsSupported();
final boolean isHomeSupported = mDisplayContent.isHomeSupported();
+ final boolean eligibleForDesktopMode =
+ isSystemDecorationsSupported && (mDisplayContent.isDefaultDisplay
+ || mDisplayContent.allowContentModeSwitch());
mHandler.post(() -> {
if (isSystemDecorationsSupported) {
StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
@@ -1895,6 +1899,10 @@
wpMgr.onDisplayAddSystemDecorations(displayId);
}
}
+ if (eligibleForDesktopMode) {
+ mService.mDisplayNotificationController.dispatchDesktopModeEligibleChanged(
+ displayId);
+ }
});
} else {
mHandler.post(() -> {
@@ -1925,6 +1933,13 @@
if (wpMgr != null) {
wpMgr.onDisplayRemoveSystemDecorations(displayId);
}
+ mService.mDisplayNotificationController.dispatchDesktopModeEligibleChanged(
+ displayId);
+ final NotificationManagerInternal notificationManager =
+ LocalServices.getService(NotificationManagerInternal.class);
+ if (notificationManager != null) {
+ notificationManager.onDisplayRemoveSystemDecorations(displayId);
+ }
});
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
index d90fff2..d705274 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
@@ -133,4 +133,15 @@
}
mDisplayListeners.finishBroadcast();
}
+
+ void dispatchDesktopModeEligibleChanged(int displayId) {
+ int count = mDisplayListeners.beginBroadcast();
+ for (int i = 0; i < count; ++i) {
+ try {
+ mDisplayListeners.getBroadcastItem(i).onDesktopModeEligibleChanged(displayId);
+ } catch (RemoteException e) {
+ }
+ }
+ mDisplayListeners.finishBroadcast();
+ }
}
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 64ae21d..1bf65d1 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -209,7 +209,8 @@
"Transfer request must originate from owner of transferFromToken");
}
final boolean didTransfer = mInputManagerService.transferTouchGesture(
- ew.getInputChannelToken(), transferToHostWindowState.mInputChannelToken);
+ ew.getInputChannelToken(), transferToHostWindowState.mInputChannelToken,
+ /* transferEntireGesture */ true);
if (didTransfer) {
ew.mGestureToEmbedded = false;
}
@@ -228,7 +229,7 @@
}
final boolean didTransfer = mInputManagerService.transferTouchGesture(
hostWindowState.mInputChannelToken,
- ew.getInputChannelToken());
+ ew.getInputChannelToken(), /* transferEntireGesture */ true);
if (didTransfer) {
ew.mGestureToEmbedded = true;
mAtmService.mBackNavigationController.onEmbeddedWindowGestureTransferred(
diff --git a/services/core/java/com/android/server/wm/SnapshotCache.java b/services/core/java/com/android/server/wm/SnapshotCache.java
index 9812a88..685bd3b 100644
--- a/services/core/java/com/android/server/wm/SnapshotCache.java
+++ b/services/core/java/com/android/server/wm/SnapshotCache.java
@@ -16,12 +16,14 @@
package com.android.server.wm;
import android.annotation.Nullable;
+import android.hardware.HardwareBuffer;
import android.util.ArrayMap;
import android.window.TaskSnapshot;
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
+import java.util.function.Consumer;
/**
* Base class for an app snapshot cache
@@ -38,12 +40,18 @@
@GuardedBy("mLock")
protected final ArrayMap<Integer, CacheEntry> mRunningCache = new ArrayMap<>();
+ protected Consumer<HardwareBuffer> mSafeSnapshotReleaser;
+
SnapshotCache(String name) {
mName = name;
}
abstract void putSnapshot(TYPE window, TaskSnapshot snapshot);
+ void setSafeSnapshotReleaser(Consumer<HardwareBuffer> safeSnapshotReleaser) {
+ mSafeSnapshotReleaser = safeSnapshotReleaser;
+ }
+
void clearRunningCache() {
synchronized (mLock) {
mRunningCache.clear();
diff --git a/services/core/java/com/android/server/wm/SnapshotController.java b/services/core/java/com/android/server/wm/SnapshotController.java
index 3a7222a..48f0959 100644
--- a/services/core/java/com/android/server/wm/SnapshotController.java
+++ b/services/core/java/com/android/server/wm/SnapshotController.java
@@ -26,13 +26,16 @@
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import android.hardware.HardwareBuffer;
import android.os.Trace;
import android.util.ArrayMap;
import android.view.WindowManager;
import android.window.TaskSnapshot;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.function.Consumer;
/**
* Integrates common functionality from TaskSnapshotController and ActivitySnapshotController.
@@ -41,11 +44,30 @@
private final SnapshotPersistQueue mSnapshotPersistQueue;
final TaskSnapshotController mTaskSnapshotController;
final ActivitySnapshotController mActivitySnapshotController;
+ private final WindowManagerService mService;
+ private final ArrayList<WeakReference<HardwareBuffer>> mObsoleteSnapshots = new ArrayList<>();
SnapshotController(WindowManagerService wms) {
+ mService = wms;
mSnapshotPersistQueue = new SnapshotPersistQueue();
mTaskSnapshotController = new TaskSnapshotController(wms, mSnapshotPersistQueue);
mActivitySnapshotController = new ActivitySnapshotController(wms, mSnapshotPersistQueue);
+ final Consumer<HardwareBuffer> releaser = hb -> {
+ mService.mH.post(() -> {
+ synchronized (mService.mGlobalLock) {
+ if (hb.isClosed()) {
+ return;
+ }
+ if (mService.mAtmService.getTransitionController().inTransition()) {
+ mObsoleteSnapshots.add(new WeakReference<>(hb));
+ } else {
+ hb.close();
+ }
+ }
+ });
+ };
+ mTaskSnapshotController.setSnapshotReleaser(releaser);
+ mActivitySnapshotController.setSnapshotReleaser(releaser);
}
void systemReady() {
@@ -168,6 +190,7 @@
final boolean isTransitionClose = isTransitionClose(type);
if (!isTransitionOpen && !isTransitionClose && type < TRANSIT_FIRST_CUSTOM
|| (changeInfos.isEmpty())) {
+ closeObsoleteSnapshots();
return;
}
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "SnapshotController_analysis");
@@ -195,9 +218,22 @@
}
}
}
+ closeObsoleteSnapshots();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
+ private void closeObsoleteSnapshots() {
+ if (mObsoleteSnapshots.isEmpty()) {
+ return;
+ }
+ for (int i = mObsoleteSnapshots.size() - 1; i >= 0; --i) {
+ final HardwareBuffer hb = mObsoleteSnapshots.remove(i).get();
+ if (hb != null && !hb.isClosed()) {
+ hb.close();
+ }
+ }
+ }
+
private static boolean isTransitionOpen(int type) {
return type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT
|| type == TRANSIT_PREPARE_BACK_NAVIGATION;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index ec17d13..3cce172 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -5764,15 +5764,16 @@
return false;
}
- // If we have a watcher, preflight the move before committing to it. First check
- // for *other* available tasks, but if none are available, then try again allowing the
- // current task to be selected.
+ // If we have a watcher, preflight the move before committing to it.
+ // Checks for other available tasks; however, if none are available, skips because this
+ // is the bottommost task.
if (mAtmService.mController != null && isTopRootTaskInDisplayArea()) {
- ActivityRecord next = topRunningActivity(null, task.mTaskId);
- if (next == null) {
- next = topRunningActivity(null, INVALID_TASK_ID);
- }
+ final ActivityRecord next = getDisplayArea().getActivity(
+ a -> isTopRunning(a, task.mTaskId, null /* notTop */));
if (next != null) {
+ if (next.isState(RESUMED)) {
+ return true;
+ }
// ask watcher if this is allowed
boolean moveOK = true;
try {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
index cc957bd..1988f26 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotCache.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
@@ -36,6 +36,7 @@
void putSnapshot(Task task, TaskSnapshot snapshot) {
synchronized (mLock) {
snapshot.addReference(TaskSnapshot.REFERENCE_CACHE);
+ snapshot.setSafeRelease(mSafeSnapshotReleaser);
final CacheEntry entry = mRunningCache.get(task.mTaskId);
if (entry != null) {
mAppIdMap.remove(entry.topApp);
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 51c3da0..02b53b0 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -512,9 +512,14 @@
return false;
}
+ /** Returns {@code true} if the display contains a collecting transition. */
+ boolean isCollectingTransitionOnDisplay(@NonNull DisplayContent dc) {
+ return mCollectingTransition != null && mCollectingTransition.isOnDisplay(dc);
+ }
+
/** Returns {@code true} if the display contains a running or pending transition. */
boolean isTransitionOnDisplay(@NonNull DisplayContent dc) {
- if (mCollectingTransition != null && mCollectingTransition.isOnDisplay(dc)) {
+ if (isCollectingTransitionOnDisplay(dc)) {
return true;
}
for (int i = mWaitingTransitions.size() - 1; i >= 0; --i) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 5b4870b..b1422c2 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -55,14 +55,12 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.CallSuper;
-import android.annotation.ColorInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.ScreenOrientation;
import android.content.res.Configuration;
-import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Debug;
@@ -105,7 +103,6 @@
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -218,14 +215,6 @@
protected final WindowManagerService mWmService;
final TransitionController mTransitionController;
- /**
- * Sources which triggered a surface animation on this container. An animation target can be
- * promoted to higher level, for example, from a set of {@link ActivityRecord}s to
- * {@link Task}. In this case, {@link ActivityRecord}s are set on this variable while
- * the animation is running, and reset after finishing it.
- */
- private final ArraySet<WindowContainer> mSurfaceAnimationSources = new ArraySet<>();
-
private final Point mTmpPos = new Point();
protected final Point mLastSurfacePosition = new Point();
protected @Surface.Rotation int mLastDeltaRotation = Surface.ROTATION_0;
@@ -279,17 +268,6 @@
*/
int mTransitFlags;
- /** Layer used to constrain the animation to a container's stack bounds. */
- SurfaceControl mAnimationBoundsLayer;
-
- /** Whether this container needs to create mAnimationBoundsLayer for cropping animations. */
- boolean mNeedsAnimationBoundsLayer;
-
- /**
- * This gets used during some open/close transitions as well as during a change transition
- * where it represents the starting-state snapshot.
- */
- final Point mTmpPoint = new Point();
protected final Rect mTmpRect = new Rect();
final Rect mTmpPrevBounds = new Rect();
@@ -2961,7 +2939,6 @@
}
void cancelAnimation() {
- doAnimationFinished(mSurfaceAnimator.getAnimationType(), mSurfaceAnimator.getAnimation());
mSurfaceAnimator.cancelAnimation();
}
@@ -2992,10 +2969,6 @@
|| (getParent() != null && getParent().inPinnedWindowingMode());
}
- ArraySet<WindowContainer> getAnimationSources() {
- return mSurfaceAnimationSources;
- }
-
@Override
public Builder makeAnimationLeash() {
return makeSurface().setContainerLayer();
@@ -3094,21 +3067,10 @@
return mAnimationLeash;
}
- private void doAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
- for (int i = 0; i < mSurfaceAnimationSources.size(); ++i) {
- mSurfaceAnimationSources.valueAt(i).onAnimationFinished(type, anim);
- }
- mSurfaceAnimationSources.clear();
- if (mDisplayContent != null) {
- mDisplayContent.onWindowAnimationFinished(this, type);
- }
- }
-
/**
* Called when an animation has finished running.
*/
protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
- doAnimationFinished(type, anim);
mWmService.onAnimationFinished();
}
@@ -3821,50 +3783,6 @@
return true;
}
- private class AnimationRunnerBuilder {
- /**
- * Runs when the surface stops animating
- */
- private final List<Runnable> mOnAnimationFinished = new LinkedList<>();
- /**
- * Runs when the animation is cancelled but the surface is still animating
- */
- private final List<Runnable> mOnAnimationCancelled = new LinkedList<>();
-
- private void setTaskBackgroundColor(@ColorInt int backgroundColor) {
- TaskDisplayArea taskDisplayArea = getTaskDisplayArea();
-
- if (taskDisplayArea != null && backgroundColor != Color.TRANSPARENT) {
- taskDisplayArea.setBackgroundColor(backgroundColor);
-
- // Atomic counter to make sure the clearColor callback is only called one.
- // It will be called twice in the case we cancel the animation without restart
- // (in that case it will run as the cancel and finished callbacks).
- final AtomicInteger callbackCounter = new AtomicInteger(0);
- final Runnable clearBackgroundColorHandler = () -> {
- if (callbackCounter.getAndIncrement() == 0) {
- taskDisplayArea.clearBackgroundColor();
- }
- };
-
- // We want to make sure this is called both when the surface stops animating and
- // also when an animation is cancelled (i.e. animation is replaced by another
- // animation but and so the surface is still animating)
- mOnAnimationFinished.add(clearBackgroundColorHandler);
- mOnAnimationCancelled.add(clearBackgroundColorHandler);
- }
- }
-
- private IAnimationStarter build() {
- return (Transaction t, AnimationAdapter adapter, boolean hidden,
- @AnimationType int type, @Nullable AnimationAdapter snapshotAnim) -> {
- startAnimation(getPendingTransaction(), adapter, !isVisible(), type,
- (animType, anim) -> mOnAnimationFinished.forEach(Runnable::run),
- () -> mOnAnimationCancelled.forEach(Runnable::run), snapshotAnim);
- };
- }
- }
-
private interface IAnimationStarter {
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type, @Nullable AnimationAdapter snapshotAnim);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a9bb690..00a437c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1845,9 +1845,12 @@
// Only a presentation window needs a transition because its visibility affets the
// lifecycle of apps below (b/390481865).
if (enablePresentationForConnectedDisplays() && win.isPresentation()) {
- Transition transition = null;
+ final boolean wasTransitionOnDisplay =
+ win.mTransitionController.isCollectingTransitionOnDisplay(displayContent);
+ Transition newlyCreatedTransition = null;
if (!win.mTransitionController.isCollecting()) {
- transition = win.mTransitionController.createAndStartCollecting(TRANSIT_OPEN);
+ newlyCreatedTransition =
+ win.mTransitionController.createAndStartCollecting(TRANSIT_OPEN);
}
win.mTransitionController.collect(win.mToken);
res |= addWindowInner(win, displayPolicy, activity, displayContent, outInsetsState,
@@ -1856,9 +1859,14 @@
// A presentation hides all activities behind on the same display.
win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null,
/*notifyClients=*/ true);
- win.mTransitionController.getCollectingTransition().setReady(win.mToken, true);
- if (transition != null) {
- win.mTransitionController.requestStartTransition(transition, null,
+ if (!wasTransitionOnDisplay && win.mTransitionController
+ .isCollectingTransitionOnDisplay(displayContent)) {
+ // Set the display ready only when the display gets added to the collecting
+ // transition in this operation.
+ win.mTransitionController.setReady(win.mToken);
+ }
+ if (newlyCreatedTransition != null) {
+ win.mTransitionController.requestStartTransition(newlyCreatedTransition, null,
null /* remoteTransition */, null /* displayChange */);
}
} else {
@@ -8835,48 +8843,45 @@
}
void updateNonSystemOverlayWindowsVisibilityIfNeeded(WindowState win, boolean surfaceShown) {
- if (!win.hideNonSystemOverlayWindowsWhenVisible()
- && !mHidingNonSystemOverlayWindows.contains(win)) {
+ final boolean effective = (surfaceShown && win.hideNonSystemOverlayWindowsWhenVisible());
+ if (effective == mHidingNonSystemOverlayWindows.contains(win)) {
return;
}
- final boolean systemAlertWindowsHidden = !mHidingNonSystemOverlayWindows.isEmpty();
- final int numUIDsRequestHidingPreUpdate = mHidingNonSystemOverlayWindowsCountPerUid.size();
- if (surfaceShown && win.hideNonSystemOverlayWindowsWhenVisible()) {
- if (!mHidingNonSystemOverlayWindows.contains(win)) {
- mHidingNonSystemOverlayWindows.add(win);
- int uid = win.getOwningUid();
- int count = mHidingNonSystemOverlayWindowsCountPerUid.getOrDefault(uid, 0);
- mHidingNonSystemOverlayWindowsCountPerUid.put(uid, count + 1);
- }
+
+ if (effective) {
+ mHidingNonSystemOverlayWindows.add(win);
} else {
mHidingNonSystemOverlayWindows.remove(win);
- int uid = win.getOwningUid();
- int count = mHidingNonSystemOverlayWindowsCountPerUid.getOrDefault(uid, 0);
- if (count <= 1) {
- mHidingNonSystemOverlayWindowsCountPerUid.remove(win.getOwningUid());
- } else {
- mHidingNonSystemOverlayWindowsCountPerUid.put(uid, count - 1);
- }
}
- final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty();
- final int numUIDSRequestHidingPostUpdate = mHidingNonSystemOverlayWindowsCountPerUid.size();
+
+ final boolean changed;
if (Flags.fixHideOverlayApi()) {
- if (numUIDSRequestHidingPostUpdate == numUIDsRequestHidingPreUpdate) {
- return;
+ final int uid = win.getOwningUid();
+ final int numUIDsPreUpdate = mHidingNonSystemOverlayWindowsCountPerUid.size();
+ final int newCount = mHidingNonSystemOverlayWindowsCountPerUid.getOrDefault(uid, 0)
+ + (effective ? +1 : -1);
+ if (newCount <= 0) {
+ mHidingNonSystemOverlayWindowsCountPerUid.remove(uid);
+ } else {
+ mHidingNonSystemOverlayWindowsCountPerUid.put(uid, newCount);
}
- // The visibility of SAWs needs to be refreshed only when the number of uids that
- // request hiding SAWs changes 0->1, 1->0, 1->2 or 2->1.
- if (numUIDSRequestHidingPostUpdate != 1 && numUIDsRequestHidingPreUpdate != 1) {
- return;
- }
+ final int numUIDsPostUpdate = mHidingNonSystemOverlayWindowsCountPerUid.size();
+ // The visibility of SAWs needs to be refreshed when the number of uids that
+ // request hiding SAWs changes between "0", "1", or "2+".
+ changed = (numUIDsPostUpdate != numUIDsPreUpdate)
+ && (numUIDsPostUpdate <= 1 || numUIDsPreUpdate <= 1);
} else {
- if (systemAlertWindowsHidden == hideSystemAlertWindows) {
- return;
- }
+ // The visibility of SAWs needs to be refreshed when the number of windows that
+ // request hiding SAWs changes between "0" or "1+".
+ changed = (effective && mHidingNonSystemOverlayWindows.size() == 1)
+ || (!effective && mHidingNonSystemOverlayWindows.isEmpty());
}
- mRoot.forAllWindows((w) -> {
- w.setForceHideNonSystemOverlayWindowIfNeeded(shouldHideNonSystemOverlayWindow(w));
- }, false /* traverseTopToBottom */);
+
+ if (changed) {
+ mRoot.forAllWindows((w) -> {
+ w.setForceHideNonSystemOverlayWindowIfNeeded(shouldHideNonSystemOverlayWindow(w));
+ }, false /* traverseTopToBottom */);
+ }
}
/** Called from Accessibility Controller to apply magnification spec */
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 22ddd5f..a03b765 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2365,9 +2365,12 @@
// Only a presentation window needs a transition because its visibility affets the
// lifecycle of apps below (b/390481865).
if (enablePresentationForConnectedDisplays() && isPresentation()) {
- Transition transition = null;
+ final boolean wasTransitionOnDisplay =
+ mTransitionController.isCollectingTransitionOnDisplay(displayContent);
+ Transition newlyCreatedTransition = null;
if (!mTransitionController.isCollecting()) {
- transition = mTransitionController.createAndStartCollecting(TRANSIT_CLOSE);
+ newlyCreatedTransition =
+ mTransitionController.createAndStartCollecting(TRANSIT_CLOSE);
}
mTransitionController.collect(mToken);
mAnimatingExit = true;
@@ -2376,9 +2379,14 @@
// A presentation hides all activities behind on the same display.
mDisplayContent.ensureActivitiesVisible(/*starting=*/ null,
/*notifyClients=*/ true);
- mTransitionController.getCollectingTransition().setReady(mToken, true);
- if (transition != null) {
- mTransitionController.requestStartTransition(transition, null,
+ if (!wasTransitionOnDisplay && mTransitionController
+ .isCollectingTransitionOnDisplay(displayContent)) {
+ // Set the display ready only when the display gets added to the collecting
+ // transition in this operation.
+ mTransitionController.setReady(mToken);
+ }
+ if (newlyCreatedTransition != null) {
+ mTransitionController.requestStartTransition(newlyCreatedTransition, null,
null /* remoteTransition */, null /* displayChange */);
}
} else {
@@ -4689,40 +4697,6 @@
return super.handleCompleteDeferredRemoval();
}
- boolean clearAnimatingFlags() {
- boolean didSomething = false;
- // We also don't clear the mAnimatingExit flag for windows which have the
- // mRemoveOnExit flag. This indicates an explicit remove request has been issued
- // by the client. We should let animation proceed and not clear this flag or
- // they won't eventually be removed by WindowStateAnimator#finishExit.
- if (!mRemoveOnExit) {
- // Clear mAnimating flag together with mAnimatingExit. When animation
- // changes from exiting to entering, we need to clear this flag until the
- // new animation gets applied, so that isAnimationStarting() becomes true
- // until then.
- // Otherwise applySurfaceChangesTransaction will fail to skip surface
- // placement for this window during this period, one or more frame will
- // show up with wrong position or scale.
- if (mAnimatingExit) {
- mAnimatingExit = false;
- ProtoLog.d(WM_DEBUG_ANIM, "Clear animatingExit: reason=clearAnimatingFlags win=%s",
- this);
- didSomething = true;
- }
- if (mDestroying) {
- mDestroying = false;
- mWmService.mDestroySurface.remove(this);
- didSomething = true;
- }
- }
-
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- didSomething |= (mChildren.get(i)).clearAnimatingFlags();
- }
-
- return didSomething;
- }
-
public boolean isRtl() {
return getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index ec8794f..e295115 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1978,6 +1978,11 @@
return inputdispatcher::KeyEntry::InterceptKeyResult::SKIP;
}
+ // -2 : Skip sending even to application and go directly to post processing e.g. fallbacks.
+ if (delayMillis == -2) {
+ return inputdispatcher::KeyEntry::InterceptKeyResult::FALLBACK;
+ }
+
return milliseconds_to_nanoseconds(delayMillis);
}
@@ -2543,7 +2548,7 @@
static jboolean nativeTransferTouchGesture(JNIEnv* env, jobject nativeImplObj,
jobject fromChannelTokenObj, jobject toChannelTokenObj,
- jboolean isDragDrop) {
+ jboolean isDragDrop, jboolean transferEntireGesture) {
if (fromChannelTokenObj == nullptr || toChannelTokenObj == nullptr) {
return JNI_FALSE;
}
@@ -2553,7 +2558,8 @@
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
if (im->getInputManager()->getDispatcher().transferTouchGesture(fromChannelToken,
- toChannelToken, isDragDrop)) {
+ toChannelToken, isDragDrop,
+ transferEntireGesture)) {
return JNI_TRUE;
} else {
return JNI_FALSE;
@@ -3339,7 +3345,7 @@
{"requestPointerCapture", "(Landroid/os/IBinder;Z)V", (void*)nativeRequestPointerCapture},
{"setInputDispatchMode", "(ZZ)V", (void*)nativeSetInputDispatchMode},
{"setSystemUiLightsOut", "(Z)V", (void*)nativeSetSystemUiLightsOut},
- {"transferTouchGesture", "(Landroid/os/IBinder;Landroid/os/IBinder;Z)Z",
+ {"transferTouchGesture", "(Landroid/os/IBinder;Landroid/os/IBinder;ZZ)Z",
(void*)nativeTransferTouchGesture},
{"transferTouch", "(Landroid/os/IBinder;I)Z", (void*)nativeTransferTouchOnDisplay},
{"getMousePointerSpeed", "()I", (void*)nativeGetMousePointerSpeed},
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f055feb..d984fcc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -9628,32 +9628,30 @@
}
}
- // TODO: with a quick glance this logic seems incomplete that it doesn't properly handle
- // the different behaviour between a profile with separate challenge vs a profile with
- // unified challenge, which was part of getActiveAdminsForLockscreenPoliciesLocked()
- // before the migration.
if (Flags.setKeyguardDisabledFeaturesCoexistence()) {
- Integer features = mDevicePolicyEngine.getResolvedPolicy(
- PolicyDefinition.KEYGUARD_DISABLED_FEATURES,
- affectedUserId);
-
return Binder.withCleanCallingIdentity(() -> {
- int combinedFeatures = features == null ? 0 : features;
- List<UserInfo> profiles = mUserManager.getProfiles(affectedUserId);
- for (UserInfo profile : profiles) {
- int profileId = profile.id;
- if (profileId == affectedUserId) {
+ if (!parent && isManagedProfile(userHandle)) {
+ return mDevicePolicyEngine.getResolvedPolicy(
+ PolicyDefinition.KEYGUARD_DISABLED_FEATURES, userHandle);
+ }
+
+ int targetUserId = getProfileParentUserIfRequested(userHandle, parent);
+
+ int combinedPolicy = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
+ for (UserInfo profile : mUserManager.getProfiles(targetUserId)) {
+ if (mLockPatternUtils.isSeparateProfileChallengeEnabled(profile.id)) {
continue;
}
- Integer profileFeatures = mDevicePolicyEngine.getResolvedPolicy(
- PolicyDefinition.KEYGUARD_DISABLED_FEATURES,
- profileId);
- if (profileFeatures != null) {
- combinedFeatures |= (profileFeatures
- & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER);
+
+ Integer profilePolicy = mDevicePolicyEngine.getResolvedPolicy(
+ PolicyDefinition.KEYGUARD_DISABLED_FEATURES, profile.id);
+ profilePolicy = profilePolicy == null ? 0 : profilePolicy;
+ if (profile.id != userHandle) {
+ profilePolicy &= PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
}
+ combinedPolicy |= profilePolicy;
}
- return combinedFeatures;
+ return combinedPolicy;
});
}
diff --git a/services/proguard.flags b/services/proguard.flags
index dd3757c..00e0a6e 100644
--- a/services/proguard.flags
+++ b/services/proguard.flags
@@ -60,6 +60,7 @@
# Referenced in wear-service
-keep public class com.android.server.wm.WindowManagerInternal { *; }
-keep public class com.android.server.wm.WindowManagerInternal$WindowFocusChangeListener { *; }
+-keep public class com.android.server.wm.ActivityAssistInfo { *; }
# JNI keep rules
# The global keep rule for native methods allows stripping of such methods if they're unreferenced
diff --git a/services/supervision/java/com/android/server/supervision/SupervisionService.java b/services/supervision/java/com/android/server/supervision/SupervisionService.java
index bb6339c..0b5a95b0 100644
--- a/services/supervision/java/com/android/server/supervision/SupervisionService.java
+++ b/services/supervision/java/com/android/server/supervision/SupervisionService.java
@@ -27,6 +27,7 @@
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
+import android.app.KeyguardManager;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.supervision.ISupervisionManager;
@@ -147,9 +148,21 @@
@Override
@Nullable
public Intent createConfirmSupervisionCredentialsIntent() {
- // TODO(b/392961554): (1) Return null if supervision is not enabled.
- // (2) check if PIN exists before return a valid intent.
enforceAnyPermission(QUERY_USERS, MANAGE_USERS);
+ if (!isSupervisionEnabledForUser(mContext.getUserId())) {
+ return null;
+ }
+ // Verify the supervising user profile exists and has a secure credential set.
+ final int supervisingUserId = mInjector.getUserManagerInternal().getSupervisingProfileId();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (supervisingUserId == UserHandle.USER_NULL
+ || !mInjector.getKeyguardManager().isDeviceSecure(supervisingUserId)) {
+ return null;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
final Intent intent = new Intent(ACTION_CONFIRM_SUPERVISION_CREDENTIALS);
// explicitly set the package for security
intent.setPackage("com.android.settings");
@@ -277,6 +290,7 @@
static class Injector {
private final Context mContext;
private DevicePolicyManagerInternal mDpmInternal;
+ private KeyguardManager mKeyguardManager;
private PackageManager mPackageManager;
private UserManagerInternal mUserManagerInternal;
@@ -292,6 +306,13 @@
return mDpmInternal;
}
+ KeyguardManager getKeyguardManager() {
+ if (mKeyguardManager == null) {
+ mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
+ }
+ return mKeyguardManager;
+ }
+
PackageManager getPackageManager() {
if (mPackageManager == null) {
mPackageManager = mContext.getPackageManager();
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/UserDataPreparerTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/UserDataPreparerTest.java
index 554b5b4..7404248 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/UserDataPreparerTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/UserDataPreparerTest.java
@@ -98,9 +98,9 @@
File systemDeDir = mUserDataPreparer.getDataSystemDeDirectory(TEST_USER_ID);
systemDeDir.mkdirs();
mUserDataPreparer.prepareUserData(TEST_USER, StorageManager.FLAG_STORAGE_DE);
- verify(mStorageManagerMock).prepareUserStorage(isNull(String.class), eq(TEST_USER_ID),
+ verify(mStorageManagerMock).prepareUserStorage(isNull(), eq(TEST_USER_ID),
eq(StorageManager.FLAG_STORAGE_DE));
- verify(mInstaller).createUserData(isNull(String.class), eq(TEST_USER_ID),
+ verify(mInstaller).createUserData(isNull(), eq(TEST_USER_ID),
eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_DE));
int serialNumber = UserDataPreparer.getSerialNumber(userDeDir);
assertEquals(TEST_USER_SERIAL, serialNumber);
@@ -115,9 +115,9 @@
File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID);
systemCeDir.mkdirs();
mUserDataPreparer.prepareUserData(TEST_USER, StorageManager.FLAG_STORAGE_CE);
- verify(mStorageManagerMock).prepareUserStorage(isNull(String.class), eq(TEST_USER_ID),
+ verify(mStorageManagerMock).prepareUserStorage(isNull(), eq(TEST_USER_ID),
eq(StorageManager.FLAG_STORAGE_CE));
- verify(mInstaller).createUserData(isNull(String.class), eq(TEST_USER_ID),
+ verify(mInstaller).createUserData(isNull(), eq(TEST_USER_ID),
eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_CE));
int serialNumber = UserDataPreparer.getSerialNumber(userCeDir);
assertEquals(TEST_USER_SERIAL, serialNumber);
@@ -129,10 +129,10 @@
public void testPrepareUserData_forNewUser_destroysOnFailure() throws Exception {
TEST_USER.lastLoggedInTime = 0;
doThrow(new IllegalStateException("expected exception for test")).when(mStorageManagerMock)
- .prepareUserStorage(isNull(String.class), eq(TEST_USER_ID),
+ .prepareUserStorage(isNull(), eq(TEST_USER_ID),
eq(StorageManager.FLAG_STORAGE_CE));
mUserDataPreparer.prepareUserData(TEST_USER, StorageManager.FLAG_STORAGE_CE);
- verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID),
+ verify(mStorageManagerMock).destroyUserStorage(isNull(), eq(TEST_USER_ID),
eq(StorageManager.FLAG_STORAGE_CE));
}
@@ -140,10 +140,10 @@
public void testPrepareUserData_forExistingUser_doesNotDestroyOnFailure() throws Exception {
TEST_USER.lastLoggedInTime = System.currentTimeMillis();
doThrow(new IllegalStateException("expected exception for test")).when(mStorageManagerMock)
- .prepareUserStorage(isNull(String.class), eq(TEST_USER_ID),
+ .prepareUserStorage(isNull(), eq(TEST_USER_ID),
eq(StorageManager.FLAG_STORAGE_CE));
mUserDataPreparer.prepareUserData(TEST_USER, StorageManager.FLAG_STORAGE_CE);
- verify(mStorageManagerMock, never()).destroyUserStorage(isNull(String.class),
+ verify(mStorageManagerMock, never()).destroyUserStorage(isNull(),
eq(TEST_USER_ID), eq(StorageManager.FLAG_STORAGE_CE));
}
@@ -171,9 +171,9 @@
mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_DE);
- verify(mInstaller).destroyUserData(isNull(String.class), eq(TEST_USER_ID),
+ verify(mInstaller).destroyUserData(isNull(), eq(TEST_USER_ID),
eq(StorageManager.FLAG_STORAGE_DE));
- verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID),
+ verify(mStorageManagerMock).destroyUserStorage(isNull(), eq(TEST_USER_ID),
eq(StorageManager.FLAG_STORAGE_DE));
// systemDir (normal path: /data/system/users/$userId) should have been deleted.
@@ -195,9 +195,9 @@
mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_CE);
- verify(mInstaller).destroyUserData(isNull(String.class), eq(TEST_USER_ID),
+ verify(mInstaller).destroyUserData(isNull(), eq(TEST_USER_ID),
eq(StorageManager.FLAG_STORAGE_CE));
- verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID),
+ verify(mStorageManagerMock).destroyUserStorage(isNull(), eq(TEST_USER_ID),
eq(StorageManager.FLAG_STORAGE_CE));
// systemCeDir (normal path: /data/system_ce/$userId) should still exist but be empty, since
@@ -225,7 +225,7 @@
.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL, Arrays.asList(u1, u2),
Arrays.asList(dir1, dir2, dir3));
// Verify that user 3 data is removed
- verify(mInstaller).destroyUserData(isNull(String.class), eq(3),
+ verify(mInstaller).destroyUserData(isNull(), eq(3),
eq(StorageManager.FLAG_STORAGE_DE|StorageManager.FLAG_STORAGE_CE));
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
index 026e72f..d0226805 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
@@ -26,15 +26,12 @@
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_WIFI_SCAN;
import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
-import static android.app.AppOpsManager.UID_STATE_CACHED;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
import static android.app.AppOpsManager.UID_STATE_TOP;
import static android.permission.flags.Flags.delayUidStateChangesFromCapabilityUpdates;
-import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -42,7 +39,6 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -64,7 +60,6 @@
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.mockito.quality.Strictness;
import java.util.PriorityQueue;
@@ -94,7 +89,6 @@
public void setUp() {
mSession = ExtendedMockito.mockitoSession()
.initMocks(this)
- .strictness(Strictness.LENIENT)
.startMocking();
mConstants.TOP_STATE_SETTLE_TIME = 10 * 1000L;
mConstants.FG_SERVICE_STATE_SETTLE_TIME = 5 * 1000L;
@@ -591,221 +585,6 @@
}
@Test
- public void testUidStateChangedCallbackCachedToBackground() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
- ActivityManager.PROCESS_STATE_RECEIVER);
- }
-
- @Test
- public void testUidStateChangedCallbackCachedToForeground() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
- ActivityManager.PROCESS_STATE_BOUND_TOP);
- }
-
- @Test
- public void testUidStateChangedCallbackCachedToForegroundService() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
- }
-
- @Test
- public void testUidStateChangedCallbackCachedToTop() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
- ActivityManager.PROCESS_STATE_TOP);
- }
-
- @Test
- public void testUidStateChangedCallbackBackgroundToCached() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_RECEIVER,
- ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
- }
-
- @Test
- public void testUidStateChangedCallbackBackgroundToForeground() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_RECEIVER,
- ActivityManager.PROCESS_STATE_BOUND_TOP);
- }
-
- @Test
- public void testUidStateChangedCallbackBackgroundToForegroundService() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_RECEIVER,
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
- }
-
- @Test
- public void testUidStateChangedCallbackBackgroundToTop() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_RECEIVER,
- ActivityManager.PROCESS_STATE_TOP);
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundToCached() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_BOUND_TOP,
- ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundToBackground() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_BOUND_TOP,
- ActivityManager.PROCESS_STATE_RECEIVER);
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundToForegroundService() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_BOUND_TOP,
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundToTop() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_BOUND_TOP,
- ActivityManager.PROCESS_STATE_TOP);
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundServiceToCached() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
- ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundServiceToBackground() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
- ActivityManager.PROCESS_STATE_RECEIVER);
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundServiceToForeground() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
- ActivityManager.PROCESS_STATE_BOUND_TOP);
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundServiceToTop() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
- ActivityManager.PROCESS_STATE_TOP);
- }
-
- @Test
- public void testUidStateChangedCallbackTopToCached() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_TOP,
- ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
- }
-
- @Test
- public void testUidStateChangedCallbackTopToBackground() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_TOP,
- ActivityManager.PROCESS_STATE_RECEIVER);
- }
-
- @Test
- public void testUidStateChangedCallbackTopToForeground() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_TOP,
- ActivityManager.PROCESS_STATE_BOUND_TOP);
- }
-
- @Test
- public void testUidStateChangedCallbackTopToForegroundService() {
- testUidStateChangedCallback(
- ActivityManager.PROCESS_STATE_TOP,
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
- }
-
- @Test
- public void testUidStateChangedCallbackCachedToNonexistent() {
- UidStateChangedCallback cb = addUidStateChangeCallback();
-
- procStateBuilder(UID)
- .cachedState()
- .update();
-
- procStateBuilder(UID)
- .nonExistentState()
- .update();
-
- verify(cb, never()).onUidStateChanged(anyInt(), anyInt(), anyBoolean());
- }
-
- @Test
- public void testUidStateChangedCallbackBackgroundToNonexistent() {
- UidStateChangedCallback cb = addUidStateChangeCallback();
-
- procStateBuilder(UID)
- .backgroundState()
- .update();
-
- procStateBuilder(UID)
- .nonExistentState()
- .update();
-
- verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(false));
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundToNonexistent() {
- UidStateChangedCallback cb = addUidStateChangeCallback();
-
- procStateBuilder(UID)
- .foregroundState()
- .update();
-
- procStateBuilder(UID)
- .nonExistentState()
- .update();
-
- verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true));
- }
-
- @Test
- public void testUidStateChangedCallbackForegroundServiceToNonexistent() {
- UidStateChangedCallback cb = addUidStateChangeCallback();
-
- procStateBuilder(UID)
- .foregroundServiceState()
- .update();
-
- procStateBuilder(UID)
- .nonExistentState()
- .update();
-
- verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true));
- }
-
- @Test
- public void testUidStateChangedCallbackTopToNonexistent() {
- UidStateChangedCallback cb = addUidStateChangeCallback();
-
- procStateBuilder(UID)
- .topState()
- .update();
-
- procStateBuilder(UID)
- .nonExistentState()
- .update();
-
- verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true));
- }
-
- @Test
public void testUidStateChangedBackgroundThenForegroundImmediately() {
procStateBuilder(UID)
.topState()
@@ -882,32 +661,6 @@
assertEquals(UID_STATE_TOP, mIntf.getUidState(UID));
}
- public void testUidStateChangedCallback(int initialState, int finalState) {
- int initialUidState = processStateToUidState(initialState);
- int finalUidState = processStateToUidState(finalState);
- boolean foregroundChange = initialUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
- != finalUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED;
- boolean finalUidStateIsBackgroundAndLessImportant =
- finalUidState > UID_STATE_MAX_LAST_NON_RESTRICTED
- && finalUidState > initialUidState;
-
- UidStateChangedCallback cb = addUidStateChangeCallback();
-
- procStateBuilder(UID)
- .setState(initialState)
- .update();
-
- procStateBuilder(UID)
- .setState(finalState)
- .update();
-
- if (finalUidStateIsBackgroundAndLessImportant) {
- mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME + 1);
- }
-
- verify(cb, atLeastOnce())
- .onUidStateChanged(eq(UID), eq(finalUidState), eq(foregroundChange));
- }
private UidStateChangedCallback addUidStateChangeCallback() {
UidStateChangedCallback cb =
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTransitionCallbackTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTransitionCallbackTest.java
new file mode 100644
index 0000000..60cdfee
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTransitionCallbackTest.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appop;
+
+import static android.app.AppOpsManager.UID_STATE_CACHED;
+import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
+import static android.app.AppOpsManager.UID_STATE_NONEXISTENT;
+import static android.permission.flags.Flags.finishRunningOpsForKilledPackages;
+
+import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.internal.os.Clock;
+import com.android.server.appop.AppOpsUidStateTracker.UidStateChangedCallback;
+import com.android.server.appop.AppOpsUidStateTrackerImpl.DelayableExecutor;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.PriorityQueue;
+
+@RunWith(Parameterized.class)
+public class AppOpsUidStateTrackerTransitionCallbackTest {
+
+ private static final int UID = 10001;
+
+ private static final int STATE_TOP = ActivityManager.PROCESS_STATE_TOP;
+ private static final int STATE_FOREGROUND_SERVICE =
+ ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+ private static final int STATE_FOREGROUND = ActivityManager.PROCESS_STATE_BOUND_TOP;
+ private static final int STATE_BACKGROUND = ActivityManager.PROCESS_STATE_SERVICE;
+ private static final int STATE_CACHED = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+ private static final int STATE_NONEXISTENT = ActivityManager.PROCESS_STATE_NONEXISTENT;
+
+ private static final int[] STATES = {STATE_TOP, STATE_FOREGROUND_SERVICE, STATE_FOREGROUND,
+ STATE_BACKGROUND, STATE_CACHED, STATE_NONEXISTENT};
+ private static final String[] STATES_NAMES = {"TOP", "FOREGROUND_SERVICE", "FOREGROUND",
+ "BACKGROUND", "CACHED", "NONEXISTENT"};
+
+ @Mock
+ ActivityManagerInternal mAmi;
+
+ @Mock
+ AppOpsService.Constants mConstants;
+
+ AppOpsUidStateTrackerTestExecutor mExecutor = new AppOpsUidStateTrackerTestExecutor();
+
+ AppOpsUidStateTrackerTestClock mClock = new AppOpsUidStateTrackerTestClock(mExecutor);
+
+ AppOpsUidStateTracker mIntf;
+
+ StaticMockitoSession mSession;
+
+ private final int mInitialState;
+ private final int mMiddleState;
+ private final int mFinalState;
+
+ @Parameterized.Parameters(name = "{3} -> {4} -> {5}")
+ public static Collection<Object[]> getParameters() {
+ ArrayList<Object[]> parameters = new ArrayList<>();
+
+ for (int i = 0; i < STATES.length; i++) {
+ for (int j = 0; j < STATES.length; j++) {
+ for (int k = 0; k < STATES.length; k++) {
+ parameters
+ .add(new Object[]{STATES[i], STATES[j], STATES[k], STATES_NAMES[i],
+ STATES_NAMES[j], STATES_NAMES[k]});
+ }
+ }
+ }
+
+ return parameters;
+ }
+
+ public AppOpsUidStateTrackerTransitionCallbackTest(int initialState, int middleState,
+ int finalState, String ignoredInitialStateName, String ignoredMiddleStateName,
+ String ignoredFinalStateName) {
+ mInitialState = initialState;
+ mMiddleState = middleState;
+ mFinalState = finalState;
+ }
+
+ @Before
+ public void setUp() {
+ mSession = ExtendedMockito.mockitoSession()
+ .initMocks(this)
+ .startMocking();
+ mConstants.TOP_STATE_SETTLE_TIME = 10 * 1000L;
+ mConstants.FG_SERVICE_STATE_SETTLE_TIME = 5 * 1000L;
+ mConstants.BG_STATE_SETTLE_TIME = 1 * 1000L;
+ mIntf = new AppOpsUidStateTrackerImpl(mAmi, mExecutor, mClock, mConstants,
+ Thread.currentThread());
+ }
+
+ @After
+ public void tearDown() {
+ mSession.finishMocking();
+ }
+
+ @Test
+ public void testUidStateChangedCallback() {
+ testUidStateTransition(mInitialState, mMiddleState, true);
+ testUidStateTransition(mMiddleState, mFinalState, false);
+ }
+
+ private void testUidStateTransition(int initialState, int finalState,
+ boolean initializeState) {
+ int initialUidState = processStateToUidState(initialState);
+ int finalUidState = processStateToUidState(finalState);
+
+ boolean expectUidProcessDeath =
+ finalUidState == UID_STATE_NONEXISTENT
+ && initialUidState != UID_STATE_NONEXISTENT
+ && finishRunningOpsForKilledPackages();
+
+ boolean foregroundChange = initialUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
+ != finalUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED;
+ boolean finalUidStateIsBackgroundAndLessImportant =
+ finalUidState > UID_STATE_MAX_LAST_NON_RESTRICTED
+ && finalUidState > initialUidState;
+
+ if (initializeState) {
+ mIntf.updateUidProcState(UID, initialState, ActivityManager.PROCESS_CAPABILITY_NONE);
+ }
+
+ UidStateChangedCallback cb = addUidStateChangeCallback();
+
+ mIntf.updateUidProcState(UID, finalState, ActivityManager.PROCESS_CAPABILITY_NONE);
+
+ if (finalUidStateIsBackgroundAndLessImportant) {
+ mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME + 1);
+ }
+
+ int expectedInitialUidState = initialUidState == UID_STATE_NONEXISTENT
+ ? UID_STATE_CACHED : initialUidState;
+ int expectedFinalUidState = finalUidState == UID_STATE_NONEXISTENT
+ ? UID_STATE_CACHED : finalUidState;
+
+ if (expectedInitialUidState != expectedFinalUidState) {
+ verify(cb, times(1))
+ .onUidStateChanged(eq(UID), eq(expectedFinalUidState), eq(foregroundChange));
+ verify(cb, times(1))
+ .onUidStateChanged(anyInt(), anyInt(), anyBoolean());
+ } else {
+ verify(cb, never()).onUidStateChanged(anyInt(), anyInt(), anyBoolean());
+ }
+ if (expectUidProcessDeath) {
+ verify(cb, times(1)).onUidProcessDeath(eq(UID));
+ verify(cb, times(1)).onUidProcessDeath(anyInt());
+ } else {
+ verify(cb, never()).onUidProcessDeath(anyInt());
+ }
+ }
+
+ private UidStateChangedCallback addUidStateChangeCallback() {
+ UidStateChangedCallback cb =
+ Mockito.mock(UidStateChangedCallback.class);
+ mIntf.addUidStateChangedCallback(r -> r.run(), cb);
+ return cb;
+ }
+
+ private static class AppOpsUidStateTrackerTestClock extends Clock {
+
+ private AppOpsUidStateTrackerTestExecutor mExecutor;
+ long mElapsedRealTime = 0x5f3759df;
+
+ AppOpsUidStateTrackerTestClock(AppOpsUidStateTrackerTestExecutor executor) {
+ mExecutor = executor;
+ executor.setUptime(mElapsedRealTime);
+ }
+
+ @Override
+ public long elapsedRealtime() {
+ return mElapsedRealTime;
+ }
+
+ void advanceTime(long time) {
+ mElapsedRealTime += time;
+ mExecutor.setUptime(mElapsedRealTime); // assume uptime == elapsedtime
+ }
+ }
+
+ private static class AppOpsUidStateTrackerTestExecutor implements DelayableExecutor {
+
+ private static class QueueElement implements Comparable<QueueElement> {
+
+ private long mExecutionTime;
+ private Runnable mRunnable;
+
+ private QueueElement(long executionTime, Runnable runnable) {
+ mExecutionTime = executionTime;
+ mRunnable = runnable;
+ }
+
+ @Override
+ public int compareTo(QueueElement queueElement) {
+ return Long.compare(mExecutionTime, queueElement.mExecutionTime);
+ }
+ }
+
+ private long mUptime = 0;
+
+ private PriorityQueue<QueueElement> mDelayedMessages = new PriorityQueue();
+
+ @Override
+ public void execute(Runnable runnable) {
+ runnable.run();
+ }
+
+ @Override
+ public void executeDelayed(Runnable runnable, long delay) {
+ if (delay <= 0) {
+ execute(runnable);
+ }
+
+ mDelayedMessages.add(new QueueElement(mUptime + delay, runnable));
+ }
+
+ private void setUptime(long uptime) {
+ while (!mDelayedMessages.isEmpty()
+ && mDelayedMessages.peek().mExecutionTime <= uptime) {
+ mDelayedMessages.poll().mRunnable.run();
+ }
+
+ mUptime = uptime;
+ }
+ }
+}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java
index 2b15231..a1cf94b 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java
@@ -26,16 +26,10 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import android.content.Context;
-import android.hardware.power.stats.Channel;
-import android.hardware.power.stats.EnergyConsumer;
import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyConsumerType;
-import android.hardware.power.stats.EnergyMeasurement;
-import android.hardware.power.stats.PowerEntity;
-import android.hardware.power.stats.StateResidencyResult;
import android.os.Handler;
import android.os.Looper;
import android.os.connectivity.WifiActivityEnergyInfo;
@@ -54,7 +48,6 @@
import org.junit.Test;
import java.util.Arrays;
-import java.util.concurrent.CompletableFuture;
/**
* Tests for {@link BatteryExternalStatsWorker}.
@@ -66,7 +59,7 @@
@android.platform.test.annotations.DisabledOnRavenwood
public class BatteryExternalStatsWorkerTest {
private BatteryExternalStatsWorker mBatteryExternalStatsWorker;
- private TestPowerStatsInternal mPowerStatsInternal;
+ private MockPowerStatsInternal mPowerStatsInternal;
private Handler mHandler;
@Before
@@ -80,7 +73,7 @@
mHandler, null, null, null,
new PowerProfile(context, true /* forTest */), buildScalingPolicies(),
new PowerStatsUidResolver());
- mPowerStatsInternal = new TestPowerStatsInternal();
+ mPowerStatsInternal = new MockPowerStatsInternal();
mBatteryExternalStatsWorker =
new BatteryExternalStatsWorker(new TestInjector(context), batteryStats, mHandler);
}
@@ -260,102 +253,4 @@
freqsByPolicy.put(4, new int[]{300000, 1000000, 2500000, 3000000});
return new CpuScalingPolicies(freqsByPolicy, freqsByPolicy);
}
-
- private static class TestPowerStatsInternal extends PowerStatsInternal {
- private final SparseArray<EnergyConsumer> mEnergyConsumers = new SparseArray();
- private final SparseArray<EnergyConsumerResult> mEnergyConsumerResults = new SparseArray();
- private final int mTimeSinceBoot = 0;
-
- @Override
- public EnergyConsumer[] getEnergyConsumerInfo() {
- final int size = mEnergyConsumers.size();
- final EnergyConsumer[] consumers = new EnergyConsumer[size];
- for (int i = 0; i < size; i++) {
- consumers[i] = mEnergyConsumers.valueAt(i);
- }
- return consumers;
- }
-
- @Override
- public CompletableFuture<EnergyConsumerResult[]> getEnergyConsumedAsync(
- int[] energyConsumerIds) {
- final CompletableFuture<EnergyConsumerResult[]> future = new CompletableFuture();
- final EnergyConsumerResult[] results;
- final int length = energyConsumerIds.length;
- if (length == 0) {
- final int size = mEnergyConsumerResults.size();
- results = new EnergyConsumerResult[size];
- for (int i = 0; i < size; i++) {
- results[i] = mEnergyConsumerResults.valueAt(i);
- }
- } else {
- results = new EnergyConsumerResult[length];
- for (int i = 0; i < length; i++) {
- results[i] = mEnergyConsumerResults.get(energyConsumerIds[i]);
- }
- }
- future.complete(results);
- return future;
- }
-
- @Override
- public PowerEntity[] getPowerEntityInfo() {
- return new PowerEntity[0];
- }
-
- @Override
- public CompletableFuture<StateResidencyResult[]> getStateResidencyAsync(
- int[] powerEntityIds) {
- return new CompletableFuture<>();
- }
-
- @Override
- public Channel[] getEnergyMeterInfo() {
- return new Channel[0];
- }
-
- @Override
- public CompletableFuture<EnergyMeasurement[]> readEnergyMeterAsync(
- int[] channelIds) {
- return new CompletableFuture<>();
- }
-
- /**
- * Util method to add a new EnergyConsumer for testing
- *
- * @return the EnergyConsumer id of the new EnergyConsumer
- */
- public int addEnergyConsumer(@EnergyConsumerType byte type, int ordinal, String name) {
- final EnergyConsumer consumer = new EnergyConsumer();
- final int id = getNextAvailableId();
- consumer.id = id;
- consumer.type = type;
- consumer.ordinal = ordinal;
- consumer.name = name;
- mEnergyConsumers.put(id, consumer);
-
- final EnergyConsumerResult result = new EnergyConsumerResult();
- result.id = id;
- result.timestampMs = mTimeSinceBoot;
- result.energyUWs = 0;
- mEnergyConsumerResults.put(id, result);
- return id;
- }
-
- public void incrementEnergyConsumption(int id, long energyUWs) {
- EnergyConsumerResult result = mEnergyConsumerResults.get(id, null);
- assertNotNull(result);
- result.energyUWs += energyUWs;
- }
-
- private int getNextAvailableId() {
- final int size = mEnergyConsumers.size();
- // Just return the first index that does not match the key (aka the EnergyConsumer id)
- for (int i = size - 1; i >= 0; i--) {
- if (mEnergyConsumers.keyAt(i) == i) return i + 1;
- }
- // Otherwise return the lowest id
- return 0;
- }
- }
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryHistoryStepDetailsProviderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryHistoryStepDetailsProviderTest.java
new file mode 100644
index 0000000..850cd88
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryHistoryStepDetailsProviderTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.os.BatteryManager;
+import android.os.BatteryStats;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Process;
+import android.power.PowerStatsInternal;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.os.BatteryStatsHistoryIterator;
+import com.android.internal.os.MonotonicClock;
+import com.android.internal.os.PowerProfile;
+import com.android.server.LocalServices;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Random;
+
+@RunWith(AndroidJUnit4.class)
+@android.platform.test.annotations.DisabledOnRavenwood(reason =
+ "PowerStatsInternal is not supported under Ravenwood")
+@SuppressWarnings("GuardedBy")
+public class BatteryHistoryStepDetailsProviderTest {
+ private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+
+ private final MockClock mMockClock = new MockClock();
+ private MockBatteryStatsImpl mBatteryStats;
+ private final Random mRandom = new Random();
+ private Handler mHandler;
+
+ @Before
+ public void setup() {
+ mMockClock.currentTime = 3000;
+ mHandler = new Handler(Looper.getMainLooper());
+ mBatteryStats = new MockBatteryStatsImpl(mMockClock, null, mHandler,
+ mock(PowerProfile.class));
+ mBatteryStats.setRecordAllHistoryLocked(true);
+ mBatteryStats.forceRecordAllHistory();
+ mBatteryStats.setNoAutoReset(true);
+ }
+
+ @Test
+ public void update() {
+ MockPowerStatsInternal powerStatsService = new MockPowerStatsInternal();
+ powerStatsService.addPowerEntity(42, "foo");
+ powerStatsService.addPowerEntityState(42, 0, "off");
+ powerStatsService.addPowerEntityState(42, 1, "on");
+ LocalServices.addService(PowerStatsInternal.class, powerStatsService);
+ mBatteryStats.onSystemReady(mock(Context.class));
+
+ mockUpdateCpuStats(100, 1_000_010, 1_000_010);
+ powerStatsService.addStateResidencyResult(42, 0, 1000, 2000, 3000);
+ powerStatsService.addStateResidencyResult(42, 1, 4000, 5000, 6000);
+
+ mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
+ 100, /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0,
+ 1_000_000, 1_000_000, 1_000_000);
+ awaitCompletion();
+
+ mockUpdateCpuStats(200, 5_000_010, 5_000_010);
+ powerStatsService.reset();
+ powerStatsService.addStateResidencyResult(42, 0, 1111, 2222, 3333);
+ powerStatsService.addStateResidencyResult(42, 1, 4444, 5555, 6666);
+
+ // Battery level is unchanged, so we don't write battery level details in history
+ mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
+ 100, /* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0,
+ 5_500_000, 5_500_000, 5_000_000);
+ awaitCompletion();
+
+ // Not a battery state change event, so details are not written
+ mBatteryStats.noteAlarmStartLocked("wakeup", null, APP_UID, 6_000_000, 6_000_000);
+
+ mockUpdateCpuStats(300, 6_000_010, 6_000_010);
+ powerStatsService.reset();
+
+ // Battery level drops, so we write the accumulated battery level details
+ mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
+ 100, /* plugType */ 0, 70, 72, 3700, 2_000_000, 4_000_000, 0,
+ 6_000_000, 6_000_000, 6_000_000);
+ awaitCompletion();
+
+ final BatteryStatsHistoryIterator iterator =
+ mBatteryStats.iterateBatteryStatsHistory(0, MonotonicClock.UNDEFINED);
+
+ BatteryStats.HistoryItem item;
+ assertThat(item = iterator.next()).isNotNull();
+ assertThat(item.cmd).isEqualTo((int) BatteryStats.HistoryItem.CMD_RESET);
+ assertThat(item.stepDetails).isNull();
+
+ assertThat(item = iterator.next()).isNotNull();
+ assertThat(item.batteryLevel).isEqualTo(90);
+ assertThat(item.stepDetails.userTime).isEqualTo(100);
+ assertThat(item.stepDetails.statSubsystemPowerState).contains("subsystem_0 name=foo "
+ + "state_0 name=off time=1000 count=2000 last entry=3000 "
+ + "state_1 name=on time=4000 count=5000 last entry=6000");
+
+ assertThat(item = iterator.next()).isNotNull();
+ assertThat(item.batteryLevel).isEqualTo(80);
+ assertThat(item.stepDetails.userTime).isEqualTo(200);
+ assertThat(item.stepDetails.statSubsystemPowerState).contains("subsystem_0 name=foo "
+ + "state_0 name=off time=1111 count=2222 last entry=3333 "
+ + "state_1 name=on time=4444 count=5555 last entry=6666");
+
+ assertThat(item = iterator.next()).isNotNull();
+ assertThat(item.batteryLevel).isEqualTo(80);
+ assertThat(item.stepDetails).isNull();
+
+ assertThat(item = iterator.next()).isNotNull();
+ assertThat(item.batteryLevel).isEqualTo(70);
+ assertThat(item.stepDetails.userTime).isEqualTo(300);
+ assertThat(item.stepDetails.statSubsystemPowerState).isNull();
+
+ assertThat(iterator.next()).isNull();
+ }
+
+ private void mockUpdateCpuStats(int totalUTimeMs, long elapsedRealtime, long uptime) {
+ BatteryStatsImpl.BatteryCallback callback = mock(BatteryStatsImpl.BatteryCallback.class);
+ doAnswer(inv -> {
+ mMockClock.realtime = elapsedRealtime;
+ mMockClock.uptime = uptime;
+ synchronized (mBatteryStats) {
+ mBatteryStats.addCpuStatsLocked(totalUTimeMs, 0, 0, 0, 0, 0, 0, 0);
+ mBatteryStats.finishAddingCpuStatsLocked();
+ }
+ return null;
+ }).when(callback).batteryNeedsCpuUpdate();
+ mBatteryStats.setCallback(callback);
+ }
+
+ private void awaitCompletion() {
+ ConditionVariable done = new ConditionVariable();
+ mHandler.post(done::open);
+ done.block();
+ }
+}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java
index 503e233..1b82ffd 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java
@@ -47,14 +47,12 @@
private final MockClock mMockClock = new MockClock();
private MockBatteryStatsImpl mBatteryStats;
private final Random mRandom = new Random();
- private final MockExternalStatsSync mExternalStatsSync = new MockExternalStatsSync();
@Before
public void setup() {
final File historyDir = createTemporaryDirectory(getClass().getSimpleName());
mMockClock.currentTime = 3000;
mBatteryStats = new MockBatteryStatsImpl(mMockClock, historyDir);
- mBatteryStats.setDummyExternalStatsSync(mExternalStatsSync);
mBatteryStats.setRecordAllHistoryLocked(true);
mBatteryStats.forceRecordAllHistory();
mBatteryStats.setNoAutoReset(true);
@@ -227,72 +225,53 @@
100, /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0,
1_000_000, 1_000_000, 1_000_000);
- mExternalStatsSync.updateCpuStats(100, 1_100_000, 1_100_000);
-
// Device was suspended for 3_000 seconds, note the difference in elapsed time and uptime
mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
100, /* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0,
5_000_000, 2_000_000, 5_000_000);
- mExternalStatsSync.updateCpuStats(200, 5_100_000, 2_100_000);
-
// Battery level is unchanged, so we don't write battery level details in history
- mBatteryStats.noteAlarmStartLocked("wakeup", null, APP_UID, 6_000_000, 3_000_000);
+ mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
+ 100, /* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0,
+ 5_500_000, 2_500_000, 5_000_000);
- assertThat(mExternalStatsSync.isSyncScheduled()).isFalse();
+ // Not a battery state change event, so details are not written
+ mBatteryStats.noteAlarmStartLocked("wakeup", null, APP_UID, 6_000_000, 3_000_000);
// Battery level drops, so we write the accumulated battery level details
mBatteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING,
- 100, /* plugType */ 0, 79, 72, 3700, 2_000_000, 4_000_000, 0,
+ 100, /* plugType */ 0, 70, 72, 3700, 2_000_000, 4_000_000, 0,
7_000_000, 4_000_000, 6_000_000);
- mExternalStatsSync.updateCpuStats(300, 7_100_000, 4_100_000);
-
final BatteryStatsHistoryIterator iterator =
mBatteryStats.iterateBatteryStatsHistory(0, MonotonicClock.UNDEFINED);
BatteryStats.HistoryItem item;
assertThat(item = iterator.next()).isNotNull();
assertThat(item.cmd).isEqualTo((int) BatteryStats.HistoryItem.CMD_RESET);
- assertThat(item.stepDetails).isNull();
assertThat(item = iterator.next()).isNotNull();
assertThat(item.batteryLevel).isEqualTo(90);
- assertThat(item.stepDetails).isNull();
-
- assertThat(item = iterator.next()).isNotNull();
- assertThat(item.batteryLevel).isEqualTo(90);
- assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS);
+ assertThat(item.states & BatteryStats.HistoryItem.STATE_CPU_RUNNING_FLAG).isNotEqualTo(0);
assertThat(item = iterator.next()).isNotNull();
assertThat(item.batteryLevel).isEqualTo(90);
assertThat(item.states & BatteryStats.HistoryItem.STATE_CPU_RUNNING_FLAG).isEqualTo(0);
- assertThat(item.stepDetails.userTime).isEqualTo(100);
assertThat(item = iterator.next()).isNotNull();
assertThat(item.batteryLevel).isEqualTo(80);
assertThat(item.states & BatteryStats.HistoryItem.STATE_CPU_RUNNING_FLAG).isNotEqualTo(0);
- assertThat(item.stepDetails.userTime).isEqualTo(0);
-
- assertThat(item = iterator.next()).isNotNull();
- assertThat(item.batteryLevel).isEqualTo(80);
- assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS);
assertThat(item = iterator.next()).isNotNull();
assertThat(item.batteryLevel).isEqualTo(80);
assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_ALARM_START);
- assertThat(item.stepDetails).isNull();
-
- assertThat(item = iterator.next()).isNotNull();
- assertThat(item.batteryLevel).isEqualTo(79);
assertThat(item.states & BatteryStats.HistoryItem.STATE_CPU_RUNNING_FLAG).isNotEqualTo(0);
- assertThat(item.stepDetails.userTime).isEqualTo(200);
assertThat(item = iterator.next()).isNotNull();
- assertThat(item.batteryLevel).isEqualTo(79);
- assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS);
+ assertThat(item.batteryLevel).isEqualTo(70);
+ assertThat(item.states & BatteryStats.HistoryItem.STATE_CPU_RUNNING_FLAG).isNotEqualTo(0);
- assertThat(item = iterator.next()).isNull();
+ assertThat(iterator.next()).isNull();
}
@Test
@@ -394,26 +373,4 @@
assertThat(item.time).isEqualTo(elapsedTimeMs);
}
-
- private class MockExternalStatsSync extends MockBatteryStatsImpl.DummyExternalStatsSync {
- private boolean mSyncScheduled;
-
- @Override
- public void scheduleCpuSyncDueToWakelockChange(long delayMillis) {
- mSyncScheduled = true;
- }
-
- public boolean isSyncScheduled() {
- return mSyncScheduled;
- }
-
- public void updateCpuStats(int totalUTimeMs, long elapsedRealtime, long uptime) {
- assertThat(mExternalStatsSync.mSyncScheduled).isTrue();
- mBatteryStats.recordHistoryEventLocked(elapsedRealtime, uptime,
- BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS, "wakelock-update", 0);
- mBatteryStats.addCpuStatsLocked(totalUTimeMs, 0, 0, 0, 0, 0, 0, 0);
- mBatteryStats.finishAddingCpuStatsLocked();
- mExternalStatsSync.mSyncScheduled = false;
- }
- }
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
index 3ed4a52..7acb93c0 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
@@ -26,7 +26,6 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
import android.os.BatteryConsumer;
import android.os.BatteryManager;
@@ -58,7 +57,8 @@
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import java.io.File;
import java.io.IOException;
@@ -85,6 +85,8 @@
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
private final Parcel mHistoryBuffer = Parcel.obtain();
private File mSystemDir;
@@ -97,14 +99,11 @@
@Mock
private BatteryStatsHistory.TraceDelegate mTracer;
@Mock
- private BatteryStatsHistory.HistoryStepDetailsCalculator mStepDetailsCalculator;
- @Mock
private BatteryStatsHistory.EventLogger mEventLogger;
private List<String> mReadFiles = new ArrayList<>();
@Before
public void setUp() throws IOException {
- MockitoAnnotations.initMocks(this);
mSystemDir = Files.createTempDirectory("BatteryStatsHistoryTest").toFile();
mHistoryDir = new File(mSystemDir, "battery-history");
String[] files = mHistoryDir.list();
@@ -138,14 +137,10 @@
mClock.currentTime = 1743645660000L; // 2025-04-03, 2:01:00 AM
mHistory = new BatteryStatsHistory(mHistoryBuffer, MAX_HISTORY_BUFFER_SIZE, mDirectory,
- mStepDetailsCalculator, mClock, mMonotonicClock, mTracer,
+ mClock, mMonotonicClock, mTracer,
mEventLogger);
mHistory.forceRecordAllHistory();
mHistory.startRecordingHistory(mClock.realtime, mClock.uptime, false);
-
- when(mStepDetailsCalculator.getHistoryStepDetails())
- .thenReturn(new BatteryStats.HistoryStepDetails());
-
mHistoryPrinter = new BatteryStats.HistoryPrinter(TimeZone.getTimeZone("GMT"));
}
@@ -288,7 +283,7 @@
// create a new BatteryStatsHistory object, it will pick up existing history files.
BatteryStatsHistory history2 = new BatteryStatsHistory(mHistoryBuffer, 1024, mDirectory,
- null, mClock, mMonotonicClock, mTracer, mEventLogger);
+ mClock, mMonotonicClock, mTracer, mEventLogger);
// verify constructor can pick up all files from file system.
verifyFileNames(history2, fileList);
verifyActiveFile(history2, "33000.bh");
@@ -595,7 +590,7 @@
// Keep the preserved part of history short - we only need to capture the very tail of
// history.
mHistory = new BatteryStatsHistory(mHistoryBuffer, 6000, mDirectory,
- mStepDetailsCalculator, mClock, mMonotonicClock, mTracer, mEventLogger);
+ mClock, mMonotonicClock, mTracer, mEventLogger);
mHistory.forceRecordAllHistory();
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
index 8a1d37b5..90b3e13 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
@@ -575,7 +575,7 @@
accumulateBatteryUsageStats(batteryStats, 10000000, 0);
// Accumulate every 200 bytes of battery history
accumulateBatteryUsageStats(batteryStats, 200, 1);
- accumulateBatteryUsageStats(batteryStats, 50, 5);
+ accumulateBatteryUsageStats(batteryStats, 50, 4);
// Accumulate on every invocation of accumulateBatteryUsageStats
accumulateBatteryUsageStats(batteryStats, 0, 7);
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
index c7a19ce..8c3bd17 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
@@ -329,10 +329,6 @@
}
@Override
- public void scheduleSyncDueToBatteryLevelChange(long delayMillis) {
- }
-
- @Override
public void scheduleSyncDueToProcessStateChange(int flags, long delayMillis) {
}
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MockPowerStatsInternal.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MockPowerStatsInternal.java
new file mode 100644
index 0000000..dc5da8c
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MockPowerStatsInternal.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.power.stats;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.hardware.power.stats.Channel;
+import android.hardware.power.stats.EnergyConsumer;
+import android.hardware.power.stats.EnergyConsumerResult;
+import android.hardware.power.stats.EnergyConsumerType;
+import android.hardware.power.stats.EnergyMeasurement;
+import android.hardware.power.stats.PowerEntity;
+import android.hardware.power.stats.State;
+import android.hardware.power.stats.StateResidency;
+import android.hardware.power.stats.StateResidencyResult;
+import android.power.PowerStatsInternal;
+import android.util.SparseArray;
+
+import java.util.Arrays;
+import java.util.concurrent.CompletableFuture;
+
+class MockPowerStatsInternal extends PowerStatsInternal {
+ private final SparseArray<PowerEntity> mPowerEntities = new SparseArray<>();
+ private final SparseArray<StateResidencyResult> mStateResidencyResults = new SparseArray<>();
+ private final SparseArray<EnergyConsumer> mEnergyConsumers = new SparseArray<>();
+ private final SparseArray<EnergyConsumerResult> mEnergyConsumerResults = new SparseArray<>();
+ private final int mTimeSinceBoot = 0;
+
+ @Override
+ public EnergyConsumer[] getEnergyConsumerInfo() {
+ final int size = mEnergyConsumers.size();
+ final EnergyConsumer[] consumers = new EnergyConsumer[size];
+ for (int i = 0; i < size; i++) {
+ consumers[i] = mEnergyConsumers.valueAt(i);
+ }
+ return consumers;
+ }
+
+ @Override
+ public CompletableFuture<EnergyConsumerResult[]> getEnergyConsumedAsync(
+ int[] energyConsumerIds) {
+ final CompletableFuture<EnergyConsumerResult[]> future = new CompletableFuture();
+ final EnergyConsumerResult[] results;
+ final int length = energyConsumerIds.length;
+ if (length == 0) {
+ final int size = mEnergyConsumerResults.size();
+ results = new EnergyConsumerResult[size];
+ for (int i = 0; i < size; i++) {
+ results[i] = mEnergyConsumerResults.valueAt(i);
+ }
+ } else {
+ results = new EnergyConsumerResult[length];
+ for (int i = 0; i < length; i++) {
+ results[i] = mEnergyConsumerResults.get(energyConsumerIds[i]);
+ }
+ }
+ future.complete(results);
+ return future;
+ }
+
+ @Override
+ public PowerEntity[] getPowerEntityInfo() {
+ final int size = mPowerEntities.size();
+ final PowerEntity[] entities = new PowerEntity[size];
+ for (int i = 0; i < size; i++) {
+ entities[i] = mPowerEntities.valueAt(i);
+ }
+ return entities;
+ }
+
+ @Override
+ public CompletableFuture<StateResidencyResult[]> getStateResidencyAsync(
+ int[] powerEntityIds) {
+ final CompletableFuture<StateResidencyResult[]> future = new CompletableFuture<>();
+ final StateResidencyResult[] results;
+ final int length = powerEntityIds.length;
+ if (length == 0) {
+ final int size = mStateResidencyResults.size();
+ results = new StateResidencyResult[size];
+ for (int i = 0; i < size; i++) {
+ results[i] = mStateResidencyResults.valueAt(i);
+ }
+ } else {
+ results = new StateResidencyResult[length];
+ for (int i = 0; i < length; i++) {
+ results[i] = mStateResidencyResults.get(powerEntityIds[i]);
+ }
+ }
+ future.complete(results);
+ return future;
+ }
+
+ @Override
+ public Channel[] getEnergyMeterInfo() {
+ return new Channel[0];
+ }
+
+ @Override
+ public CompletableFuture<EnergyMeasurement[]> readEnergyMeterAsync(
+ int[] channelIds) {
+ return new CompletableFuture<>();
+ }
+
+ public void reset() {
+ mStateResidencyResults.clear();
+ mEnergyConsumerResults.clear();
+ }
+
+ public void addPowerEntity(int id, String name) {
+ PowerEntity powerEntity = new PowerEntity();
+ powerEntity.id = id;
+ powerEntity.name = name;
+ powerEntity.states = new State[0];
+ mPowerEntities.put(id, powerEntity);
+ }
+
+ public void addPowerEntityState(int powerEntityId, int stateId, String name) {
+ State state = new State();
+ state.id = stateId;
+ state.name = name;
+
+ PowerEntity powerEntity = mPowerEntities.get(powerEntityId);
+ powerEntity.states = Arrays.copyOf(powerEntity.states, powerEntity.states.length + 1);
+ powerEntity.states[powerEntity.states.length - 1] = state;
+ }
+
+ public void addStateResidencyResult(int entityId, int stateId, long totalTimeInStateMs,
+ long totalStateEntryCount, long lastEntryTimestampMs) {
+ StateResidencyResult result = mStateResidencyResults.get(entityId);
+ if (result == null) {
+ result = new StateResidencyResult();
+ result.id = entityId;
+ result.stateResidencyData = new StateResidency[0];
+ mStateResidencyResults.put(entityId, result);
+ }
+
+ StateResidency residency = new StateResidency();
+ residency.id = stateId;
+ residency.totalTimeInStateMs = totalTimeInStateMs;
+ residency.totalStateEntryCount = totalStateEntryCount;
+ residency.lastEntryTimestampMs = lastEntryTimestampMs;
+
+ result.stateResidencyData = Arrays.copyOf(result.stateResidencyData,
+ result.stateResidencyData.length + 1);
+ result.stateResidencyData[result.stateResidencyData.length - 1] = residency;
+ }
+
+ /**
+ * Util method to add a new EnergyConsumer for testing
+ *
+ * @return the EnergyConsumer id of the new EnergyConsumer
+ */
+ public int addEnergyConsumer(@EnergyConsumerType byte type, int ordinal, String name) {
+ final EnergyConsumer consumer = new EnergyConsumer();
+ final int id = getNextAvailableId();
+ consumer.id = id;
+ consumer.type = type;
+ consumer.ordinal = ordinal;
+ consumer.name = name;
+ mEnergyConsumers.put(id, consumer);
+
+ final EnergyConsumerResult result = new EnergyConsumerResult();
+ result.id = id;
+ result.timestampMs = mTimeSinceBoot;
+ result.energyUWs = 0;
+ mEnergyConsumerResults.put(id, result);
+ return id;
+ }
+
+ public void incrementEnergyConsumption(int id, long energyUWs) {
+ EnergyConsumerResult result = mEnergyConsumerResults.get(id, null);
+ assertNotNull(result);
+ result.energyUWs += energyUWs;
+ }
+
+ private int getNextAvailableId() {
+ final int size = mEnergyConsumers.size();
+ // Just return the first index that does not match the key (aka the EnergyConsumer id)
+ for (int i = size - 1; i >= 0; i--) {
+ if (mEnergyConsumers.keyAt(i) == i) return i + 1;
+ }
+ // Otherwise return the lowest id
+ return 0;
+ }
+}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsAggregatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsAggregatorTest.java
index 73d491c..7aa59bd 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsAggregatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsAggregatorTest.java
@@ -59,9 +59,8 @@
@Before
public void setup() throws ParseException {
- mHistory = new BatteryStatsHistory(null, 1024, null,
- mock(BatteryStatsHistory.HistoryStepDetailsCalculator.class), mClock,
- mMonotonicClock, mock(BatteryStatsHistory.TraceDelegate.class), null);
+ mHistory = new BatteryStatsHistory(null, 1024, null, mClock, mMonotonicClock,
+ mock(BatteryStatsHistory.TraceDelegate.class), null);
AggregatedPowerStatsConfig config = new AggregatedPowerStatsConfig();
config.trackPowerComponent(TEST_POWER_COMPONENT)
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java
index a5a29f5..b33cb7e 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java
@@ -114,8 +114,7 @@
mPowerStatsStore = new PowerStatsStore(storeDirectory, new TestHandler());
mDirectory = new BatteryHistoryDirectory(storeDirectory, 0);
- mHistory = new BatteryStatsHistory(Parcel.obtain(), 10000, mDirectory,
- mock(BatteryStatsHistory.HistoryStepDetailsCalculator.class), mClock,
+ mHistory = new BatteryStatsHistory(Parcel.obtain(), 10000, mDirectory, mClock,
mMonotonicClock, null, null);
mPowerStatsAggregator = new PowerStatsAggregator(config);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/WakelockPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/WakelockPowerStatsProcessorTest.java
index 5ac7216..b90019f 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/WakelockPowerStatsProcessorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/WakelockPowerStatsProcessorTest.java
@@ -29,8 +29,6 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.mock;
-
import android.annotation.SuppressLint;
import android.os.BatteryConsumer;
import android.os.PersistableBundle;
@@ -89,7 +87,6 @@
long[] uidStats = new long[descriptor.uidStatsArrayLength];
BatteryStatsHistory history = new BatteryStatsHistory(null, 10000, null,
- mock(BatteryStatsHistory.HistoryStepDetailsCalculator.class),
mStatsRule.getMockClock(),
new MonotonicClock(START_TIME, mStatsRule.getMockClock()), null, null);
history.forceRecordAllHistory();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java
index 33529c3..44870eb 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/HearingDevicePhoneCallNotificationControllerTest.java
@@ -37,7 +37,6 @@
import android.media.AudioDeviceInfo;
import android.media.AudioDevicePort;
import android.media.AudioManager;
-import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
@@ -164,7 +163,6 @@
}
@Test
- @EnableFlags(Flags.FLAG_HEARING_INPUT_CHANGE_WHEN_COMM_DEVICE)
public void onCallStateChanged_nonHearingDevice_offHookThenIdle_callAddAndRemoveListener() {
final ArgumentCaptor<AudioManager.OnCommunicationDeviceChangedListener> listenerCaptor =
ArgumentCaptor.forClass(AudioManager.OnCommunicationDeviceChangedListener.class);
@@ -185,7 +183,6 @@
@Test
- @EnableFlags(Flags.FLAG_HEARING_INPUT_CHANGE_WHEN_COMM_DEVICE)
public void onCallStateChanged_hearingDeviceFromCommunicationDeviceChanged_showNotification() {
final ArgumentCaptor<AudioManager.OnCommunicationDeviceChangedListener> listenerCaptor =
ArgumentCaptor.forClass(AudioManager.OnCommunicationDeviceChangedListener.class);
@@ -209,7 +206,6 @@
}
@Test
- @EnableFlags(Flags.FLAG_HEARING_INPUT_CHANGE_WHEN_COMM_DEVICE)
public void onCallStateChanged_offHookMultiple_addListenerOnlyOneTime() {
AudioDeviceInfo a2dpDeviceInfo = createAudioDeviceInfo(TEST_ADDRESS,
AudioManager.DEVICE_OUT_BLUETOOTH_A2DP);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownOrSwipeTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownOrSwipeTest.java
index d94faec..49eb63b 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownOrSwipeTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownOrSwipeTest.java
@@ -28,10 +28,6 @@
import android.content.Context;
import android.graphics.PointF;
-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;
import android.view.Display;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -54,9 +50,6 @@
*/
public class TwoFingersDownOrSwipeTest {
- @Rule
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
private static final float DEFAULT_X = 100f;
private static final float DEFAULT_Y = 100f;
@@ -94,22 +87,6 @@
}
@Test
- @RequiresFlagsDisabled(android.view.accessibility.Flags.FLAG_COPY_EVENTS_FOR_GESTURE_DETECTION)
- public void sendTwoFingerDownEvent_onGestureCompleted_withoutCopiedEvents() {
- final List<MotionEvent> downEvents = twoPointersDownEvents(Display.DEFAULT_DISPLAY,
- new PointF(DEFAULT_X, DEFAULT_Y), new PointF(DEFAULT_X + 10, DEFAULT_Y + 10));
-
- for (MotionEvent event : downEvents) {
- mGesturesObserver.onMotionEvent(event, event, 0);
- }
-
- verify(mListener, timeout(sTimeoutMillis)).onGestureCompleted(
- MagnificationGestureMatcher.GESTURE_TWO_FINGERS_DOWN_OR_SWIPE, downEvents.get(1),
- downEvents.get(1), 0);
- }
-
- @Test
- @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_COPY_EVENTS_FOR_GESTURE_DETECTION)
public void sendTwoFingerDownEvent_onGestureCompleted() {
final List<MotionEvent> downEvents = twoPointersDownEvents(Display.DEFAULT_DISPLAY,
new PointF(DEFAULT_X, DEFAULT_Y), new PointF(DEFAULT_X + 10, DEFAULT_Y + 10));
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index c50c623..a1f7317 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -816,14 +816,14 @@
MockUtils.checkIntentAction(
DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED),
MockUtils.checkUserHandle(CALLER_USER_HANDLE),
- isNull(String.class),
+ isNull(),
eq(AppOpsManager.OP_NONE),
any(Bundle.class),
any(BroadcastReceiver.class),
eq(dpms.mHandler),
eq(Activity.RESULT_OK),
- isNull(String.class),
- isNull(Bundle.class));
+ isNull(),
+ isNull());
assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse();
verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
@@ -873,14 +873,14 @@
MockUtils.checkIntentAction(
DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED),
MockUtils.checkUserHandle(CALLER_USER_HANDLE),
- isNull(String.class),
+ isNull(),
eq(AppOpsManager.OP_NONE),
any(Bundle.class),
any(BroadcastReceiver.class),
eq(dpms.mHandler),
eq(Activity.RESULT_OK),
- isNull(String.class),
- isNull(Bundle.class));
+ isNull(),
+ isNull());
assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse();
verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
diff --git a/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java b/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java
index 87cd156..992c118 100644
--- a/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java
@@ -20,6 +20,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
@@ -62,6 +63,7 @@
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.ScheduledExecutorService;
@RunWith(AndroidJUnit4.class)
@Presubmit
@@ -97,6 +99,7 @@
private HubInfoRegistry mHubInfoRegistry;
private ContextHubTransactionManager mTransactionManager;
private Context mContext;
+ @Mock private ScheduledExecutorService mMockTimeoutExecutorService;
@Mock private IEndpointCommunication mMockEndpointCommunications;
@Mock private IContextHubWrapper mMockContextHubWrapper;
@Mock private IContextHubEndpointCallback mMockCallback;
@@ -120,7 +123,11 @@
mMockContextHubWrapper, mClientManager, new NanoAppStateManager());
mEndpointManager =
new ContextHubEndpointManager(
- mContext, mMockContextHubWrapper, mHubInfoRegistry, mTransactionManager);
+ mContext,
+ mMockContextHubWrapper,
+ mHubInfoRegistry,
+ mTransactionManager,
+ mMockTimeoutExecutorService);
mEndpointManager.init();
}
@@ -248,14 +255,20 @@
endpoint.getAssignedHubEndpointInfo().getIdentifier(),
targetInfo.getIdentifier(),
ENDPOINT_SERVICE_DESCRIPTOR);
-
verify(mMockCallback)
.onSessionOpenRequest(
SESSION_ID_FOR_OPEN_REQUEST, targetInfo, ENDPOINT_SERVICE_DESCRIPTOR);
// Accept
endpoint.openSessionRequestComplete(SESSION_ID_FOR_OPEN_REQUEST);
- verify(mMockEndpointCommunications)
+
+ // Even when timeout happens, there should be no effect on this session
+ ArgumentCaptor<Runnable> runnableArgumentCaptor = ArgumentCaptor.forClass(Runnable.class);
+ verify(mMockTimeoutExecutorService)
+ .schedule(runnableArgumentCaptor.capture(), anyLong(), any());
+ runnableArgumentCaptor.getValue().run();
+
+ verify(mMockEndpointCommunications, times(1))
.endpointSessionOpenComplete(SESSION_ID_FOR_OPEN_REQUEST);
unregisterExampleEndpoint(endpoint);
@@ -331,6 +344,87 @@
}
@Test
+ public void testEndpointSessionOpenRequest_rejectAfterTimeout() throws RemoteException {
+ assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE);
+ IContextHubEndpoint endpoint = registerExampleEndpoint();
+
+ HubEndpointInfo targetInfo =
+ new HubEndpointInfo(
+ TARGET_ENDPOINT_NAME,
+ TARGET_ENDPOINT_ID,
+ ENDPOINT_PACKAGE_NAME,
+ Collections.emptyList());
+ mHubInfoRegistry.onEndpointStarted(new HubEndpointInfo[] {targetInfo});
+ mEndpointManager.onEndpointSessionOpenRequest(
+ SESSION_ID_FOR_OPEN_REQUEST,
+ endpoint.getAssignedHubEndpointInfo().getIdentifier(),
+ targetInfo.getIdentifier(),
+ ENDPOINT_SERVICE_DESCRIPTOR);
+
+ // Immediately timeout
+ ArgumentCaptor<Runnable> runnableArgumentCaptor = ArgumentCaptor.forClass(Runnable.class);
+ verify(mMockTimeoutExecutorService)
+ .schedule(runnableArgumentCaptor.capture(), anyLong(), any());
+ runnableArgumentCaptor.getValue().run();
+
+ // Client's callback shouldn't matter after timeout
+ try {
+ endpoint.openSessionRequestComplete(SESSION_ID_FOR_OPEN_REQUEST);
+ } catch (IllegalArgumentException ignore) {
+ // This will throw because the session is no longer valid
+ }
+
+ // HAL will receive closeEndpointSession with Timeout as reason
+ verify(mMockEndpointCommunications, times(1))
+ .closeEndpointSession(SESSION_ID_FOR_OPEN_REQUEST, Reason.TIMEOUT);
+ // HAL will not receives open complete notifications
+ verify(mMockEndpointCommunications, never())
+ .endpointSessionOpenComplete(SESSION_ID_FOR_OPEN_REQUEST);
+
+ unregisterExampleEndpoint(endpoint);
+ }
+
+ @Test
+ public void testEndpointSessionOpenRequest_duplicatedSessionId_noopWithinTimeout()
+ throws RemoteException {
+ assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE);
+ IContextHubEndpoint endpoint = registerExampleEndpoint();
+
+ HubEndpointInfo targetInfo =
+ new HubEndpointInfo(
+ TARGET_ENDPOINT_NAME,
+ TARGET_ENDPOINT_ID,
+ ENDPOINT_PACKAGE_NAME,
+ Collections.emptyList());
+ mHubInfoRegistry.onEndpointStarted(new HubEndpointInfo[] {targetInfo});
+ mEndpointManager.onEndpointSessionOpenRequest(
+ SESSION_ID_FOR_OPEN_REQUEST,
+ endpoint.getAssignedHubEndpointInfo().getIdentifier(),
+ targetInfo.getIdentifier(),
+ ENDPOINT_SERVICE_DESCRIPTOR);
+
+ // Duplicated session open request
+ mEndpointManager.onEndpointSessionOpenRequest(
+ SESSION_ID_FOR_OPEN_REQUEST,
+ endpoint.getAssignedHubEndpointInfo().getIdentifier(),
+ targetInfo.getIdentifier(),
+ ENDPOINT_SERVICE_DESCRIPTOR);
+
+ // Finally, endpoint approved the session open request
+ endpoint.openSessionRequestComplete(SESSION_ID_FOR_OPEN_REQUEST);
+
+ // Client API is only invoked once
+ verify(mMockCallback, times(1))
+ .onSessionOpenRequest(
+ SESSION_ID_FOR_OPEN_REQUEST, targetInfo, ENDPOINT_SERVICE_DESCRIPTOR);
+ // HAL still receives two open complete notifications
+ verify(mMockEndpointCommunications, times(1))
+ .endpointSessionOpenComplete(SESSION_ID_FOR_OPEN_REQUEST);
+
+ unregisterExampleEndpoint(endpoint);
+ }
+
+ @Test
public void testMessageTransaction() throws RemoteException {
IContextHubEndpoint endpoint = registerExampleEndpoint();
testMessageTransactionInternal(endpoint, /* deliverMessageStatus= */ true);
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
index 88395a4..071bd73 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
@@ -306,9 +306,9 @@
// This method is always called, even with PI == null.
if (resultIntent == null) {
- verify(mServiceContext, times(1)).sendIntentSender(isNull(IntentSender.class));
+ verify(mServiceContext, times(1)).sendIntentSender(isNull());
} else {
- verify(mServiceContext, times(1)).sendIntentSender(notNull(IntentSender.class));
+ verify(mServiceContext, times(1)).sendIntentSender(notNull());
}
runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
@@ -619,7 +619,7 @@
makeResultIntent()));
// The intent should be sent right away.
- verify(mServiceContext, times(1)).sendIntentSender(notNull(IntentSender.class));
+ verify(mServiceContext, times(1)).sendIntentSender(notNull());
});
// Already pinned.
@@ -661,7 +661,7 @@
assertTrue(request.accept());
// The intent is only sent once, so times(1).
- verify(mServiceContext, times(1)).sendIntentSender(isNull(IntentSender.class));
+ verify(mServiceContext, times(1)).sendIntentSender(isNull());
});
// Still pinned.
@@ -698,7 +698,7 @@
makeResultIntent()));
// The intent should be sent right away.
- verify(mServiceContext, times(1)).sendIntentSender(notNull(IntentSender.class));
+ verify(mServiceContext, times(1)).sendIntentSender(notNull());
});
// Already pinned.
@@ -742,7 +742,7 @@
assertTrue(request.accept());
// The intent is only sent once, so times(1).
- verify(mServiceContext, times(1)).sendIntentSender(isNull(IntentSender.class));
+ verify(mServiceContext, times(1)).sendIntentSender(isNull());
});
// Still pinned.
diff --git a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
index 952d8fa..09acfdd 100644
--- a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
@@ -51,6 +51,7 @@
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.Temperature;
+import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -78,6 +79,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server
@@ -117,7 +119,8 @@
*/
private class ThermalHalFake extends ThermalHalWrapper {
private static final int INIT_STATUS = Temperature.THROTTLING_NONE;
- private List<Temperature> mTemperatureList = new ArrayList<>();
+ private final List<Temperature> mTemperatureList = new ArrayList<>();
+ private AtomicInteger mGetCurrentTemperaturesCalled = new AtomicInteger();
private List<CoolingDevice> mCoolingDeviceList = new ArrayList<>();
private List<TemperatureThreshold> mTemperatureThresholdList = initializeThresholds();
@@ -173,6 +176,7 @@
mTemperatureList.add(mUsbPort);
mCoolingDeviceList.add(mCpu);
mCoolingDeviceList.add(mGpu);
+ mGetCurrentTemperaturesCalled.set(0);
}
void enableForecastSkinTemperature() {
@@ -188,14 +192,24 @@
mForecastSkinTemperaturesError = true;
}
+ void updateTemperatureList(Temperature... temperatures) {
+ synchronized (mTemperatureList) {
+ mTemperatureList.clear();
+ mTemperatureList.addAll(Arrays.asList(temperatures));
+ }
+ }
+
@Override
protected List<Temperature> getCurrentTemperatures(boolean shouldFilter, int type) {
List<Temperature> ret = new ArrayList<>();
- for (Temperature temperature : mTemperatureList) {
- if (shouldFilter && type != temperature.getType()) {
- continue;
+ synchronized (mTemperatureList) {
+ mGetCurrentTemperaturesCalled.incrementAndGet();
+ for (Temperature temperature : mTemperatureList) {
+ if (shouldFilter && type != temperature.getType()) {
+ continue;
+ }
+ ret.add(temperature);
}
- ret.add(temperature);
}
return ret;
}
@@ -407,7 +421,7 @@
Thread.sleep(CALLBACK_TIMEOUT_MILLI_SEC);
resetListenerMock();
int status = Temperature.THROTTLING_SEVERE;
- mFakeHal.mTemperatureList = new ArrayList<>();
+ mFakeHal.updateTemperatureList();
// Should not notify on non-skin type
Temperature newBattery = new Temperature(37, Temperature.TYPE_BATTERY, "batt", status);
@@ -537,6 +551,42 @@
}
@Test
+ @DisableFlags({Flags.FLAG_ALLOW_THERMAL_HAL_SKIN_FORECAST})
+ public void testGetThermalHeadroom_handlerUpdateTemperatures()
+ throws RemoteException, InterruptedException {
+ // test that handler will at least enqueue one message to periodically read temperatures
+ // even if there is sample seeded from HAL temperature callback
+ String temperatureName = "skin1";
+ Temperature temperature = new Temperature(100, Temperature.TYPE_SKIN, temperatureName,
+ Temperature.THROTTLING_NONE);
+ mFakeHal.mCallback.onTemperatureChanged(temperature);
+ float headroom = mService.mService.getThermalHeadroom(0);
+ // the callback temperature 100C (headroom > 1.0f) sample should have been appended by the
+ // immediately scheduled fake HAL current temperatures read (mSkin1, mSkin2), and because
+ // there are less samples for prediction, the latest temperature mSkin1 is used to calculate
+ // headroom (mSkin2 has no threshold), which is 0.6f (28C vs threshold 40C).
+ assertEquals(0.6f, headroom, 0.01f);
+ // one called by service onActivityManagerReady, one called by handler on headroom call
+ assertEquals(2, mFakeHal.mGetCurrentTemperaturesCalled.get());
+ // periodic read should update the samples history, so the headroom should increase 0.1f
+ // as current temperature goes up by 3C every 1100ms.
+ for (int i = 1; i < 5; i++) {
+ Temperature newTemperature = new Temperature(mFakeHal.mSkin1.getValue() + 3 * i,
+ Temperature.TYPE_SKIN,
+ temperatureName,
+ Temperature.THROTTLING_NONE);
+ mFakeHal.updateTemperatureList(newTemperature);
+ // wait for handler to update temperature
+ Thread.sleep(1100);
+ // assert that only one callback was scheduled to query HAL when making multiple
+ // headroom calls
+ assertEquals(2 + i, mFakeHal.mGetCurrentTemperaturesCalled.get());
+ headroom = mService.mService.getThermalHeadroom(0);
+ assertEquals(0.6f + 0.1f * i, headroom, 0.01f);
+ }
+ }
+
+ @Test
@EnableFlags({Flags.FLAG_ALLOW_THERMAL_HAL_SKIN_FORECAST})
public void testGetThermalHeadroom_halForecast() throws RemoteException {
mFakeHal.mForecastSkinTemperaturesCalled = 0;
diff --git a/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java b/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
index 339bac4..d6b3fec 100644
--- a/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
@@ -45,6 +45,8 @@
import org.junit.runners.JUnit4;
import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;
@SuppressLint("VisibleForTests")
@@ -66,17 +68,28 @@
mPermissionEnforcer.grant(Manifest.permission.QUERY_ADVANCED_PROTECTION_MODE);
mStore = new AdvancedProtectionService.AdvancedProtectionStore(mContext) {
+ private Map<String, Integer> mStoredValues = new HashMap<>();
private boolean mEnabled = false;
@Override
- boolean retrieve() {
+ boolean retrieveAdvancedProtectionModeEnabled() {
return mEnabled;
}
@Override
- void store(boolean enabled) {
+ void storeAdvancedProtectionModeEnabled(boolean enabled) {
this.mEnabled = enabled;
}
+
+ @Override
+ void storeInt(String key, int value) {
+ mStoredValues.put(key, value);
+ }
+
+ @Override
+ int retrieveInt(String key, int defaultValue) {
+ return mStoredValues.getOrDefault(key, defaultValue);
+ }
};
mLooper = new TestLooper();
@@ -316,6 +329,18 @@
}
@Test
+ public void testUsbDataProtection_withoutPermission() {
+ mPermissionEnforcer.revoke(Manifest.permission.QUERY_ADVANCED_PROTECTION_MODE);
+ assertThrows(SecurityException.class, () -> mService.isUsbDataProtectionEnabled());
+ }
+
+ @Test
+ public void testSetUsbDataProtection_withoutPermission() {
+ mPermissionEnforcer.revoke(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE);
+ assertThrows(SecurityException.class, () -> mService.setUsbDataProtectionEnabled(true));
+ }
+
+ @Test
public void testRegisterCallback_withoutPermission() {
mPermissionEnforcer.revoke(Manifest.permission.QUERY_ADVANCED_PROTECTION_MODE);
assertThrows(SecurityException.class, () -> mService.registerAdvancedProtectionCallback(
diff --git a/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java b/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java
index 4a97b46..291d0ec 100644
--- a/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java
@@ -85,7 +85,7 @@
mDownloads = new TemporaryFolder();
mDownloads.create();
mStorageStats = new ExternalStorageStats();
- when(mSsm.queryExternalStatsForUser(isNull(String.class), any(UserHandle.class)))
+ when(mSsm.queryExternalStatsForUser((String)isNull(), any(UserHandle.class)))
.thenReturn(mStorageStats);
when(mJobService.getSystemService(anyString())).thenReturn(mSsm);
}
diff --git a/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt b/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt
index fbf9065..c59f0a0 100644
--- a/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt
+++ b/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt
@@ -17,6 +17,7 @@
package com.android.server.supervision
import android.app.Activity
+import android.app.KeyguardManager
import android.app.admin.DevicePolicyManager
import android.app.admin.DevicePolicyManagerInternal
import android.app.supervision.flags.Flags
@@ -61,6 +62,9 @@
@get:Rule val mocks: MockitoRule = MockitoJUnit.rule()
@Mock private lateinit var mockDpmInternal: DevicePolicyManagerInternal
+
+ @Mock
+ private lateinit var mockKeyguardManager: KeyguardManager
@Mock private lateinit var mockPackageManager: PackageManager
@Mock private lateinit var mockUserManagerInternal: UserManagerInternal
@@ -71,7 +75,7 @@
@Before
fun setUp() {
context = InstrumentationRegistry.getInstrumentation().context
- context = SupervisionContextWrapper(context, mockPackageManager)
+ context = SupervisionContextWrapper(context, mockKeyguardManager, mockPackageManager)
LocalServices.removeServiceForTest(DevicePolicyManagerInternal::class.java)
LocalServices.addService(DevicePolicyManagerInternal::class.java, mockDpmInternal)
@@ -250,11 +254,41 @@
@Test
fun createConfirmSupervisionCredentialsIntent() {
+ service.mInternal.setSupervisionEnabledForUser(context.getUserId(), true)
+ whenever(mockUserManagerInternal.getSupervisingProfileId()).thenReturn(SUPERVISING_USER_ID)
+ whenever(mockKeyguardManager.isDeviceSecure(SUPERVISING_USER_ID)).thenReturn(true)
+
val intent = checkNotNull(service.createConfirmSupervisionCredentialsIntent())
assertThat(intent.action).isEqualTo(ACTION_CONFIRM_SUPERVISION_CREDENTIALS)
assertThat(intent.getPackage()).isEqualTo("com.android.settings")
}
+ @Test
+ fun createConfirmSupervisionCredentialsIntent_supervisionNotEnabled_returnsNull() {
+ service.mInternal.setSupervisionEnabledForUser(context.getUserId(), false)
+ whenever(mockUserManagerInternal.getSupervisingProfileId()).thenReturn(SUPERVISING_USER_ID)
+ whenever(mockKeyguardManager.isDeviceSecure(SUPERVISING_USER_ID)).thenReturn(true)
+
+ assertThat(service.createConfirmSupervisionCredentialsIntent()).isNull()
+ }
+
+ @Test
+ fun createConfirmSupervisionCredentialsIntent_noSupervisingUser_returnsNull() {
+ service.mInternal.setSupervisionEnabledForUser(context.getUserId(), true)
+ whenever(mockUserManagerInternal.getSupervisingProfileId()).thenReturn(UserHandle.USER_NULL)
+
+ assertThat(service.createConfirmSupervisionCredentialsIntent()).isNull()
+ }
+
+ @Test
+ fun createConfirmSupervisionCredentialsIntent_supervisingUserMissingSecureLock_returnsNull() {
+ service.mInternal.setSupervisionEnabledForUser(context.getUserId(), true)
+ whenever(mockUserManagerInternal.getSupervisingProfileId()).thenReturn(SUPERVISING_USER_ID)
+ whenever(mockKeyguardManager.isDeviceSecure(SUPERVISING_USER_ID)).thenReturn(false)
+
+ assertThat(service.createConfirmSupervisionCredentialsIntent()).isNull()
+ }
+
private val systemSupervisionPackage: String
get() = context.getResources().getString(R.string.config_systemSupervision)
@@ -279,6 +313,7 @@
private companion object {
const val USER_ID = 100
const val APP_UID = USER_ID * UserHandle.PER_USER_RANGE
+ const val SUPERVISING_USER_ID = 10
}
}
@@ -286,10 +321,19 @@
* A context wrapper that allows broadcast intents to immediately invoke the receivers without
* performing checks on the sending user.
*/
-private class SupervisionContextWrapper(val context: Context, val pkgManager: PackageManager) :
- ContextWrapper(context) {
+private class SupervisionContextWrapper(
+ val context: Context,
+ val keyguardManager: KeyguardManager,
+ val pkgManager: PackageManager,
+) : ContextWrapper(context) {
val interceptors = mutableListOf<Pair<BroadcastReceiver, IntentFilter>>()
+ override fun getSystemService(name: String): Any =
+ when (name) {
+ Context.KEYGUARD_SERVICE -> keyguardManager
+ else -> super.getSystemService(name)
+ }
+
override fun getPackageManager() = pkgManager
override fun registerReceiverForAllUsers(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 902171d..159b3fd 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -24,6 +24,7 @@
import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.SHOW_IMMEDIATELY;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.Flags.FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS;
+import static android.app.Flags.FLAG_NM_SUMMARIZATION;
import static android.app.Flags.FLAG_SORT_SECTION_BY_TIME;
import static android.app.Notification.EXTRA_ALLOW_DURING_SETUP;
import static android.app.Notification.EXTRA_PICTURE;
@@ -105,6 +106,7 @@
import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
import static android.service.notification.Adjustment.KEY_CONTEXTUAL_ACTIONS;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
+import static android.service.notification.Adjustment.KEY_SUMMARIZATION;
import static android.service.notification.Adjustment.KEY_TEXT_REPLIES;
import static android.service.notification.Adjustment.KEY_TYPE;
import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
@@ -18308,9 +18310,11 @@
// Post some notifications and classify in different bundles
final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size();
final int numNewsNotifications = 1;
+ List<String> postedNotificationKeys = new ArrayList();
for (int i = 0; i < numNotifications; i++) {
NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId);
mService.addNotification(r);
+ postedNotificationKeys.add(r.getKey());
Bundle signals = new Bundle();
final int adjustmentType = i + 1;
signals.putInt(Adjustment.KEY_TYPE, adjustmentType);
@@ -18330,7 +18334,8 @@
waitForIdle();
//Check that all notifications classified as TYPE_NEWS have been unbundled
- for (NotificationRecord record : mService.mNotificationList) {
+ for (String key : postedNotificationKeys) {
+ NotificationRecord record= mService.mNotificationsByKey.get(key);
// Check that the original channel was restored
// for notifications classified as TYPE_NEWS
if (record.getBundleType() == TYPE_NEWS) {
@@ -18355,7 +18360,8 @@
// Check that the bundle channel was restored
verify(mRankingHandler, times(numNewsNotifications)).requestSort();
- for (NotificationRecord record : mService.mNotificationList) {
+ for (String key : postedNotificationKeys) {
+ NotificationRecord record= mService.mNotificationsByKey.get(key);
assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS);
}
}
@@ -18425,6 +18431,36 @@
}
@Test
+ @EnableFlags({FLAG_NM_SUMMARIZATION})
+ public void testDisableBundleAdjustmentByPkg_unsummarizesNotifications() throws Exception {
+ NotificationManagerService.WorkerHandler handler = mock(
+ NotificationManagerService.WorkerHandler.class);
+ mService.setHandler(handler);
+ when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
+ when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
+ when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
+ when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
+
+ NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, mUserId);
+ mService.addNotification(r);
+ Bundle signals = new Bundle();
+ signals.putCharSequence(Adjustment.KEY_SUMMARIZATION, "hello");
+ Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals,
+ "", r.getUser().getIdentifier());
+ mBinderService.applyAdjustmentFromAssistant(null, adjustment);
+ waitForIdle();
+ r.applyAdjustments();
+ Mockito.clearInvocations(mRankingHandler);
+
+ // Disable summarization for package
+ mBinderService.setAdjustmentSupportedForPackage(KEY_SUMMARIZATION, mPkg, false);
+ verify(mRankingHandler).requestSort();
+ mService.handleRankingSort();
+
+ assertThat(mService.mNotificationsByKey.get(r.getKey()).getSummarization()).isNull();
+ }
+
+ @Test
@EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION,
FLAG_NOTIFICATION_FORCE_GROUPING,
FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION,
@@ -18627,6 +18663,36 @@
}
@Test
+ @EnableFlags({FLAG_NM_SUMMARIZATION})
+ public void testDisableBundleAdjustment_unsummarizesNotifications() throws Exception {
+ NotificationManagerService.WorkerHandler handler = mock(
+ NotificationManagerService.WorkerHandler.class);
+ mService.setHandler(handler);
+ when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
+ when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
+ when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
+ when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true);
+
+ NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, mUserId);
+ mService.addNotification(r);
+ Bundle signals = new Bundle();
+ signals.putCharSequence(Adjustment.KEY_SUMMARIZATION, "hello");
+ Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals,
+ "", r.getUser().getIdentifier());
+ mBinderService.applyAdjustmentFromAssistant(null, adjustment);
+ waitForIdle();
+ r.applyAdjustments();
+ Mockito.clearInvocations(mRankingHandler);
+
+ // Disable summarization for package
+ mBinderService.disallowAssistantAdjustment(KEY_SUMMARIZATION);
+ verify(mRankingHandler).requestSort();
+ mService.handleRankingSort();
+
+ assertThat(mService.mNotificationsByKey.get(r.getKey()).getSummarization()).isNull();
+ }
+
+ @Test
@EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
public void clearAll_fromUser_willSendDeleteIntentForCachedSummaries() throws Exception {
NotificationRecord n = generateNotificationRecord(
@@ -18657,4 +18723,37 @@
verify(mGroupHelper).onNotificationRemoved(eq(n), any(), eq(false));
}
+
+ @Test
+ public void onDisplayRemoveSystemDecorations_cancelToasts() throws RemoteException {
+ final String testPackage = "testPackageName";
+ final INotificationManager service = ((INotificationManager) mService.mService);
+ final IBinder firstExternal = new Binder();
+ final IBinder secondExternal = new Binder();
+ final IBinder firstBuiltin = new Binder();
+ service.enqueueTextToast(testPackage,
+ firstExternal, "First external", TOAST_DURATION,
+ /* isUiContext= */ true, /* displayId= */ 10, /* callback= */ null);
+ service.enqueueTextToast(testPackage,
+ secondExternal, "Second external", TOAST_DURATION,
+ /* isUiContext= */ true, /* displayId= */ 10, /* callback= */ null);
+ service.enqueueTextToast(testPackage,
+ firstBuiltin, "First built-in", TOAST_DURATION, /* isUiContext= */ true,
+ /* displayId= */ DEFAULT_DISPLAY, /* callback= */ null);
+
+ mInternalService.onDisplayRemoveSystemDecorations(10);
+
+ verify(mStatusBar).showToast(anyInt(), eq(testPackage), eq(firstExternal),
+ any(String.class), any(IBinder.class), anyInt(), any(), eq(10));
+ verify(mStatusBar).hideToast(eq(testPackage), eq(firstExternal));
+ // The second toast has not been shown but invokes hide() anyway as
+ // NotificationManagerService does not remembered if it invoked show().
+ verify(mStatusBar, never()).showToast(anyInt(), eq(testPackage), eq(secondExternal),
+ any(String.class), any(IBinder.class), anyInt(), any(), eq(10));
+ verify(mStatusBar).hideToast(eq(testPackage), eq(secondExternal));
+ // The toast on the default display is shown as other notifications are cancelled.
+ verify(mStatusBar).showToast(anyInt(), eq(testPackage), eq(firstBuiltin), any(String.class),
+ any(IBinder.class), anyInt(), any(), eq(DEFAULT_DISPLAY));
+ verify(mStatusBar, never()).hideToast(eq(testPackage), eq(firstBuiltin));
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
index 0495e96..5ab0036 100644
--- a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
@@ -491,6 +491,11 @@
@Test
public void testKeyGestureBack() {
+ mPhoneWindowManager.overrideDelegateBackGestureRemote(true);
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_BACK);
+ mPhoneWindowManager.assertBackEventInjected();
+
+ mPhoneWindowManager.overrideDelegateBackGestureRemote(false);
sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_BACK);
mPhoneWindowManager.assertBackEventInjected();
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
index f3d5e39..8d164e1 100644
--- a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
@@ -53,14 +53,16 @@
import android.content.Context;
import android.hardware.input.InputManager;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.service.dreams.DreamManagerInternal;
import android.testing.TestableContext;
-import android.view.contentprotection.flags.Flags;
+import android.view.KeyEvent;
import androidx.test.filters.SmallTest;
@@ -102,6 +104,8 @@
public final TestableContext mContext = spy(
new TestableContext(getInstrumentation().getContext()));
+ @Mock private IBinder mInputToken;
+
PhoneWindowManager mPhoneWindowManager;
@Mock
private ActivityTaskManagerInternal mAtmInternal;
@@ -125,6 +129,8 @@
@Mock
private LockPatternUtils mLockPatternUtils;
+ private static final int INTERCEPT_SYSTEM_KEY_NOT_CONSUMED_DELAY = 0;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -216,7 +222,7 @@
@Test
public void testCheckAddPermission_withoutAccessibilityOverlay_noAccessibilityAppOpLogged() {
- mSetFlagsRule.enableFlags(Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED);
+ mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED);
int[] outAppOp = new int[1];
assertEquals(ADD_OKAY, mPhoneWindowManager.checkAddPermission(TYPE_WALLPAPER,
/* isRoundedCornerOverlay= */ false, "test.pkg", outAppOp, DEFAULT_DISPLAY));
@@ -225,7 +231,7 @@
@Test
public void testCheckAddPermission_withAccessibilityOverlay() {
- mSetFlagsRule.enableFlags(Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED);
+ mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED);
int[] outAppOp = new int[1];
assertEquals(ADD_OKAY, mPhoneWindowManager.checkAddPermission(TYPE_ACCESSIBILITY_OVERLAY,
/* isRoundedCornerOverlay= */ false, "test.pkg", outAppOp, DEFAULT_DISPLAY));
@@ -234,7 +240,7 @@
@Test
public void testCheckAddPermission_withAccessibilityOverlay_flagDisabled() {
- mSetFlagsRule.disableFlags(Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED);
+ mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED);
int[] outAppOp = new int[1];
assertEquals(ADD_OKAY, mPhoneWindowManager.checkAddPermission(TYPE_ACCESSIBILITY_OVERLAY,
/* isRoundedCornerOverlay= */ false, "test.pkg", outAppOp, DEFAULT_DISPLAY));
@@ -401,6 +407,35 @@
verify(mDreamManagerInternal).requestDream();
}
+ @EnableFlags(com.android.hardware.input.Flags.FLAG_FIX_SEARCH_MODIFIER_FALLBACKS)
+ public void testInterceptKeyBeforeDispatching() {
+ // Handle sub-tasks of init().
+ doNothing().when(mPhoneWindowManager).updateSettings(any());
+ doNothing().when(mPhoneWindowManager).initializeHdmiState();
+ final DisplayPolicy displayPolicy = mock(DisplayPolicy.class);
+ mPhoneWindowManager.mDefaultDisplayPolicy = displayPolicy;
+ mPhoneWindowManager.mDefaultDisplayRotation = mock(DisplayRotation.class);
+ final PowerManager pm = mock(PowerManager.class);
+ doReturn(true).when(pm).isInteractive();
+ doReturn(pm).when(mContext).getSystemService(eq(Context.POWER_SERVICE));
+
+ mContext.getMainThreadHandler().runWithScissors(() -> mPhoneWindowManager.init(
+ new PhoneWindowManager.Injector(mContext,
+ mock(WindowManagerPolicy.WindowManagerFuncs.class))), 0);
+
+ // Case: KeyNotConsumed with meta key.
+ KeyEvent keyEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_A, 0, KeyEvent.META_META_ON);
+ long result = mPhoneWindowManager.interceptKeyBeforeDispatching(mInputToken, keyEvent, 0);
+ assertEquals(INTERCEPT_SYSTEM_KEY_NOT_CONSUMED_DELAY, result);
+
+ // Case: KeyNotConsumed without meta key.
+ KeyEvent keyEvent1 = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_ESCAPE, 0, 0);
+ long result1 = mPhoneWindowManager.interceptKeyBeforeDispatching(mInputToken, keyEvent1, 0);
+ assertEquals(INTERCEPT_SYSTEM_KEY_NOT_CONSUMED_DELAY, result1);
+ }
+
private void initPhoneWindowManager() {
mPhoneWindowManager.mDefaultDisplayPolicy = mDisplayPolicy;
mPhoneWindowManager.mDefaultDisplayRotation = mock(DisplayRotation.class);
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index 7b6d361..7059c41 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -202,6 +202,7 @@
private boolean mIsTalkBackEnabled;
private boolean mIsTalkBackShortcutGestureEnabled;
+ private boolean mDelegateBackGestureRemote;
private boolean mIsVoiceAccessEnabled;
private Intent mBrowserIntent;
@@ -580,6 +581,12 @@
setPhoneCallIsInProgress();
}
+ void overrideDelegateBackGestureRemote(boolean isDelegating) {
+ mDelegateBackGestureRemote = isDelegating;
+ doReturn(mDelegateBackGestureRemote).when(mActivityTaskManagerInternal)
+ .requestBackGesture();
+ }
+
void prepareBrightnessDecrease(float currentBrightness) {
doReturn(0.0f).when(mPowerManager).getBrightnessConstraint(
DEFAULT_DISPLAY, PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
@@ -661,13 +668,21 @@
}
void assertBackEventInjected() {
- ArgumentCaptor<InputEvent> intentCaptor = ArgumentCaptor.forClass(InputEvent.class);
- verify(mInputManager, times(2)).injectInputEvent(intentCaptor.capture(), anyInt());
- List<InputEvent> inputEvents = intentCaptor.getAllValues();
- Assert.assertEquals(KeyEvent.KEYCODE_BACK, ((KeyEvent) inputEvents.get(0)).getKeyCode());
- Assert.assertEquals(KeyEvent.KEYCODE_BACK, ((KeyEvent) inputEvents.get(1)).getKeyCode());
- // Reset verifier for next call.
- Mockito.clearInvocations(mContext);
+ if (mDelegateBackGestureRemote) {
+ Mockito.verify(mActivityTaskManagerInternal).requestBackGesture();
+ ArgumentCaptor<InputEvent> intentCaptor = ArgumentCaptor.forClass(InputEvent.class);
+ verify(mInputManager, never()).injectInputEvent(intentCaptor.capture(), anyInt());
+ } else {
+ ArgumentCaptor<InputEvent> intentCaptor = ArgumentCaptor.forClass(InputEvent.class);
+ verify(mInputManager, times(2)).injectInputEvent(intentCaptor.capture(), anyInt());
+ List<InputEvent> inputEvents = intentCaptor.getAllValues();
+ Assert.assertEquals(KeyEvent.KEYCODE_BACK,
+ ((KeyEvent) inputEvents.get(0)).getKeyCode());
+ Assert.assertEquals(KeyEvent.KEYCODE_BACK,
+ ((KeyEvent) inputEvents.get(1)).getKeyCode());
+ // Reset verifier for next call.
+ Mockito.clearInvocations(mContext);
+ }
}
void overrideSearchKeyBehavior(int behavior) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 1cb1e3c..ec26403 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -25,6 +25,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT;
import static com.android.server.wm.ActivityInterceptorCallback.MAINLINE_FIRST_ORDERED_ID;
import static com.android.server.wm.ActivityInterceptorCallback.SYSTEM_FIRST_ORDERED_ID;
import static com.android.server.wm.ActivityInterceptorCallback.SYSTEM_LAST_ORDERED_ID;
@@ -67,6 +68,7 @@
import android.os.PowerManagerInternal;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.view.Display;
import android.view.DisplayInfo;
@@ -75,6 +77,8 @@
import androidx.test.filters.MediumTest;
+import com.android.server.UiThread;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -164,11 +168,13 @@
verify(mClientLifecycleManager, never()).scheduleTransactionItem(any(), any());
}
+ @EnableFlags(FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT)
@Test
public void testDisplayWindowListener() {
final ArrayList<Integer> added = new ArrayList<>();
final ArrayList<Integer> changed = new ArrayList<>();
final ArrayList<Integer> removed = new ArrayList<>();
+ final ArrayList<Integer> desktopModeEligibleChanged = new ArrayList<>();
IDisplayWindowListener listener = new IDisplayWindowListener.Stub() {
@Override
public void onDisplayAdded(int displayId) {
@@ -194,6 +200,11 @@
@Override
public void onKeepClearAreasChanged(int displayId, List<Rect> restricted,
List<Rect> unrestricted) {}
+
+ @Override
+ public void onDesktopModeEligibleChanged(int displayId) {
+ desktopModeEligibleChanged.add(displayId);
+ }
};
int[] displayIds = mAtm.mWindowManager.registerDisplayWindowListener(listener);
for (int i = 0; i < displayIds.length; i++) {
@@ -218,7 +229,25 @@
assertEquals(1, changed.size());
assertEquals(0, removed.size());
changed.clear();
+
+ // Check adding decoration
+ doReturn(true).when(newDisp1).allowContentModeSwitch();
+ doReturn(true).when(newDisp1).isSystemDecorationsSupported();
+ mAtm.mWindowManager.setShouldShowSystemDecors(newDisp1.mDisplayId, true);
+ waitHandlerIdle(UiThread.getHandler());
+ assertEquals(1, desktopModeEligibleChanged.size());
+ assertEquals(newDisp1.mDisplayId, (int) desktopModeEligibleChanged.get(0));
+ desktopModeEligibleChanged.clear();
+ // Check removing decoration
+ doReturn(false).when(newDisp1).isSystemDecorationsSupported();
+ mAtm.mWindowManager.setShouldShowSystemDecors(newDisp1.mDisplayId, false);
+ waitHandlerIdle(UiThread.getHandler());
+ assertEquals(1, desktopModeEligibleChanged.size());
+ assertEquals(newDisp1.mDisplayId, (int) desktopModeEligibleChanged.get(0));
+ desktopModeEligibleChanged.clear();
+
// Check that removal is reported
+ changed.clear();
newDisp1.remove();
assertEquals(0, added.size());
assertEquals(0, changed.size());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
index f587d6e..6782305 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
@@ -21,7 +21,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_SMALL_VALUE;
@@ -282,6 +282,7 @@
final DisplayContent dc = spy(createNewDisplay());
final Task existingFreeformTask = new TaskBuilder(mSupervisor).setCreateActivity(true)
.setWindowingMode(WINDOWING_MODE_FREEFORM).setPackage(packageName).build();
+ existingFreeformTask.topRunningActivity().launchMode = LAUNCH_SINGLE_INSTANCE;
existingFreeformTask.setBounds(
/* left */ 0,
/* top */ 0,
@@ -293,8 +294,8 @@
// so first instance will close.
final Task launchingTask = new TaskBuilder(mSupervisor).setPackage(packageName)
.setCreateActivity(true).build();
+ launchingTask.topRunningActivity().launchMode = LAUNCH_SINGLE_INSTANCE;
launchingTask.onDisplayChanged(dc);
- launchingTask.intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
// New instance should inherit task bounds of old instance.
assertEquals(RESULT_DONE,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index 521d836..449ca86 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -52,6 +52,8 @@
import androidx.test.filters.SmallTest;
import com.android.server.LocalServices;
+import com.android.server.UiThread;
+import com.android.server.notification.NotificationManagerInternal;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
import com.android.window.flags.Flags;
@@ -59,6 +61,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mockito;
import java.util.HashMap;
import java.util.Map;
@@ -387,6 +390,30 @@
}
@Test
+ @EnableFlags(com.android.server.display.feature.flags.Flags
+ .FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT)
+ public void testSetShouldShowSystemDecorsNotifyNotificationManager() {
+ final NotificationManagerInternal notificationManager = Mockito.mock(
+ NotificationManagerInternal.class);
+ LocalServices.addService(NotificationManagerInternal.class, notificationManager);
+ try {
+ // First show the decoration because setting false is noop if the decoration has already
+ // been hidden.
+ mDisplayWindowSettings.setShouldShowSystemDecorsLocked(
+ mSecondaryDisplay, /* shouldShow= */ true);
+
+ mDisplayWindowSettings.setShouldShowSystemDecorsLocked(
+ mSecondaryDisplay, /* shouldShow= */ false);
+
+ waitHandlerIdle(UiThread.getHandler());
+ Mockito.verify(notificationManager).onDisplayRemoveSystemDecorations(
+ mSecondaryDisplay.mDisplayId);
+ } finally {
+ LocalServices.removeServiceForTest(NotificationManagerInternal.class);
+ }
+ }
+
+ @Test
public void testPrimaryDisplayImePolicy() {
assertEquals(DISPLAY_IME_POLICY_LOCAL,
mDisplayWindowSettings.getImePolicyLocked(mPrimaryDisplay));
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 73102c4..5427dc2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -1486,6 +1486,46 @@
}
@Test
+ @EnableFlags(Flags.FLAG_FIX_HIDE_OVERLAY_API)
+ public void testUpdateOverlayWindows_multipleWindowsFromSameUid_idempotent() {
+ // Deny INTERNAL_SYSTEM_WINDOW permission for WindowSession so that the saw isn't allowed to
+ // show despite hideNonSystemOverlayWindows.
+ doReturn(PackageManager.PERMISSION_DENIED).when(mWm.mContext).checkPermission(
+ eq(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW), anyInt(), anyInt());
+
+ WindowState saw =
+ newWindowBuilder("saw", TYPE_APPLICATION_OVERLAY).setOwnerId(10123).build();
+ saw.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
+ saw.mWinAnimator.mSurfaceControl = mock(SurfaceControl.class);
+ assertThat(saw.mSession.mCanAddInternalSystemWindow).isFalse();
+
+ WindowState app1 = newWindowBuilder("app1", TYPE_APPLICATION).setOwnerId(10456).build();
+ spyOn(app1);
+ doReturn(true).when(app1).hideNonSystemOverlayWindowsWhenVisible();
+
+ WindowState app2 = newWindowBuilder("app2", TYPE_APPLICATION).setOwnerId(10456).build();
+ spyOn(app2);
+ doReturn(true).when(app2).hideNonSystemOverlayWindowsWhenVisible();
+
+ makeWindowVisible(saw, app1, app2);
+ assertThat(saw.isVisibleByPolicy()).isTrue();
+
+ // Two hideNonSystemOverlayWindows windows: SAW is hidden.
+ mWm.updateNonSystemOverlayWindowsVisibilityIfNeeded(app1, true);
+ mWm.updateNonSystemOverlayWindowsVisibilityIfNeeded(app2, true);
+ assertThat(saw.isVisibleByPolicy()).isFalse();
+
+ // Marking the same window hidden twice: SAW is still hidden.
+ mWm.updateNonSystemOverlayWindowsVisibilityIfNeeded(app1, false);
+ mWm.updateNonSystemOverlayWindowsVisibilityIfNeeded(app1, false);
+ assertThat(saw.isVisibleByPolicy()).isFalse();
+
+ // Marking the remaining window hidden: SAW can be shown again.
+ mWm.updateNonSystemOverlayWindowsVisibilityIfNeeded(app2, false);
+ assertThat(saw.isVisibleByPolicy()).isTrue();
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_REPARENT_WINDOW_TOKEN_API)
public void reparentWindowContextToDisplayArea_newDisplay_reparented() {
final WindowToken windowToken = createTestClientWindowToken(TYPE_NOTIFICATION_SHADE,
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 5624677..fa77e42 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -562,26 +562,6 @@
}
@Test
- public void testDeferredRemovalByAnimating() {
- final WindowState appWindow = newWindowBuilder("appWindow", TYPE_APPLICATION).build();
- makeWindowVisible(appWindow);
- spyOn(appWindow.mWinAnimator);
- doReturn(true).when(appWindow.mWinAnimator).getShown();
- final AnimationAdapter animation = mock(AnimationAdapter.class);
- final ActivityRecord activity = appWindow.mActivityRecord;
- activity.startAnimation(appWindow.getPendingTransaction(),
- animation, false /* hidden */, SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION);
-
- appWindow.removeIfPossible();
- assertTrue(appWindow.mAnimatingExit);
- assertFalse(appWindow.mRemoved);
-
- activity.cancelAnimation();
- assertFalse(appWindow.mAnimatingExit);
- assertTrue(appWindow.mRemoved);
- }
-
- @Test
public void testOnExitAnimationDone() {
final WindowState parent = newWindowBuilder("parent", TYPE_APPLICATION).build();
final WindowState child = newWindowBuilder("child", TYPE_APPLICATION_PANEL).setParent(
diff --git a/services/usb/java/com/android/server/usb/flags/usb_flags.aconfig b/services/usb/java/com/android/server/usb/flags/usb_flags.aconfig
index dfbd74c..5628c75 100644
--- a/services/usb/java/com/android/server/usb/flags/usb_flags.aconfig
+++ b/services/usb/java/com/android/server/usb/flags/usb_flags.aconfig
@@ -28,3 +28,10 @@
description: "This flag maximizes the usb audio volume when it is connected"
bug: "245041322"
}
+
+flag {
+ name: "wait_for_alsa_scan_results_if_has_audio_interface"
+ namespace: "usb"
+ description: "This flag waits for alsa scan results for audio device"
+ bug: "378826805"
+}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index c244168..51ce144 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -2912,38 +2912,48 @@
if (bundle.size() != newBundle.size()) {
return false;
}
-
- for(String key : bundle.keySet()) {
- if (key != null) {
- if (!newBundle.containsKey(key)) {
- return false;
- }
- // In case new call extra contains non-framework class objects, return false to
- // force update the call extra
- try {
- final Object value = bundle.get(key);
- final Object newValue = newBundle.get(key);
- if (value instanceof Bundle && newValue instanceof Bundle) {
- if (!areBundlesEqual((Bundle) value, (Bundle) newValue)) {
- return false;
- }
- }
- if (value instanceof byte[] && newValue instanceof byte[]) {
- if (!Arrays.equals((byte[]) value, (byte[]) newValue)) {
- return false;
- }
- } else if (!Objects.equals(value, newValue)) {
+ try {
+ for (String key : bundle.keySet()) {
+ if (key != null) {
+ if (!newBundle.containsKey(key)) {
return false;
}
- } catch (BadParcelableException e) {
- return false;
- } catch (ClassCastException e) {
- Log.e(LOG_TAG, e, "areBundlesEqual: failure comparing bundle key %s", key);
- // until we know what is causing this, we should rethrow -- this is still not
- // expected.
- throw e;
+ // In case new call extra contains non-framework class objects, return false to
+ // force update the call extra
+ try {
+ final Object value = bundle.get(key);
+ final Object newValue = newBundle.get(key);
+ if (value instanceof Bundle && newValue instanceof Bundle) {
+ if (!areBundlesEqual((Bundle) value, (Bundle) newValue)) {
+ return false;
+ }
+ }
+ if (value instanceof byte[] && newValue instanceof byte[]) {
+ if (!Arrays.equals((byte[]) value, (byte[]) newValue)) {
+ return false;
+ }
+ } else if (!Objects.equals(value, newValue)) {
+ return false;
+ }
+ } catch (BadParcelableException e) {
+ return false;
+ }
}
}
+ } catch (ClassCastException | ArrayIndexOutOfBoundsException e) {
+ // Unfortunately this may get raised when accessing the bundle's keyset, so we cannot
+ // determine WHY a class cast exception is happening. We had tried in the past to do
+ // this down in the for loop so we could figure out which key is causing an issue.
+ // Bundles are not thread safe, so the most likely issue here is that the InCallService
+ // implementation is accessing the Bundle WHILE an incoming Telecom update comes in to
+ // potentially replace the Bundle. We call "areBundlesEqual" to see if the newly
+ // unparceled Call.Details is the same as what is already in the current Call instance.
+ // If those two operations overleave, I can see the potential for concurrent
+ // modification and edit of the Bundle. So we'll just catch here and assume the Bundles
+ // are not the same. This means a Call.CallBack may fire the onCallDetails changed
+ // callback when the Bundle didn't actually change.
+ Log.e(LOG_TAG, e, "areBundlesEqual: failed!");
+ return false;
}
return true;
}
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 270d599..6b4b0ee 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -700,6 +700,56 @@
public @interface DisplayMode {}
/**
+ * Unknown or unsupported value for data mode on satellite.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_25Q4_APIS)
+ public static final int SATELLITE_DATA_SUPPORT_UNKNOWN = -1;
+
+ /**
+ * Support only restricted data usecases like carrier messaging using RCS.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_25Q4_APIS)
+ public static final int SATELLITE_DATA_SUPPORT_RESTRICTED = 0;
+
+ /**
+ * Support constrained internet which would enable internet only for applications that are
+ * modified.
+ *
+ * <p>
+ * To get internet access, applications need to be modified to use the satellite data
+ * optimized network. This can be done by setting the {@link #PROPERTY_SATELLITE_DATA_OPTIMIZED}
+ * property to {@code true} in the manifest.
+ * </p>
+ *
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_25Q4_APIS)
+ public static final int SATELLITE_DATA_SUPPORT_CONSTRAINED = 1;
+
+ /**
+ * Support default internet on satellite without any restrictions on any apps.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_25Q4_APIS)
+ public static final int SATELLITE_DATA_SUPPORT_UNCONSTRAINED = 2;
+
+ /** @hide */
+ @IntDef(prefix = {"SATELLITE_DATA_SUPPORT_"}, value = {
+ SATELLITE_DATA_SUPPORT_UNKNOWN,
+ SATELLITE_DATA_SUPPORT_RESTRICTED,
+ SATELLITE_DATA_SUPPORT_CONSTRAINED,
+ SATELLITE_DATA_SUPPORT_UNCONSTRAINED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SatelliteDataSupportMode {}
+
+ /**
* The emergency call is handed over to oem-enabled satellite SOS messaging. SOS messages are
* sent to SOS providers, which will then forward the messages to emergency providers.
* @hide
@@ -3788,6 +3838,39 @@
return appsNames;
}
+ /**
+ * Method to return the current satellite data service policy supported mode for the
+ * subscriptionId based on carrier config.
+ *
+ * @param subId current subscription id.
+ *
+ * @return Supported modes {@link SatelliteDataSupportMode}
+ * @throws IllegalArgumentException if the subscription is invalid.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+ @FlaggedApi(Flags.FLAG_SATELLITE_25Q4_APIS)
+ @SatelliteDataSupportMode
+ public int getSatelliteDataSupportMode(int subId) {
+ int satelliteMode = SATELLITE_DATA_SUPPORT_UNKNOWN;
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ satelliteMode = telephony.getSatelliteDataSupportMode(subId);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ loge("getSatelliteDataSupportMode() RemoteException:" + ex);
+ ex.rethrowAsRuntimeException();
+ }
+
+ return satelliteMode;
+ }
+
@Nullable
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(TelephonyFrameworkInitializer
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index b8aa9e8..2095ee8 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -3135,6 +3135,16 @@
boolean setSatelliteIgnoreCellularServiceState(in boolean enabled);
/**
+ * This API can be used by only CTS to control the feature
+ * {@code config_support_disable_satellite_while_enable_in_progress}.
+ *
+ * @param reset Whether to reset the override.
+ * @param supported Whether to support the feature.
+ * @return {@code true} if the value is set successfully, {@code false} otherwise.
+ */
+ boolean setSupportDisableSatelliteWhileEnableInProgress(boolean reset, boolean supported);
+
+ /**
* This API can be used by only CTS to update satellite pointing UI app package and class names.
*
* @param packageName The package name of the satellite pointing UI app.
@@ -3641,4 +3651,19 @@
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
List<String> getSatelliteDataOptimizedApps();
+
+ /**
+ * Method to return the current satellite data service policy supported mode for the
+ * subscriptionId based on subscription id. Note: Iif any error or invalid sub id
+ * {@Link SatelliteDataSupportMode#SATELLITE_DATA_SUPPORT_UNKNOWN} will be returned.
+ *
+ * @param subId current subscription id.
+ *
+ * @return Supported modes {@link SatelliteDataSupportMode}
+ * @throws IllegalArgumentException if the subscription is invalid.
+ * @hide
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ int getSatelliteDataSupportMode(in int subId);
}
diff --git a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
index 7ec8f9c..71c7a6b 100644
--- a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
+++ b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
@@ -35,8 +35,8 @@
import android.os.SystemClock
import android.os.test.FakePermissionEnforcer
import android.os.test.TestLooper
-import android.platform.test.annotations.Presubmit
import android.platform.test.annotations.EnableFlags
+import android.platform.test.annotations.Presubmit
import android.platform.test.flag.junit.SetFlagsRule
import android.provider.Settings
import android.view.View.OnKeyListener
@@ -373,6 +373,29 @@
}
@Test
+ @EnableFlags(com.android.hardware.input.Flags.FLAG_FIX_SEARCH_MODIFIER_FALLBACKS)
+ fun testInterceptKeyBeforeDispatchingWithFallthroughEvent() {
+ service.systemRunning()
+ overrideSendActionKeyEventsToFocusedWindow(
+ /* hasPermission = */false,
+ /* hasPrivateFlag = */false
+ )
+ whenever(wmCallbacks.interceptKeyBeforeDispatching(any(), any(), anyInt())).thenReturn(0)
+
+ // Create a fallback for a key event with a meta modifier. Should result in -2,
+ // which represents the fallback event, which indicates that original key event will
+ // be ignored (not sent to app) and instead the fallback will be created and sent to the
+ // app.
+ val fallbackAction: KeyCharacterMap.FallbackAction = KeyCharacterMap.FallbackAction.obtain()
+ fallbackAction.keyCode = KeyEvent.KEYCODE_SEARCH
+ whenever(kcm.getFallbackAction(anyInt(), anyInt())).thenReturn(fallbackAction)
+
+ val event = KeyEvent( /* downTime= */0, /* eventTime= */0, KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_SPACE, /* repeat= */0, KeyEvent.META_META_ON)
+ assertEquals(-2, service.interceptKeyBeforeDispatching(null, event, 0))
+ }
+
+ @Test
fun testKeyEventsNotForwardedToFocusedWindow_whenWmConsumes() {
service.systemRunning()
overrideSendActionKeyEventsToFocusedWindow(
diff --git a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
index adefac6..6846d48 100644
--- a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
+++ b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
@@ -231,7 +231,7 @@
.replacePreferredActivity(intentFilterCaptor.capture(),
eq(IntentFilter.MATCH_CATEGORY_SCHEME
| IntentFilter.MATCH_ADJUSTMENT_NORMAL),
- isNotNull(List.class),
+ (List<ComponentName>)isNotNull(),
eq(new ComponentName(TEST_COMPONENT_NAME.getPackageName(), SEND_TO_NAME)));
Set<String> capturedSchemes = intentFilterCaptor.getAllValues().stream()
diff --git a/tools/aapt2/cmd/Compile.h b/tools/aapt2/cmd/Compile.h
index e244546..88d61b5 100644
--- a/tools/aapt2/cmd/Compile.h
+++ b/tools/aapt2/cmd/Compile.h
@@ -75,7 +75,7 @@
AddOptionalSwitch("--preserve-visibility-of-styleables",
"If specified, apply the same visibility rules for\n"
"styleables as are used for all other resources.\n"
- "Otherwise, all stylesables will be made public.",
+ "Otherwise, all styleables will be made public.",
&options_.preserve_visibility_of_styleables);
AddOptionalFlag("--visibility",
"Sets the visibility of the compiled resources to the specified\n"
diff --git a/tools/protologtool/Android.bp b/tools/protologtool/Android.bp
index 8fbc3e8..a103d03 100644
--- a/tools/protologtool/Android.bp
+++ b/tools/protologtool/Android.bp
@@ -11,13 +11,13 @@
name: "protologtool-lib",
srcs: [
"src/com/android/protolog/tool/**/*.kt",
- ":protolog-common-src",
],
static_libs: [
"javaparser",
- "platformprotos",
"jsonlib",
"perfetto_trace-full",
+ "platformprotos",
+ "protolog-common-lib",
],
}
@@ -39,10 +39,10 @@
unit_test: true,
},
static_libs: [
- "protologtool-lib",
"junit",
"mockito",
"objenesis",
+ "protologtool-lib",
"truth",
],
}
diff --git a/tools/protologtool/src/com/android/protolog/tool/Exceptions.kt b/tools/protologtool/src/com/android/protolog/tool/Exceptions.kt
new file mode 100644
index 0000000..4f7e8d1
--- /dev/null
+++ b/tools/protologtool/src/com/android/protolog/tool/Exceptions.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.protolog.tool
+
+import java.lang.Exception
+
+open class CodeProcessingException(
+ message: String, context: ParsingContext, cause: Throwable? = null
+) : Exception("Code processing error in ${context.filePath}:${context.lineNumber}:\n" +
+ " $message", cause)
+
+class HashCollisionException(
+ message: String, context: ParsingContext, cause: Throwable? = null
+) : CodeProcessingException(message, context, cause)
+
+class IllegalImportException(message: String, context: ParsingContext, cause: Throwable? = null) :
+ CodeProcessingException("Illegal import: $message", context, cause)
+
+class InvalidProtoLogCallException(
+ message: String, context: ParsingContext, cause: Throwable? = null
+) : CodeProcessingException("InvalidProtoLogCall: $message", context, cause)
+
+class ParsingException(message: String, context: ParsingContext, cause: Throwable? = null) :
+ CodeProcessingException(message, context, cause)
+
+class InvalidViewerConfigException(message: String) : Exception(message)
+
+class InvalidInputException(message: String) : Exception(message)
+
+class InvalidCommandException(message: String) : Exception(message)
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt
index 47724b7..03c3a15 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt
@@ -24,5 +24,5 @@
logCallVisitor: ProtoLogCallVisitor?,
otherCallVisitor: MethodCallVisitor?,
fileName: String
- ): CompilationUnit
+ ): Collection<CodeProcessingException>
}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt
index 272d8bb..44db2ba 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt
@@ -74,7 +74,7 @@
}
fun process(code: CompilationUnit, logCallVisitor: ProtoLogCallVisitor?, fileName: String):
- CompilationUnit {
+ Collection<CodeProcessingException> {
return process(code, logCallVisitor, null, fileName)
}
@@ -83,7 +83,7 @@
logCallVisitor: ProtoLogCallVisitor?,
otherCallVisitor: MethodCallVisitor?,
fileName: String
- ): CompilationUnit {
+ ): Collection<CodeProcessingException> {
CodeUtils.checkWildcardStaticImported(code, protoLogClassName, fileName)
CodeUtils.checkWildcardStaticImported(code, protoLogGroupClassName, fileName)
@@ -93,42 +93,63 @@
protoLogGroupClassName)
val staticGroupImports = CodeUtils.staticallyImportedMethods(code, protoLogGroupClassName)
+ val errors = mutableListOf<CodeProcessingException>()
code.findAll(MethodCallExpr::class.java)
.filter { call ->
isProtoCall(call, isLogClassImported, staticLogImports)
}.forEach { call ->
val context = ParsingContext(fileName, call)
- val logMethods = LogLevel.entries.map { it.shortCode }
- if (logMethods.contains(call.name.id)) {
- // Process a log call
- if (call.arguments.size < 2) {
- throw InvalidProtoLogCallException("Method signature does not match " +
- "any ProtoLog method: $call", context)
- }
+ try {
+ val logMethods = LogLevel.entries.map { it.shortCode }
+ if (logMethods.contains(call.name.id)) {
+ // Process a log call
+ if (call.arguments.size < 2) {
+ errors.add(InvalidProtoLogCallException(
+ "Method signature does not match " +
+ "any ProtoLog method: $call", context
+ ))
+ return@forEach
+ }
- val messageString = CodeUtils.concatMultilineString(call.getArgument(1),
- context)
- val groupNameArg = call.getArgument(0)
- val groupName =
- getLogGroupName(groupNameArg, isGroupClassImported,
- staticGroupImports, fileName)
- if (groupName !in groupMap) {
- throw InvalidProtoLogCallException("Unknown group argument " +
- "- not a ProtoLogGroup enum member: $call", context)
- }
+ val messageString = CodeUtils.concatMultilineString(
+ call.getArgument(1),
+ context
+ )
+ val groupNameArg = call.getArgument(0)
+ val groupName =
+ getLogGroupName(
+ groupNameArg, isGroupClassImported,
+ staticGroupImports, fileName
+ )
+ if (groupName !in groupMap) {
+ errors.add(InvalidProtoLogCallException(
+ "Unknown group argument " +
+ "- not a ProtoLogGroup enum member: $call", context
+ ))
+ return@forEach
+ }
- logCallVisitor?.processCall(call, messageString, getLevelForMethodName(
- call.name.toString(), call, context), groupMap.getValue(groupName),
- context.lineNumber)
- } else if (call.name.id == "init") {
- // No processing
- } else {
- // Process non-log message calls
- otherCallVisitor?.processCall(call)
+ logCallVisitor?.processCall(
+ call, messageString, getLevelForMethodName(
+ call.name.toString(), call, context
+ ), groupMap.getValue(groupName),
+ context.lineNumber
+ )
+ } else if (call.name.id == "init") {
+ // No processing
+ } else {
+ // Process non-log message calls
+ otherCallVisitor?.processCall(call)
+ }
+ } catch (e: Throwable) {
+ errors.add(InvalidProtoLogCallException(
+ "Error processing log call: $call",
+ context, e
+ ))
}
}
- return code
+ return errors
}
private fun getLevelForMethodName(
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index d8a2954..e9f2e81 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -130,14 +130,16 @@
val outSrc = try {
val code = tryParse(text, path)
if (containsProtoLogText(text, PROTOLOG_CLASS_NAME)) {
- transformer.processClass(text, path, packagePath(file, code), code)
+ val (processedText, errors) = transformer.processClass(text, path, packagePath(file, code), code)
+ errors.forEach { injector.reportProcessingError(it) }
+ processedText
} else {
text
}
} catch (ex: ParsingException) {
// If we cannot parse this file, skip it (and log why). Compilation will
// fail in a subsequent build step.
- injector.reportParseError(ex)
+ injector.reportProcessingError(ex)
text
}
path to outSrc
@@ -405,7 +407,7 @@
} catch (ex: ParsingException) {
// If we cannot parse this file, skip it (and log why). Compilation will
// fail in a subsequent build step.
- injector.reportParseError(ex)
+ injector.reportProcessingError(ex)
null
}
} else {
@@ -466,6 +468,14 @@
try {
val command = CommandOptions(args)
invoke(command)
+
+ if (injector.processingErrors.isNotEmpty()) {
+ injector.processingErrors.forEachIndexed { index, it ->
+ println("CodeProcessingException " +
+ "(${index + 1}/${injector.processingErrors.size}): \n${it.message}\n")
+ }
+ exitProcess(1)
+ }
} catch (ex: InvalidCommandException) {
println("InvalidCommandException: \n${ex.message}\n")
showHelpAndExit()
@@ -489,12 +499,14 @@
}
var injector = object : Injector {
+ override val processingErrors: MutableList<CodeProcessingException>
+ get() = mutableListOf()
override fun fileOutputStream(file: String) = FileOutputStream(file)
override fun readText(file: File) = file.readText()
override fun readLogGroups(jarPath: String, className: String) =
ProtoLogGroupReader().loadFromJar(jarPath, className)
- override fun reportParseError(ex: ParsingException) {
- println("\n${ex.message}\n")
+ override fun reportProcessingError(ex: CodeProcessingException) {
+ processingErrors.add(ex)
}
}
@@ -502,7 +514,8 @@
fun fileOutputStream(file: String): OutputStream
fun readText(file: File): String
fun readLogGroups(jarPath: String, className: String): Map<String, LogGroup>
- fun reportParseError(ex: ParsingException)
+ fun reportProcessingError(ex: CodeProcessingException)
+ val processingErrors: Collection<CodeProcessingException>
}
}
diff --git a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
index 76df067..e97b0dd 100644
--- a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
@@ -66,13 +66,13 @@
packagePath: String,
compilationUnit: CompilationUnit =
StaticJavaParser.parse(code)
- ): String {
+ ): Pair<String, Collection<CodeProcessingException>> {
this.path = path
this.packagePath = packagePath
processedCode = code.split('\n').toMutableList()
offsets = IntArray(processedCode.size)
- protoLogCallProcessor.process(compilationUnit, protoLogCallVisitor, otherCallVisitor, path)
- return processedCode.joinToString("\n")
+ val processingErrors = protoLogCallProcessor.process(compilationUnit, protoLogCallVisitor, otherCallVisitor, path)
+ return Pair(processedCode.joinToString("\n"), processingErrors)
}
private val protoLogImplClassNode =
diff --git a/tools/protologtool/src/com/android/protolog/tool/exceptions.kt b/tools/protologtool/src/com/android/protolog/tool/exceptions.kt
deleted file mode 100644
index ae00df1..0000000
--- a/tools/protologtool/src/com/android/protolog/tool/exceptions.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.protolog.tool
-
-import java.lang.Exception
-
-open class CodeProcessingException(message: String, context: ParsingContext)
- : Exception("Code processing error in ${context.filePath}:${context.lineNumber}:\n" +
- " $message")
-
-class HashCollisionException(message: String, context: ParsingContext) :
- CodeProcessingException(message, context)
-
-class IllegalImportException(message: String, context: ParsingContext) :
- CodeProcessingException("Illegal import: $message", context)
-
-class InvalidProtoLogCallException(message: String, context: ParsingContext)
- : CodeProcessingException("InvalidProtoLogCall: $message", context)
-
-class ParsingException(message: String, context: ParsingContext)
- : CodeProcessingException(message, context)
-
-class InvalidViewerConfigException(message: String) : Exception(message)
-
-class InvalidInputException(message: String) : Exception(message)
-
-class InvalidCommandException(message: String) : Exception(message)
diff --git a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
index 0cbbd48..71bab3e 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
@@ -17,6 +17,7 @@
package com.android.protolog.tool
import com.android.protolog.tool.ProtoLogTool.PROTOLOG_IMPL_SRC_PATH
+import com.android.protolog.tool.ProtoLogTool.injector
import com.google.common.truth.Truth
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
@@ -102,6 +103,42 @@
""".trimIndent())
}
+ @Test
+ fun e2e_transform_withErrors() {
+ val srcs = mapOf(
+ "frameworks/base/org/example/Example.java" to """
+ package org.example;
+ import com.android.internal.protolog.ProtoLog;
+ import static com.android.internal.protolog.ProtoLogGroup.GROUP;
+
+ class Example {
+ void method() {
+ String argString = "hello";
+ int argInt = 123;
+ ProtoLog.d(GROUP, "Invalid format: %s %d %9 %", argString, argInt);
+ }
+ }
+ """.trimIndent())
+ val output = run(
+ srcs = srcs,
+ logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"),
+ commandOptions = CommandOptions(arrayOf("transform-protolog-calls",
+ "--protolog-class", "com.android.internal.protolog.ProtoLog",
+ "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup",
+ "--loggroups-jar", "not_required.jar",
+ "--viewer-config-file-path", "not_required.pb",
+ "--output-srcjar", "out.srcjar",
+ "frameworks/base/org/example/Example.java"))
+ )
+ val outSrcJar = assertLoadSrcJar(output, "out.srcjar")
+ // No change to source code on failure to process
+ Truth.assertThat(outSrcJar["frameworks/base/org/example/Example.java"])
+ .contains(srcs["frameworks/base/org/example/Example.java"])
+
+ Truth.assertThat(injector.processingErrors).hasSize(1)
+ Truth.assertThat(injector.processingErrors.first().message).contains("Invalid format")
+ }
+
private fun assertLoadSrcJar(
outputs: Map<String, ByteArray>,
path: String
@@ -172,7 +209,11 @@
override fun readLogGroups(jarPath: String, className: String) = mapOf(
logGroup.name to logGroup)
- override fun reportParseError(ex: ParsingException) = throw AssertionError(ex)
+ override fun reportProcessingError(ex: CodeProcessingException) {
+ processingErrors.add(ex)
+ }
+
+ override val processingErrors: MutableList<CodeProcessingException> = mutableListOf()
}
ProtoLogTool.invoke(commandOptions)
diff --git a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt
index 004d97b..8f765ae 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt
@@ -16,11 +16,13 @@
package com.android.protolog.tool
+import com.android.internal.protolog.common.InvalidFormatStringException
import com.android.internal.protolog.common.LogLevel
import com.github.javaparser.StaticJavaParser
import com.github.javaparser.ast.expr.MethodCallExpr
import org.junit.Assert.assertEquals
import org.junit.Test
+import com.google.common.truth.Truth
class ProtoLogCallProcessorImplTest {
private data class LogCall(
@@ -121,7 +123,7 @@
checkCalls()
}
- @Test(expected = InvalidProtoLogCallException::class)
+ @Test
fun process_groupNotImported() {
val code = """
package org.example2;
@@ -135,7 +137,10 @@
}
"""
groupMap["TEST"] = LogGroup("TEST", true, true, "WindowManager")
- visitor.process(StaticJavaParser.parse(code), processor, "")
+ val errors = visitor.process(StaticJavaParser.parse(code), processor, "")
+
+ Truth.assertThat(errors).hasSize(1)
+ Truth.assertThat(errors.first()).isInstanceOf(InvalidProtoLogCallException::class.java)
}
@Test
@@ -156,7 +161,7 @@
assertEquals(0, calls.size)
}
- @Test(expected = InvalidProtoLogCallException::class)
+ @Test
fun process_unknownGroup() {
val code = """
package org.example;
@@ -167,10 +172,13 @@
}
}
"""
- visitor.process(StaticJavaParser.parse(code), processor, "")
+ val errors = visitor.process(StaticJavaParser.parse(code), processor, "")
+
+ Truth.assertThat(errors).hasSize(1)
+ Truth.assertThat(errors.first()).isInstanceOf(InvalidProtoLogCallException::class.java)
}
- @Test(expected = InvalidProtoLogCallException::class)
+ @Test
fun process_staticGroup() {
val code = """
package org.example;
@@ -181,10 +189,13 @@
}
}
"""
- visitor.process(StaticJavaParser.parse(code), processor, "")
+ val errors = visitor.process(StaticJavaParser.parse(code), processor, "")
+
+ Truth.assertThat(errors).hasSize(1)
+ Truth.assertThat(errors.first()).isInstanceOf(InvalidProtoLogCallException::class.java)
}
- @Test(expected = InvalidProtoLogCallException::class)
+ @Test
fun process_badGroup() {
val code = """
package org.example;
@@ -195,10 +206,13 @@
}
}
"""
- visitor.process(StaticJavaParser.parse(code), processor, "")
+ val errors = visitor.process(StaticJavaParser.parse(code), processor, "")
+
+ Truth.assertThat(errors).hasSize(1)
+ Truth.assertThat(errors.first()).isInstanceOf(InvalidProtoLogCallException::class.java)
}
- @Test(expected = InvalidProtoLogCallException::class)
+ @Test
fun process_invalidSignature() {
val code = """
package org.example;
@@ -209,7 +223,10 @@
}
}
"""
- visitor.process(StaticJavaParser.parse(code), processor, "")
+ val errors = visitor.process(StaticJavaParser.parse(code), processor, "")
+
+ Truth.assertThat(errors).hasSize(1)
+ Truth.assertThat(errors.first()).isInstanceOf(InvalidProtoLogCallException::class.java)
}
@Test
@@ -228,4 +245,39 @@
visitor.process(StaticJavaParser.parse(code), processor, "")
checkCalls()
}
+
+ @Test
+ fun throws_clear_error_message_on_invalid_format_exception() {
+ val code = """
+ package org.example;
+
+ class Test {
+ void test() {
+ ProtoLog.d(ProtoLogGroup.TEST, "Invalid message %9 %");
+ }
+ }
+ """
+ groupMap["TEST"] = LogGroup("TEST", false, true, "WindowManager")
+
+ val processor = object : ProtoLogCallVisitor {
+ override fun processCall(
+ call: MethodCallExpr,
+ messageString: String,
+ level: LogLevel,
+ group: LogGroup,
+ lineNumber: Int,
+ ) {
+ throw InvalidFormatStringException("Invalid Protolog message format")
+ }
+ }
+
+ val errors = visitor.process(StaticJavaParser.parse(code), processor, "MyTestFile.java")
+ Truth.assertThat(errors).hasSize(1)
+
+ val exception = errors.first()
+ Truth.assertThat(exception).hasMessageThat()
+ .contains("Code processing error in MyTestFile.java:6")
+ Truth.assertThat(exception.cause).hasMessageThat()
+ .contains("Invalid Protolog message format")
+ }
}
diff --git a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
index 674a907..271fc60 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
@@ -160,10 +160,10 @@
visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f",
LogLevel.WARN, LogGroup("TEST_GROUP", true, true, "WM_TEST"), 123)
- invocation.arguments[0] as CompilationUnit
+ listOf<CodeProcessingException>()
}
- val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
+ val (out, _) = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
code = StaticJavaParser.parse(out)
val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
@@ -201,10 +201,10 @@
visitor.processCall(calls[2], "test %d %f",
LogLevel.WARN, LogGroup("TEST_GROUP", true, true, "WM_TEST"), 123)
- invocation.arguments[0] as CompilationUnit
+ listOf<CodeProcessingException>()
}
- val out = sourceJarWriter.processClass(TEST_CODE_MULTICALLS, PATH, PATH, code)
+ val (out, _) = sourceJarWriter.processClass(TEST_CODE_MULTICALLS, PATH, PATH, code)
code = StaticJavaParser.parse(out)
val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
@@ -238,10 +238,10 @@
"test %d %f abc %s\n test", LogLevel.WARN, LogGroup("TEST_GROUP",
true, true, "WM_TEST"), 123)
- invocation.arguments[0] as CompilationUnit
+ listOf<CodeProcessingException>()
}
- val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
+ val (out, _) = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
code = StaticJavaParser.parse(out)
val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
@@ -275,10 +275,10 @@
visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test",
LogLevel.WARN, LogGroup("TEST_GROUP", true, true, "WM_TEST"), 456)
- invocation.arguments[0] as CompilationUnit
+ listOf<CodeProcessingException>()
}
- val out = sourceJarWriter.processClass(TEST_CODE_NO_PARAMS, PATH, PATH, code)
+ val (out, _) = sourceJarWriter.processClass(TEST_CODE_NO_PARAMS, PATH, PATH, code)
code = StaticJavaParser.parse(out)
val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
@@ -309,10 +309,10 @@
visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f",
LogLevel.WARN, LogGroup("TEST_GROUP", true, false, "WM_TEST"), 789)
- invocation.arguments[0] as CompilationUnit
+ listOf<CodeProcessingException>()
}
- val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
+ val (out, _) = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
code = StaticJavaParser.parse(out)
val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
@@ -346,10 +346,10 @@
"test %d %f abc %s\n test", LogLevel.WARN, LogGroup("TEST_GROUP",
true, false, "WM_TEST"), 123)
- invocation.arguments[0] as CompilationUnit
+ listOf<CodeProcessingException>()
}
- val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
+ val (out, _) = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
code = StaticJavaParser.parse(out)
val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
diff --git a/vendor/google_testing/integration/tests/scenarios/screenshots/cuttlefish/flexiglass/six_digits_pin_delete.png b/vendor/google_testing/integration/tests/scenarios/screenshots/cuttlefish/flexiglass/six_digits_pin_delete.png
new file mode 100644
index 0000000..d4e72fb
--- /dev/null
+++ b/vendor/google_testing/integration/tests/scenarios/screenshots/cuttlefish/flexiglass/six_digits_pin_delete.png
Binary files differ