Merge "[expressive design] Create IntroPreference layout." into main
diff --git a/ACTIVITY_MANAGER_OWNERS b/ACTIVITY_MANAGER_OWNERS
new file mode 100644
index 0000000..47782d1
--- /dev/null
+++ b/ACTIVITY_MANAGER_OWNERS
@@ -0,0 +1,4 @@
[email protected]
[email protected]
[email protected]
[email protected]
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 0ca9789..dd919ca 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -93,6 +93,7 @@
"com.android.media.flags.performance-aconfig-java",
"com.android.media.flags.projection-aconfig-java",
"com.android.net.thread.platform.flags-aconfig-java",
+ "com.android.ranging.flags.ranging-aconfig-java",
"com.android.server.contextualsearch.flags-java",
"com.android.server.flags.services-aconfig-java",
"com.android.text.flags-aconfig-java",
@@ -1549,6 +1550,13 @@
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+// Ranging
+java_aconfig_library {
+ name: "com.android.ranging.flags.ranging-aconfig-java",
+ aconfig_declarations: "ranging_aconfig_flags",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
// System Server
aconfig_declarations {
name: "android.systemserver.flags-aconfig",
diff --git a/BATTERY_STATS_OWNERS b/BATTERY_STATS_OWNERS
index 7728975..575bded 100644
--- a/BATTERY_STATS_OWNERS
+++ b/BATTERY_STATS_OWNERS
@@ -1,4 +1,3 @@
# OWNERS of BatteryStats related files
[email protected]
[email protected]
[email protected]
diff --git a/OOM_ADJUSTER_OWNERS b/OOM_ADJUSTER_OWNERS
new file mode 100644
index 0000000..7727f9f
--- /dev/null
+++ b/OOM_ADJUSTER_OWNERS
@@ -0,0 +1,3 @@
[email protected]
[email protected]
[email protected]
diff --git a/apex/jobscheduler/ALARM_OWNERS b/apex/jobscheduler/ALARM_OWNERS
new file mode 100644
index 0000000..5c3bff7
--- /dev/null
+++ b/apex/jobscheduler/ALARM_OWNERS
@@ -0,0 +1,2 @@
[email protected]
[email protected]
\ No newline at end of file
diff --git a/apex/jobscheduler/DEVICE_IDLE_OWNERS b/apex/jobscheduler/DEVICE_IDLE_OWNERS
new file mode 100644
index 0000000..62db91d
--- /dev/null
+++ b/apex/jobscheduler/DEVICE_IDLE_OWNERS
@@ -0,0 +1,2 @@
[email protected]
[email protected]
\ No newline at end of file
diff --git a/apex/jobscheduler/JOB_OWNERS b/apex/jobscheduler/JOB_OWNERS
new file mode 100644
index 0000000..05bf25c
--- /dev/null
+++ b/apex/jobscheduler/JOB_OWNERS
@@ -0,0 +1,3 @@
[email protected]
[email protected]
[email protected]
\ No newline at end of file
diff --git a/apex/jobscheduler/OWNERS b/apex/jobscheduler/OWNERS
index 22b6489..ffa5802 100644
--- a/apex/jobscheduler/OWNERS
+++ b/apex/jobscheduler/OWNERS
@@ -1,8 +1,25 @@
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
+# For Job Scheduler and App Standby changes, JOB_OWNERS
+per-file JOB_OWNERS = file:/apex/jobscheduler/JOB_OWNERS
+per-file framework/aconfig/job.aconfig = file:/apex/jobscheduler/JOB_OWNERS
+per-file service/aconfig/job.aconfig = file:/apex/jobscheduler/JOB_OWNERS
+per-file service/aconfig/app_idle.aconfig = file:/apex/jobscheduler/JOB_OWNERS
+per-file *Job* = file:/apex/jobscheduler/JOB_OWNERS
+per-file *Standby* = file:/apex/jobscheduler/JOB_OWNERS
+per-file framework/java/android/app/job/* = file:/apex/jobscheduler/JOB_OWNERS
+per-file framework/java/com/android/server/job/* = file:/apex/jobscheduler/JOB_OWNERS
+per-file service/java/com/android/server/job/* = file:/apex/jobscheduler/JOB_OWNERS
+
+# For Alarm Manager changes, ALARM_OWNERS
+per-file ALARM_OWNERS = file:/apex/jobscheduler/ALARM_OWNERS
+per-file service/aconfig/alarm.aconfig = file:/apex/jobscheduler/ALARM_OWNERS
+per-file *Alarm* = file:/apex/jobscheduler/ALARM_OWNERS
+per-file service/java/com/android/server/alarm/* = file:/apex/jobscheduler/ALARM_OWNERS
+
+# For Device Idle changes, DEVICE_IDLE_OWNERS
+per-file DEVICE_IDLE_OWNERS = file:/apex/jobscheduler/DEVICE_IDLE_OWNERS
+per-file service/aconfig/device_idle.aconfig = file:/apex/jobscheduler/DEVICE_IDLE_OWNERS
+per-file *Idle* = file:/apex/jobscheduler/DEVICE_IDLE_OWNERS
+per-file service/java/com/android/server/deviceidle/* = file:/apex/jobscheduler/DEVICE_IDLE_OWNERS
+per-file framework/java/com/android/server/deviceidle/* = file:/apex/jobscheduler/DEVICE_IDLE_OWNERS
+
[email protected] #{LAST_RESORT_SUGGESTION}
\ No newline at end of file
diff --git a/apex/jobscheduler/framework/java/android/app/job/OWNERS b/apex/jobscheduler/framework/java/android/app/job/OWNERS
deleted file mode 100644
index 0b1e559..0000000
--- a/apex/jobscheduler/framework/java/android/app/job/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-# Bug component: 330738
-
[email protected]
[email protected]
[email protected]
[email protected]
diff --git a/api/Android.bp b/api/Android.bp
index 533f9f6..3f2316f 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -102,6 +102,11 @@
"framework-crashrecovery",
],
default: [],
+ }) + select(release_flag("RELEASE_RANGING_STACK"), {
+ true: [
+ "framework-ranging",
+ ],
+ default: [],
}),
system_server_classpath: [
"service-art",
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index b3a674f..d1aa23c 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -466,6 +466,32 @@
}
java_library {
+ name: "android-non-updatable.stubs.system_server",
+ defaults: ["android-non-updatable_defaults"],
+ static_libs: [
+ "android-non-updatable.stubs.system_server.from-source",
+ ],
+ product_variables: {
+ build_from_text_stub: {
+ static_libs: [
+ "android-non-updatable.stubs.system_server.from-text",
+ ],
+ exclude_static_libs: [
+ "android-non-updatable.stubs.system_server.from-source",
+ ],
+ },
+ },
+}
+
+java_library {
+ name: "android-non-updatable.stubs.exportable.system_server",
+ defaults: ["android-non-updatable_defaults"],
+ static_libs: [
+ "android-non-updatable.stubs.exportable.system_server.from-source",
+ ],
+}
+
+java_library {
name: "android-non-updatable.stubs.from-source",
defaults: [
"android-non-updatable_defaults",
@@ -561,6 +587,30 @@
},
}
+java_library {
+ name: "android-non-updatable.stubs.system_server.from-source",
+ defaults: [
+ "android-non-updatable_defaults",
+ "android-non-updatable_from_source_defaults",
+ ],
+ srcs: [":services-non-updatable-stubs"],
+ libs: non_updatable_api_deps_on_modules,
+}
+
+java_library {
+ name: "android-non-updatable.stubs.exportable.system_server.from-source",
+ defaults: [
+ "android-non-updatable_defaults",
+ "android-non-updatable_from_source_defaults",
+ "android-non-updatable_exportable_from_source_defaults",
+ ],
+ srcs: [":services-non-updatable-stubs{.exportable}"],
+ libs: non_updatable_api_deps_on_modules,
+ dist: {
+ dir: "apistubs/android/system-server",
+ },
+}
+
java_defaults {
name: "android-non-updatable_from_text_defaults",
defaults: ["android-non-updatable-stubs-libs-defaults"],
@@ -662,6 +712,25 @@
libs: ["all-modules-system-stubs"],
}
+java_api_library {
+ name: "android-non-updatable.stubs.system_server.from-text",
+ api_surface: "system_server",
+ api_contributions: [
+ "api-stubs-docs-non-updatable.api.contribution",
+ "system-api-stubs-docs-non-updatable.api.contribution",
+ "module-lib-api-stubs-docs-non-updatable.api.contribution",
+ "services-non-updatable-stubs.api.contribution",
+ ],
+ defaults: [
+ "module-classpath-java-defaults",
+ "android-non-updatable_everything_from_text_defaults",
+ ],
+
+ // Use full Android API not just the non-updatable API as the latter is incomplete
+ // and can result in incorrect behavior.
+ previous_api: ":android.api.combined.system-server.latest",
+}
+
java_defaults {
name: "android_stubs_dists_default",
dist: {
@@ -813,9 +882,9 @@
defaults: [
"android.jar_defaults",
],
- srcs: [":services-non-updatable-stubs"],
installable: false,
static_libs: [
+ "android-non-updatable.stubs.system_server",
"android_module_lib_stubs_current",
],
visibility: ["//frameworks/base/services"],
@@ -827,9 +896,9 @@
"android.jar_defaults",
"android_stubs_dists_default",
],
- srcs: [":services-non-updatable-stubs{.exportable}"],
installable: false,
static_libs: [
+ "android-non-updatable.stubs.exportable.system_server",
"android_module_lib_stubs_current_exportable",
],
dist: {
diff --git a/cmds/uiautomator/library/Android.bp b/cmds/uiautomator/library/Android.bp
index 966bf13..5c5b220 100644
--- a/cmds/uiautomator/library/Android.bp
+++ b/cmds/uiautomator/library/Android.bp
@@ -28,9 +28,9 @@
"testrunner-src/**/*.java",
],
libs: [
- "android.test.runner",
+ "android.test.runner.stubs.system",
"junit",
- "android.test.base",
+ "android.test.base.stubs.system",
"unsupportedappusage",
],
installable: false,
@@ -56,9 +56,9 @@
":uiautomator-stubs",
],
libs: [
- "android.test.runner",
+ "android.test.runner.stubs",
"junit",
- "android.test.base",
+ "android.test.base.stubs",
],
sdk_version: "current",
installable: false,
diff --git a/core/api/current.txt b/core/api/current.txt
index 1667f2e..d0e2003 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -19396,7 +19396,7 @@
public abstract static class CameraExtensionSession.ExtensionCaptureCallback {
ctor public CameraExtensionSession.ExtensionCaptureCallback();
method public void onCaptureFailed(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public void onCaptureFailed(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest, int);
+ method public void onCaptureFailed(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest, int);
method public void onCaptureProcessProgressed(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest, @IntRange(from=0, to=100) int);
method public void onCaptureProcessStarted(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest);
method public void onCaptureResultAvailable(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest, @NonNull android.hardware.camera2.TotalCaptureResult);
@@ -19921,7 +19921,7 @@
field @Deprecated @NonNull public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_RADIAL_DISTORTION;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_STATE;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.String> LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID;
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.graphics.Rect> LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION;
+ field @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.graphics.Rect> LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> NOISE_REDUCTION_MODE;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Byte> REQUEST_PIPELINE_DEPTH;
@@ -19947,7 +19947,7 @@
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_FACE_DETECT_MODE;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.graphics.Point[]> STATISTICS_HOT_PIXEL_MAP;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> STATISTICS_HOT_PIXEL_MAP_MODE;
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.LensIntrinsicsSample[]> STATISTICS_LENS_INTRINSICS_SAMPLES;
+ field @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.LensIntrinsicsSample[]> STATISTICS_LENS_INTRINSICS_SAMPLES;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.LensShadingMap> STATISTICS_LENS_SHADING_CORRECTION_MAP;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_LENS_SHADING_MAP_MODE;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_OIS_DATA_MODE;
@@ -20107,10 +20107,10 @@
method public boolean isMultiResolution();
}
- @FlaggedApi("com.android.internal.camera.flags.concert_mode") public final class LensIntrinsicsSample {
- ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public LensIntrinsicsSample(long, @NonNull float[]);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public float[] getLensIntrinsics();
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public long getTimestampNanos();
+ public final class LensIntrinsicsSample {
+ ctor public LensIntrinsicsSample(long, @NonNull float[]);
+ method @NonNull public float[] getLensIntrinsics();
+ method public long getTimestampNanos();
}
public final class LensShadingMap {
@@ -32613,6 +32613,13 @@
method public boolean isCharging();
field public static final String ACTION_CHARGING = "android.os.action.CHARGING";
field public static final String ACTION_DISCHARGING = "android.os.action.DISCHARGING";
+ field @FlaggedApi("android.os.battery_part_status_api") public static final int BATTERY_CAPACITY_LEVEL_CRITICAL = 1; // 0x1
+ field @FlaggedApi("android.os.battery_part_status_api") public static final int BATTERY_CAPACITY_LEVEL_FULL = 5; // 0x5
+ field @FlaggedApi("android.os.battery_part_status_api") public static final int BATTERY_CAPACITY_LEVEL_HIGH = 4; // 0x4
+ field @FlaggedApi("android.os.battery_part_status_api") public static final int BATTERY_CAPACITY_LEVEL_LOW = 2; // 0x2
+ field @FlaggedApi("android.os.battery_part_status_api") public static final int BATTERY_CAPACITY_LEVEL_NORMAL = 3; // 0x3
+ field @FlaggedApi("android.os.battery_part_status_api") public static final int BATTERY_CAPACITY_LEVEL_UNKNOWN = 0; // 0x0
+ field @FlaggedApi("android.os.battery_part_status_api") public static final int BATTERY_CAPACITY_LEVEL_UNSUPPORTED = -1; // 0xffffffff
field public static final int BATTERY_HEALTH_COLD = 7; // 0x7
field public static final int BATTERY_HEALTH_DEAD = 4; // 0x4
field public static final int BATTERY_HEALTH_GOOD = 2; // 0x2
@@ -32637,6 +32644,7 @@
field public static final int BATTERY_STATUS_NOT_CHARGING = 4; // 0x4
field public static final int BATTERY_STATUS_UNKNOWN = 1; // 0x1
field public static final String EXTRA_BATTERY_LOW = "battery_low";
+ field @FlaggedApi("android.os.battery_part_status_api") public static final String EXTRA_CAPACITY_LEVEL = "android.os.extra.CAPACITY_LEVEL";
field public static final String EXTRA_CHARGING_STATUS = "android.os.extra.CHARGING_STATUS";
field public static final String EXTRA_CYCLE_COUNT = "android.os.extra.CYCLE_COUNT";
field public static final String EXTRA_HEALTH = "health";
@@ -33228,6 +33236,7 @@
}
public interface IBinder {
+ method @FlaggedApi("android.os.binder_frozen_state_change_callback") public default void addFrozenStateChangeCallback(@NonNull android.os.IBinder.FrozenStateChangeCallback) throws android.os.RemoteException;
method public void dump(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException;
method public void dumpAsync(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException;
method @Nullable public String getInterfaceDescriptor() throws android.os.RemoteException;
@@ -33236,6 +33245,7 @@
method public void linkToDeath(@NonNull android.os.IBinder.DeathRecipient, int) throws android.os.RemoteException;
method public boolean pingBinder();
method @Nullable public android.os.IInterface queryLocalInterface(@NonNull String);
+ method @FlaggedApi("android.os.binder_frozen_state_change_callback") public default boolean removeFrozenStateChangeCallback(@NonNull android.os.IBinder.FrozenStateChangeCallback);
method public boolean transact(int, @NonNull android.os.Parcel, @Nullable android.os.Parcel, int) throws android.os.RemoteException;
method public boolean unlinkToDeath(@NonNull android.os.IBinder.DeathRecipient, int);
field public static final int DUMP_TRANSACTION = 1598311760; // 0x5f444d50
@@ -33253,6 +33263,12 @@
method public default void binderDied(@NonNull android.os.IBinder);
}
+ @FlaggedApi("android.os.binder_frozen_state_change_callback") public static interface IBinder.FrozenStateChangeCallback {
+ method public void onFrozenStateChanged(@NonNull android.os.IBinder, int);
+ field public static final int STATE_FROZEN = 0; // 0x0
+ field public static final int STATE_UNFROZEN = 1; // 0x1
+ }
+
public interface IInterface {
method public android.os.IBinder asBinder();
}
@@ -44070,7 +44086,7 @@
}
public static final class CarrierConfigManager.Gps {
- field @FlaggedApi("android.location.flags.enable_ni_supl_message_injection_by_carrier_config") public static final String KEY_ENABLE_NI_SUPL_MESSAGE_INJECTION_BOOL = "gps.enable_ni_supl_message_injection_bool";
+ field @FlaggedApi("android.location.flags.enable_ni_supl_message_injection_by_carrier_config_bugfix") public static final String KEY_ENABLE_NI_SUPL_MESSAGE_INJECTION_BOOL = "gps.enable_ni_supl_message_injection_bool";
field public static final String KEY_PERSIST_LPP_MODE_BOOL = "gps.persist_lpp_mode_bool";
field public static final String KEY_PREFIX = "gps.";
}
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index df45862..8447a7f 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -387,6 +387,12 @@
field public static final int DEVICE_INITIAL_SDK_INT;
}
+ public class Handler {
+ method @FlaggedApi("android.os.mainline_vcn_platform_api") public final boolean hasMessagesOrCallbacks();
+ method @FlaggedApi("android.os.mainline_vcn_platform_api") public final void removeCallbacksAndEqualMessages(@Nullable Object);
+ method @FlaggedApi("android.os.mainline_vcn_platform_api") public final void removeEqualMessages(int, @Nullable Object);
+ }
+
public class IpcDataCache<Query, Result> {
ctor public IpcDataCache(int, @NonNull String, @NonNull String, @NonNull String, @NonNull android.os.IpcDataCache.QueryHandler<Query,Result>);
method public void disableForCurrentProcess();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 7a8e829..cc0354c 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3835,6 +3835,7 @@
field @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public static final String ON_DEVICE_INTELLIGENCE_SERVICE = "on_device_intelligence";
field public static final String PERMISSION_CONTROLLER_SERVICE = "permission_controller";
field public static final String PERMISSION_SERVICE = "permission";
+ field @FlaggedApi("com.android.ranging.flags.ranging_stack_enabled") public static final String RANGING_SERVICE = "ranging";
field public static final String REBOOT_READINESS_SERVICE = "reboot_readiness";
field public static final String ROLLBACK_SERVICE = "rollback";
field public static final String SAFETY_CENTER_SERVICE = "safety_center";
@@ -4949,94 +4950,94 @@
package android.hardware.camera2.extension {
- @FlaggedApi("com.android.internal.camera.flags.concert_mode") public abstract class AdvancedExtender {
- ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public AdvancedExtender(@NonNull android.hardware.camera2.CameraManager);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public abstract java.util.List<android.hardware.camera2.CaptureRequest.Key> getAvailableCaptureRequestKeys(@NonNull String);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public abstract java.util.List<android.hardware.camera2.CaptureResult.Key> getAvailableCaptureResultKeys(@NonNull String);
- method @FlaggedApi("com.android.internal.camera.flags.camera_extensions_characteristics_get") @NonNull public abstract java.util.List<android.util.Pair<android.hardware.camera2.CameraCharacteristics.Key,java.lang.Object>> getAvailableCharacteristicsKeyValues();
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public long getMetadataVendorId(@NonNull String);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public abstract android.hardware.camera2.extension.SessionProcessor getSessionProcessor();
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public abstract java.util.Map<java.lang.Integer,java.util.List<android.util.Size>> getSupportedCaptureOutputResolutions(@NonNull String);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public abstract java.util.Map<java.lang.Integer,java.util.List<android.util.Size>> getSupportedPreviewOutputResolutions(@NonNull String);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public abstract void initialize(@NonNull String, @NonNull android.hardware.camera2.extension.CharacteristicsMap);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public abstract boolean isExtensionAvailable(@NonNull String, @NonNull android.hardware.camera2.extension.CharacteristicsMap);
+ public abstract class AdvancedExtender {
+ ctor public AdvancedExtender(@NonNull android.hardware.camera2.CameraManager);
+ method @NonNull public abstract java.util.List<android.hardware.camera2.CaptureRequest.Key> getAvailableCaptureRequestKeys(@NonNull String);
+ method @NonNull public abstract java.util.List<android.hardware.camera2.CaptureResult.Key> getAvailableCaptureResultKeys(@NonNull String);
+ method @NonNull public abstract java.util.List<android.util.Pair<android.hardware.camera2.CameraCharacteristics.Key,java.lang.Object>> getAvailableCharacteristicsKeyValues();
+ method public long getMetadataVendorId(@NonNull String);
+ method @NonNull public abstract android.hardware.camera2.extension.SessionProcessor getSessionProcessor();
+ method @NonNull public abstract java.util.Map<java.lang.Integer,java.util.List<android.util.Size>> getSupportedCaptureOutputResolutions(@NonNull String);
+ method @NonNull public abstract java.util.Map<java.lang.Integer,java.util.List<android.util.Size>> getSupportedPreviewOutputResolutions(@NonNull String);
+ method public abstract void initialize(@NonNull String, @NonNull android.hardware.camera2.extension.CharacteristicsMap);
+ method public abstract boolean isExtensionAvailable(@NonNull String, @NonNull android.hardware.camera2.extension.CharacteristicsMap);
}
- @FlaggedApi("com.android.internal.camera.flags.concert_mode") public abstract class CameraExtensionService extends android.app.Service {
- ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") protected CameraExtensionService();
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public abstract android.hardware.camera2.extension.AdvancedExtender onInitializeAdvancedExtension(int);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public abstract boolean onRegisterClient(@NonNull android.os.IBinder);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public abstract void onUnregisterClient(@NonNull android.os.IBinder);
+ public abstract class CameraExtensionService extends android.app.Service {
+ ctor protected CameraExtensionService();
+ method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
+ method @NonNull public abstract android.hardware.camera2.extension.AdvancedExtender onInitializeAdvancedExtension(int);
+ method public abstract boolean onRegisterClient(@NonNull android.os.IBinder);
+ method public abstract void onUnregisterClient(@NonNull android.os.IBinder);
}
- @FlaggedApi("com.android.internal.camera.flags.concert_mode") public final class CameraOutputSurface {
- ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public CameraOutputSurface(@NonNull android.view.Surface, @NonNull android.util.Size);
+ public final class CameraOutputSurface {
+ ctor public CameraOutputSurface(@NonNull android.view.Surface, @NonNull android.util.Size);
method public int getColorSpace();
method public long getDynamicRangeProfile();
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public int getImageFormat();
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public android.util.Size getSize();
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public android.view.Surface getSurface();
+ method public int getImageFormat();
+ method @NonNull public android.util.Size getSize();
+ method @NonNull public android.view.Surface getSurface();
method public void setDynamicRangeProfile(long);
}
- @FlaggedApi("com.android.internal.camera.flags.concert_mode") public class CharacteristicsMap {
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @Nullable public android.hardware.camera2.CameraCharacteristics get(@NonNull String);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public java.util.Set<java.lang.String> getCameraIds();
+ public class CharacteristicsMap {
+ method @Nullable public android.hardware.camera2.CameraCharacteristics get(@NonNull String);
+ method @NonNull public java.util.Set<java.lang.String> getCameraIds();
}
- @FlaggedApi("com.android.internal.camera.flags.concert_mode") public class ExtensionConfiguration {
- ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public ExtensionConfiguration(int, int, @NonNull java.util.List<android.hardware.camera2.extension.ExtensionOutputConfiguration>, @Nullable android.hardware.camera2.CaptureRequest);
+ public class ExtensionConfiguration {
+ ctor public ExtensionConfiguration(int, int, @NonNull java.util.List<android.hardware.camera2.extension.ExtensionOutputConfiguration>, @Nullable android.hardware.camera2.CaptureRequest);
method public void setColorSpace(int);
}
- @FlaggedApi("com.android.internal.camera.flags.concert_mode") public class ExtensionOutputConfiguration {
- ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public ExtensionOutputConfiguration(@NonNull java.util.List<android.hardware.camera2.extension.CameraOutputSurface>, int, @Nullable String, int);
+ public class ExtensionOutputConfiguration {
+ ctor public ExtensionOutputConfiguration(@NonNull java.util.List<android.hardware.camera2.extension.CameraOutputSurface>, int, @Nullable String, int);
}
- @FlaggedApi("com.android.internal.camera.flags.concert_mode") public final class RequestProcessor {
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public void abortCaptures();
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public int setRepeating(@NonNull android.hardware.camera2.extension.RequestProcessor.Request, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.extension.RequestProcessor.RequestCallback) throws android.hardware.camera2.CameraAccessException;
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public void stopRepeating();
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public int submit(@NonNull android.hardware.camera2.extension.RequestProcessor.Request, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.extension.RequestProcessor.RequestCallback) throws android.hardware.camera2.CameraAccessException;
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public int submitBurst(@NonNull java.util.List<android.hardware.camera2.extension.RequestProcessor.Request>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.extension.RequestProcessor.RequestCallback) throws android.hardware.camera2.CameraAccessException;
+ public final class RequestProcessor {
+ method public void abortCaptures();
+ method public int setRepeating(@NonNull android.hardware.camera2.extension.RequestProcessor.Request, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.extension.RequestProcessor.RequestCallback) throws android.hardware.camera2.CameraAccessException;
+ method public void stopRepeating();
+ method public int submit(@NonNull android.hardware.camera2.extension.RequestProcessor.Request, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.extension.RequestProcessor.RequestCallback) throws android.hardware.camera2.CameraAccessException;
+ method public int submitBurst(@NonNull java.util.List<android.hardware.camera2.extension.RequestProcessor.Request>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.extension.RequestProcessor.RequestCallback) throws android.hardware.camera2.CameraAccessException;
}
- @FlaggedApi("com.android.internal.camera.flags.concert_mode") public static final class RequestProcessor.Request {
- ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public RequestProcessor.Request(@NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<android.util.Pair<android.hardware.camera2.CaptureRequest.Key,java.lang.Object>>, int);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public java.util.List<android.util.Pair<android.hardware.camera2.CaptureRequest.Key,java.lang.Object>> getParameters();
+ public static final class RequestProcessor.Request {
+ ctor public RequestProcessor.Request(@NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<android.util.Pair<android.hardware.camera2.CaptureRequest.Key,java.lang.Object>>, int);
+ method @NonNull public java.util.List<android.util.Pair<android.hardware.camera2.CaptureRequest.Key,java.lang.Object>> getParameters();
}
- @FlaggedApi("com.android.internal.camera.flags.concert_mode") public static interface RequestProcessor.RequestCallback {
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public void onCaptureBufferLost(@NonNull android.hardware.camera2.extension.RequestProcessor.Request, long, int);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public void onCaptureCompleted(@NonNull android.hardware.camera2.extension.RequestProcessor.Request, @Nullable android.hardware.camera2.TotalCaptureResult);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public void onCaptureFailed(@NonNull android.hardware.camera2.extension.RequestProcessor.Request, @NonNull android.hardware.camera2.CaptureFailure);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public void onCaptureProgressed(@NonNull android.hardware.camera2.extension.RequestProcessor.Request, @NonNull android.hardware.camera2.CaptureResult);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public void onCaptureSequenceAborted(int);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public void onCaptureSequenceCompleted(int, long);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public void onCaptureStarted(@NonNull android.hardware.camera2.extension.RequestProcessor.Request, long, long);
+ public static interface RequestProcessor.RequestCallback {
+ method public void onCaptureBufferLost(@NonNull android.hardware.camera2.extension.RequestProcessor.Request, long, int);
+ method public void onCaptureCompleted(@NonNull android.hardware.camera2.extension.RequestProcessor.Request, @Nullable android.hardware.camera2.TotalCaptureResult);
+ method public void onCaptureFailed(@NonNull android.hardware.camera2.extension.RequestProcessor.Request, @NonNull android.hardware.camera2.CaptureFailure);
+ method public void onCaptureProgressed(@NonNull android.hardware.camera2.extension.RequestProcessor.Request, @NonNull android.hardware.camera2.CaptureResult);
+ method public void onCaptureSequenceAborted(int);
+ method public void onCaptureSequenceCompleted(int, long);
+ method public void onCaptureStarted(@NonNull android.hardware.camera2.extension.RequestProcessor.Request, long, long);
}
- @FlaggedApi("com.android.internal.camera.flags.concert_mode") public abstract class SessionProcessor {
- ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public SessionProcessor();
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public abstract void deInitSession(@NonNull android.os.IBinder);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public abstract android.hardware.camera2.extension.ExtensionConfiguration initSession(@NonNull android.os.IBinder, @NonNull String, @NonNull android.hardware.camera2.extension.CharacteristicsMap, @NonNull android.hardware.camera2.extension.CameraOutputSurface, @NonNull android.hardware.camera2.extension.CameraOutputSurface);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public abstract void onCaptureSessionEnd();
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public abstract void onCaptureSessionStart(@NonNull android.hardware.camera2.extension.RequestProcessor, @NonNull String);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public abstract void setParameters(@NonNull android.hardware.camera2.CaptureRequest);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public abstract int startMultiFrameCapture(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.extension.SessionProcessor.CaptureCallback);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public abstract int startRepeating(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.extension.SessionProcessor.CaptureCallback);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public abstract int startTrigger(@NonNull android.hardware.camera2.CaptureRequest, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.extension.SessionProcessor.CaptureCallback);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public abstract void stopRepeating();
+ public abstract class SessionProcessor {
+ ctor public SessionProcessor();
+ method public abstract void deInitSession(@NonNull android.os.IBinder);
+ method @NonNull public abstract android.hardware.camera2.extension.ExtensionConfiguration initSession(@NonNull android.os.IBinder, @NonNull String, @NonNull android.hardware.camera2.extension.CharacteristicsMap, @NonNull android.hardware.camera2.extension.CameraOutputSurface, @NonNull android.hardware.camera2.extension.CameraOutputSurface);
+ method public abstract void onCaptureSessionEnd();
+ method public abstract void onCaptureSessionStart(@NonNull android.hardware.camera2.extension.RequestProcessor, @NonNull String);
+ method public abstract void setParameters(@NonNull android.hardware.camera2.CaptureRequest);
+ method public abstract int startMultiFrameCapture(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.extension.SessionProcessor.CaptureCallback);
+ method public abstract int startRepeating(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.extension.SessionProcessor.CaptureCallback);
+ method public abstract int startTrigger(@NonNull android.hardware.camera2.CaptureRequest, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.extension.SessionProcessor.CaptureCallback);
+ method public abstract void stopRepeating();
}
- @FlaggedApi("com.android.internal.camera.flags.concert_mode") public static interface SessionProcessor.CaptureCallback {
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public void onCaptureCompleted(long, int, @NonNull java.util.Map<android.hardware.camera2.CaptureResult.Key,java.lang.Object>);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public void onCaptureFailed(int, int);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public void onCaptureProcessStarted(int);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public void onCaptureSequenceAborted(int);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public void onCaptureSequenceCompleted(int);
- method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public void onCaptureStarted(int, long);
+ public static interface SessionProcessor.CaptureCallback {
+ method public void onCaptureCompleted(long, int, @NonNull java.util.Map<android.hardware.camera2.CaptureResult.Key,java.lang.Object>);
+ method public void onCaptureFailed(int, int);
+ method public void onCaptureProcessStarted(int);
+ method public void onCaptureSequenceAborted(int);
+ method public void onCaptureSequenceCompleted(int);
+ method public void onCaptureStarted(int, long);
}
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index caf6992..72a68f8 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1797,18 +1797,20 @@
public class InputSettings {
method @FlaggedApi("com.android.hardware.input.keyboard_a11y_bounce_keys_flag") public static int getAccessibilityBounceKeysThreshold(@NonNull android.content.Context);
- method @FlaggedApi("com.android.hardware.input.keyboard_repeat_keys") public static int getAccessibilityRepeatKeysDelay(@NonNull android.content.Context);
- method @FlaggedApi("com.android.hardware.input.keyboard_repeat_keys") public static int getAccessibilityRepeatKeysTimeout(@NonNull android.content.Context);
method @FlaggedApi("com.android.hardware.input.keyboard_a11y_slow_keys_flag") public static int getAccessibilitySlowKeysThreshold(@NonNull android.content.Context);
+ method @FlaggedApi("com.android.input.flags.keyboard_repeat_keys") public static int getRepeatKeysDelay(@NonNull android.content.Context);
+ method @FlaggedApi("com.android.input.flags.keyboard_repeat_keys") public static int getRepeatKeysTimeout(@NonNull android.content.Context);
method @FlaggedApi("com.android.hardware.input.keyboard_a11y_mouse_keys") public static boolean isAccessibilityMouseKeysEnabled(@NonNull android.content.Context);
method @FlaggedApi("com.android.hardware.input.keyboard_a11y_sticky_keys_flag") public static boolean isAccessibilityStickyKeysEnabled(@NonNull android.content.Context);
+ method @FlaggedApi("com.android.input.flags.keyboard_repeat_keys") public static boolean isRepeatKeysEnabled(@NonNull android.content.Context);
method @FlaggedApi("com.android.hardware.input.keyboard_a11y_bounce_keys_flag") @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public static void setAccessibilityBounceKeysThreshold(@NonNull android.content.Context, int);
method @FlaggedApi("com.android.hardware.input.keyboard_a11y_mouse_keys") @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public static void setAccessibilityMouseKeysEnabled(@NonNull android.content.Context, boolean);
- method @FlaggedApi("com.android.hardware.input.keyboard_repeat_keys") @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public static void setAccessibilityRepeatKeysDelay(@NonNull android.content.Context, int);
- method @FlaggedApi("com.android.hardware.input.keyboard_repeat_keys") @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public static void setAccessibilityRepeatKeysTimeout(@NonNull android.content.Context, int);
method @FlaggedApi("com.android.hardware.input.keyboard_a11y_slow_keys_flag") @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public static void setAccessibilitySlowKeysThreshold(@NonNull android.content.Context, int);
method @FlaggedApi("com.android.hardware.input.keyboard_a11y_sticky_keys_flag") @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public static void setAccessibilityStickyKeysEnabled(@NonNull android.content.Context, boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void setMaximumObscuringOpacityForTouch(@NonNull android.content.Context, @FloatRange(from=0, to=1) float);
+ method @FlaggedApi("com.android.input.flags.keyboard_repeat_keys") @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public static void setRepeatKeysDelay(@NonNull android.content.Context, int);
+ method @FlaggedApi("com.android.input.flags.keyboard_repeat_keys") @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public static void setRepeatKeysEnabled(@NonNull android.content.Context, boolean);
+ method @FlaggedApi("com.android.input.flags.keyboard_repeat_keys") @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public static void setRepeatKeysTimeout(@NonNull android.content.Context, int);
field public static final int DEFAULT_POINTER_SPEED = 0; // 0x0
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5db79fe..3bc3a93 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -255,6 +255,7 @@
import libcore.io.IoUtils;
import libcore.io.Os;
import libcore.net.event.NetworkEventDispatcher;
+import libcore.util.NativeAllocationRegistry;
import org.apache.harmony.dalvik.ddmc.DdmVmInternal;
@@ -1610,6 +1611,32 @@
}
@NeverCompile
+ private void dumpMemInfoNativeAllocations(PrintWriter pw) {
+ pw.println(" ");
+ pw.println(" Native Allocations");
+ printRow(pw, TWO_COUNT_COLUMN_HEADER, "", "Count", "", "Total(kB)");
+ printRow(pw, TWO_COUNT_COLUMN_HEADER, "", "------", "", "------");
+
+ for (NativeAllocationRegistry.Metrics m : NativeAllocationRegistry.getMetrics()) {
+ // group into 3 major categories: Bitmap, HardwareBuffer and Other
+ final String className = switch (m.getClassName()) {
+ case "android.graphics.Bitmap" -> "Bitmap";
+ case "android.hardware.HardwareBuffer" -> "HardwareBuffer";
+ default -> "Other";
+ };
+
+ if (m.getMallocedCount() != 0 || m.getMallocedBytes() != 0) {
+ printRow(pw, TWO_COUNT_COLUMNS, className + " (malloced):",
+ m.getMallocedCount(), "", m.getMallocedBytes() / 1024);
+ }
+ if (m.getNonmallocedCount() != 0 || m.getNonmallocedBytes() != 0) {
+ printRow(pw, TWO_COUNT_COLUMNS, className + " (nonmalloced):",
+ m.getNonmallocedCount(), "", m.getNonmallocedBytes() / 1024);
+ }
+ }
+ }
+
+ @NeverCompile
private void dumpMemInfo(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin,
boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly,
boolean dumpUnreachable, boolean dumpAllocatorStats) {
@@ -1707,6 +1734,10 @@
printRow(pw, TWO_COUNT_COLUMNS, "Death Recipients:", binderDeathObjectCount,
"WebViews:", webviewInstanceCount);
+ if (com.android.libcore.Flags.nativeMetrics()) {
+ dumpMemInfoNativeAllocations(pw);
+ }
+
// SQLite mem info
pw.println(" ");
pw.println(" SQL");
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index dbf9afd..ed6b851 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -16,6 +16,7 @@
package android.app;
+import static android.app.PropertyInvalidatedCache.createSystemCacheKey;
import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_COLORED;
import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_NOT_COLORED;
import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
@@ -817,7 +818,7 @@
private final static PropertyInvalidatedCache<HasSystemFeatureQuery, Boolean>
mHasSystemFeatureCache =
new PropertyInvalidatedCache<HasSystemFeatureQuery, Boolean>(
- 256, "cache_key.has_system_feature") {
+ 256, createSystemCacheKey("has_system_feature")) {
@Override
public Boolean recompute(HasSystemFeatureQuery query) {
try {
@@ -1127,7 +1128,7 @@
}
private static final String CACHE_KEY_PACKAGES_FOR_UID_PROPERTY =
- "cache_key.get_packages_for_uid";
+ createSystemCacheKey("get_packages_for_uid");
private static final PropertyInvalidatedCache<Integer, GetPackagesForUidResult>
mGetPackagesForUidCache =
new PropertyInvalidatedCache<Integer, GetPackagesForUidResult>(
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 0c786cb..0e761fc 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -283,6 +284,12 @@
*/
/**
+ * The well-known key prefix.
+ * @hide
+ */
+ private static final String CACHE_KEY_PREFIX = "cache_key";
+
+ /**
* The module used for unit tests and cts tests. It is expected that no process in
* the system has permissions to write properties with this module.
* @hide
@@ -366,7 +373,44 @@
}
}
- return "cache_key." + module + "." + new String(suffix);
+ return CACHE_KEY_PREFIX + "." + module + "." + new String(suffix);
+ }
+
+ /**
+ * All legal keys start with one of the following strings.
+ */
+ private static final String[] sValidKeyPrefix = {
+ CACHE_KEY_PREFIX + "." + MODULE_SYSTEM + ".",
+ CACHE_KEY_PREFIX + "." + MODULE_BLUETOOTH + ".",
+ CACHE_KEY_PREFIX + "." + MODULE_TELEPHONY + ".",
+ CACHE_KEY_PREFIX + "." + MODULE_TEST + ".",
+ };
+
+ /**
+ * Verify that the property name conforms to the standard. Log a warning if this is not true.
+ * Note that this is done once in the cache constructor; it does not have to be very fast.
+ */
+ private void validateCacheKey(String name) {
+ if (Build.IS_USER) {
+ // Do not bother checking keys in user builds. The keys will have been tested in
+ // eng/userdebug builds already.
+ return;
+ }
+ for (int i = 0; i < sValidKeyPrefix.length; i++) {
+ if (name.startsWith(sValidKeyPrefix[i])) return;
+ }
+ Log.w(TAG, "invalid cache name: " + name);
+ }
+
+ /**
+ * Create a cache key for the system module. The parameter is the API name. This reduces
+ * some of the boilerplate in system caches. It is not needed in other modules because other
+ * modules must use the {@link IpcDataCache} interfaces.
+ * @hide
+ */
+ @NonNull
+ public static String createSystemCacheKey(@NonNull String api) {
+ return createPropertyName(MODULE_SYSTEM, api);
}
/**
@@ -561,6 +605,7 @@
public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName,
@NonNull String cacheName) {
mPropertyName = propertyName;
+ validateCacheKey(mPropertyName);
mCacheName = cacheName;
mMaxEntries = maxEntries;
mComputer = new DefaultComputer<>(this);
@@ -584,6 +629,7 @@
public PropertyInvalidatedCache(int maxEntries, @NonNull String module, @NonNull String api,
@NonNull String cacheName, @NonNull QueryHandler<Query, Result> computer) {
mPropertyName = createPropertyName(module, api);
+ validateCacheKey(mPropertyName);
mCacheName = cacheName;
mMaxEntries = maxEntries;
mComputer = computer;
diff --git a/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java b/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
index 36daaab..83b5aa0 100644
--- a/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
+++ b/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
@@ -164,7 +164,13 @@
*/
@Nullable
public Boolean getEnabled() {
- return (Boolean) getProperty(PROPERTY_ENABLED);
+ // We can't use getPropertyBoolean here. getPropertyBoolean returns false instead of null
+ // if the value is missing.
+ boolean[] enabled = getPropertyBooleanArray(PROPERTY_ENABLED);
+ if (enabled == null || enabled.length == 0) {
+ return null;
+ }
+ return enabled[0];
}
/** Returns the qualified id linking to the static metadata of the app function. */
@@ -201,11 +207,16 @@
/**
* Sets an indicator specifying if the function is enabled or not. This would override the
* default enabled state in the static metadata ({@link
- * AppFunctionStaticMetadataHelper#STATIC_PROPERTY_ENABLED_BY_DEFAULT}).
+ * AppFunctionStaticMetadataHelper#STATIC_PROPERTY_ENABLED_BY_DEFAULT}). Sets this to
+ * null to clear the override.
*/
@NonNull
- public Builder setEnabled(boolean enabled) {
- setPropertyBoolean(PROPERTY_ENABLED, enabled);
+ public Builder setEnabled(@Nullable Boolean enabled) {
+ if (enabled == null) {
+ setPropertyBoolean(PROPERTY_ENABLED);
+ } else {
+ setPropertyBoolean(PROPERTY_ENABLED, enabled);
+ }
return this;
}
diff --git a/core/java/android/app/appfunctions/AppFunctionService.java b/core/java/android/app/appfunctions/AppFunctionService.java
index c27141a..0d981ea 100644
--- a/core/java/android/app/appfunctions/AppFunctionService.java
+++ b/core/java/android/app/appfunctions/AppFunctionService.java
@@ -26,6 +26,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Service;
+import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
@@ -60,29 +61,53 @@
@NonNull
public static final String SERVICE_INTERFACE = "android.app.appfunctions.AppFunctionService";
- private final Binder mBinder =
- new IAppFunctionService.Stub() {
- @Override
- public void executeAppFunction(
- @NonNull ExecuteAppFunctionRequest request,
- @NonNull IExecuteAppFunctionCallback callback) {
- if (AppFunctionService.this.checkCallingPermission(BIND_APP_FUNCTION_SERVICE)
- == PERMISSION_DENIED) {
- throw new SecurityException("Can only be called by the system server.");
- }
- SafeOneTimeExecuteAppFunctionCallback safeCallback =
- new SafeOneTimeExecuteAppFunctionCallback(callback);
- try {
- AppFunctionService.this.onExecuteFunction(request, safeCallback::onResult);
- } catch (Exception ex) {
- // Apps should handle exceptions. But if they don't, report the error on
- // behalf of them.
- safeCallback.onResult(
- ExecuteAppFunctionResponse.newFailure(
- getResultCode(ex), ex.getMessage(), /* extras= */ null));
- }
+ /**
+ * Functional interface to represent the execution logic of an app function.
+ *
+ * @hide
+ */
+ @FunctionalInterface
+ public interface OnExecuteFunction {
+ /**
+ * Performs the semantic of executing the function specified by the provided request and
+ * return the response through the provided callback.
+ */
+ void perform(
+ @NonNull ExecuteAppFunctionRequest request,
+ @NonNull Consumer<ExecuteAppFunctionResponse> callback);
+ }
+
+ /** @hide */
+ @NonNull
+ public static Binder createBinder(
+ @NonNull Context context, @NonNull OnExecuteFunction onExecuteFunction) {
+ return new IAppFunctionService.Stub() {
+ @Override
+ public void executeAppFunction(
+ @NonNull ExecuteAppFunctionRequest request,
+ @NonNull IExecuteAppFunctionCallback callback) {
+ if (context.checkCallingPermission(BIND_APP_FUNCTION_SERVICE)
+ == PERMISSION_DENIED) {
+ throw new SecurityException("Can only be called by the system server.");
}
- };
+ SafeOneTimeExecuteAppFunctionCallback safeCallback =
+ new SafeOneTimeExecuteAppFunctionCallback(callback);
+ try {
+ onExecuteFunction.perform(request, safeCallback::onResult);
+ } catch (Exception ex) {
+ // Apps should handle exceptions. But if they don't, report the error on
+ // behalf of them.
+ safeCallback.onResult(
+ ExecuteAppFunctionResponse.newFailure(
+ getResultCode(ex), ex.getMessage(), /* extras= */ null));
+ }
+ }
+ };
+ }
+
+ private final Binder mBinder = createBinder(
+ AppFunctionService.this,
+ AppFunctionService.this::onExecuteFunction);
@NonNull
@Override
diff --git a/core/java/android/app/compat/ChangeIdStateCache.java b/core/java/android/app/compat/ChangeIdStateCache.java
index 7948cec..db663f8 100644
--- a/core/java/android/app/compat/ChangeIdStateCache.java
+++ b/core/java/android/app/compat/ChangeIdStateCache.java
@@ -16,6 +16,8 @@
package android.app.compat;
+import static android.app.PropertyInvalidatedCache.createSystemCacheKey;
+
import android.annotation.NonNull;
import android.app.PropertyInvalidatedCache;
import android.content.Context;
@@ -31,7 +33,7 @@
*/
public final class ChangeIdStateCache
extends PropertyInvalidatedCache<ChangeIdStateQuery, Boolean> {
- private static final String CACHE_KEY = "cache_key.is_compat_change_enabled";
+ private static final String CACHE_KEY = createSystemCacheKey("is_compat_change_enabled");
private static final int MAX_ENTRIES = 2048;
private static boolean sDisabled = false;
private volatile IPlatformCompat mPlatformCompat;
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index 9891e89..9b06adf 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -236,4 +236,12 @@
namespace: "systemui"
description: "Guards new android.app.richongoingnotification api"
bug: "337261753"
+}
+
+flag {
+ name: "ui_rich_ongoing"
+ is_exported: true
+ namespace: "systemui"
+ description: "Guards new android.app.richongoingnotification promotion and new uis"
+ bug: "337261753"
}
\ No newline at end of file
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 12c5d07..91f7a8b 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4324,6 +4324,7 @@
SECURITY_STATE_SERVICE,
//@hide: ECM_ENHANCED_CONFIRMATION_SERVICE,
CONTACT_KEYS_SERVICE,
+ RANGING_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
@@ -6402,6 +6403,17 @@
/**
* Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.ranging.RangingManager}.
+ *
+ * @see #getSystemService(String)
+ * @hide
+ */
+ @FlaggedApi(com.android.ranging.flags.Flags.FLAG_RANGING_STACK_ENABLED)
+ @SystemApi
+ public static final String RANGING_SERVICE = "ranging";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a
* {@link android.app.DreamManager} for controlling Dream states.
*
* @see #getSystemService(String)
diff --git a/core/java/android/content/pm/Android.bp b/core/java/android/content/pm/Android.bp
new file mode 100644
index 0000000..057b5da
--- /dev/null
+++ b/core/java/android/content/pm/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * 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 {
+ default_team: "trendy_team_framework_android_packages",
+ // 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"],
+}
+
+filegroup {
+ name: "framework-pm-sources",
+ srcs: [
+ "**/*.java",
+ "**/*.aidl",
+ ],
+ exclude_srcs: [
+ "dex/**/*.java",
+ "overlay/**/*.java",
+ "permission/**/*.java",
+ ],
+ visibility: ["//frameworks/base"],
+}
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index ffadd1e..2cdae21 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -206,6 +206,17 @@
]
},
{
+ "name": "CtsPackageInstallerCUJDeviceAdminTestCases",
+ "options":[
+ {
+ "exclude-annotation":"androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation":"org.junit.Ignore"
+ }
+ ]
+ },
+ {
"name": "CtsPackageInstallerCUJInstallationTestCases",
"options":[
{
@@ -217,6 +228,17 @@
]
},
{
+ "name": "CtsPackageInstallerCUJMultiUsersTestCases",
+ "options":[
+ {
+ "exclude-annotation":"androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation":"org.junit.Ignore"
+ }
+ ]
+ },
+ {
"name": "CtsPackageInstallerCUJUninstallationTestCases",
"options":[
{
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index 9b87df9..3cf508a 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -259,10 +259,8 @@
private static final String PROXY_SERVICE_NAME =
"com.android.cameraextensions.CameraExtensionsProxyService";
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
private static final int FALLBACK_PACKAGE_NAME =
com.android.internal.R.string.config_extensionFallbackPackageName;
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
private static final int FALLBACK_SERVICE_NAME =
com.android.internal.R.string.config_extensionFallbackServiceName;
@@ -309,7 +307,7 @@
intent.setClassName(vendorProxyPackage, vendorProxyService);
}
- if (Flags.concertMode() && useFallback) {
+ if (useFallback) {
String packageName = ctx.getResources().getString(FALLBACK_PACKAGE_NAME);
String serviceName = ctx.getResources().getString(FALLBACK_SERVICE_NAME);
@@ -433,7 +431,7 @@
releaseProxyConnectionLocked(ctx, extension);
}
- if (Flags.concertMode() && ret && useFallback && mIsFallbackEnabled) {
+ if (ret && useFallback && mIsFallbackEnabled) {
try {
InitializeSessionHandler cb = new InitializeSessionHandler(ctx);
initializeSession(cb, extension);
@@ -462,26 +460,24 @@
boolean ret = registerClientHelper(ctx, token, extension, false /*useFallback*/);
- if (Flags.concertMode()) {
- // Check if user enabled fallback impl
- ContentResolver resolver = ctx.getContentResolver();
- int userEnabled = Settings.Secure.getInt(resolver,
- Settings.Secure.CAMERA_EXTENSIONS_FALLBACK, 1);
+ // Check if user enabled fallback impl
+ ContentResolver resolver = ctx.getContentResolver();
+ int userEnabled = Settings.Secure.getInt(resolver,
+ Settings.Secure.CAMERA_EXTENSIONS_FALLBACK, 1);
- boolean vendorImpl = true;
- if (ret && (mConnectionManager.getProxy(extension) != null) && (userEnabled == 1)) {
- // At this point, we are connected to either CameraExtensionsProxyService or
- // the vendor extension proxy service. If the vendor does not support the
- // extension, unregisterClient and re-register client with the proxy service
- // containing the fallback impl
- vendorImpl = isExtensionSupported(cameraId, extension,
- characteristicsMapNative);
- }
+ boolean vendorImpl = true;
+ if (ret && (mConnectionManager.getProxy(extension) != null) && (userEnabled == 1)) {
+ // At this point, we are connected to either CameraExtensionsProxyService or
+ // the vendor extension proxy service. If the vendor does not support the
+ // extension, unregisterClient and re-register client with the proxy service
+ // containing the fallback impl
+ vendorImpl = isExtensionSupported(cameraId, extension,
+ characteristicsMapNative);
+ }
- if (!vendorImpl) {
- unregisterClient(ctx, token, extension);
- ret = registerClientHelper(ctx, token, extension, true /*useFallback*/);
- }
+ if (!vendorImpl) {
+ unregisterClient(ctx, token, extension);
+ ret = registerClientHelper(ctx, token, extension, true /*useFallback*/);
}
return ret;
diff --git a/core/java/android/hardware/camera2/CameraExtensionSession.java b/core/java/android/hardware/camera2/CameraExtensionSession.java
index 2d9433e..20f89a55 100644
--- a/core/java/android/hardware/camera2/CameraExtensionSession.java
+++ b/core/java/android/hardware/camera2/CameraExtensionSession.java
@@ -156,7 +156,6 @@
* @see #capture
* @see #setRepeatingRequest
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public void onCaptureFailed(@NonNull CameraExtensionSession session,
@NonNull CaptureRequest request, @CaptureFailure.FailureReason int failure) {
// default empty implementation
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index d40b2e3..2162792 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -818,7 +818,7 @@
}
boolean hasConcurrentStreams =
- CameraManagerGlobal.get().cameraIdHasConcurrentStreamsLocked(cameraId,
+ CameraManagerGlobal.get().cameraIdHasConcurrentStreams(cameraId,
mContext.getDeviceId(), getDevicePolicyFromContext(mContext));
metadata.setHasMandatoryConcurrentStreams(hasConcurrentStreams);
@@ -2629,24 +2629,26 @@
* @return Whether the camera device was found in the set of combinations returned by
* getConcurrentCameraIds
*/
- public boolean cameraIdHasConcurrentStreamsLocked(String cameraId, int deviceId,
+ public boolean cameraIdHasConcurrentStreams(String cameraId, int deviceId,
int devicePolicy) {
- DeviceCameraInfo info = new DeviceCameraInfo(cameraId,
- devicePolicy == DEVICE_POLICY_DEFAULT ? DEVICE_ID_DEFAULT : deviceId);
- if (!mDeviceStatus.containsKey(info)) {
- // physical camera ids aren't advertised in concurrent camera id combinations.
- if (DEBUG) {
- Log.v(TAG, " physical camera id " + cameraId + " is hidden." +
- " Available logical camera ids : " + mDeviceStatus);
+ synchronized (mLock) {
+ DeviceCameraInfo info = new DeviceCameraInfo(cameraId,
+ devicePolicy == DEVICE_POLICY_DEFAULT ? DEVICE_ID_DEFAULT : deviceId);
+ if (!mDeviceStatus.containsKey(info)) {
+ // physical camera ids aren't advertised in concurrent camera id combinations.
+ if (DEBUG) {
+ Log.v(TAG, " physical camera id " + cameraId + " is hidden."
+ + " Available logical camera ids : " + mDeviceStatus);
+ }
+ return false;
+ }
+ for (Set<DeviceCameraInfo> comb : mConcurrentCameraIdCombinations) {
+ if (comb.contains(info)) {
+ return true;
+ }
}
return false;
}
- for (Set<DeviceCameraInfo> comb : mConcurrentCameraIdCombinations) {
- if (comb.contains(info)) {
- return true;
- }
- }
- return false;
}
public void setTorchMode(
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 75d617c..a18a634 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -5293,7 +5293,6 @@
@PublicKey
@NonNull
@SyntheticKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public static final Key<android.hardware.camera2.params.LensIntrinsicsSample[]> STATISTICS_LENS_INTRINSICS_SAMPLES =
new Key<android.hardware.camera2.params.LensIntrinsicsSample[]>("android.statistics.lensIntrinsicsSamples", android.hardware.camera2.params.LensIntrinsicsSample[].class);
@@ -5307,7 +5306,6 @@
* @see CaptureResult#SENSOR_TIMESTAMP
* @hide
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public static final Key<long[]> STATISTICS_LENS_INTRINSIC_TIMESTAMPS =
new Key<long[]>("android.statistics.lensIntrinsicTimestamps", long[].class);
@@ -5323,7 +5321,6 @@
* @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
* @hide
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public static final Key<float[]> STATISTICS_LENS_INTRINSIC_SAMPLES =
new Key<float[]>("android.statistics.lensIntrinsicSamples", float[].class);
@@ -5814,7 +5811,6 @@
*/
@PublicKey
@NonNull
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public static final Key<android.graphics.Rect> LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION =
new Key<android.graphics.Rect>("android.logicalMultiCamera.activePhysicalSensorCropRegion", android.graphics.Rect.class);
diff --git a/core/java/android/hardware/camera2/extension/AdvancedExtender.java b/core/java/android/hardware/camera2/extension/AdvancedExtender.java
index 8fa09a8..df66f59 100644
--- a/core/java/android/hardware/camera2/extension/AdvancedExtender.java
+++ b/core/java/android/hardware/camera2/extension/AdvancedExtender.java
@@ -53,7 +53,6 @@
* @hide
*/
@SystemApi
-@FlaggedApi(Flags.FLAG_CONCERT_MODE)
public abstract class AdvancedExtender {
private HashMap<String, Long> mMetadataVendorIdMap = new HashMap<>();
private final CameraManager mCameraManager;
@@ -66,7 +65,6 @@
*
* @param cameraManager the system camera manager
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public AdvancedExtender(@NonNull CameraManager cameraManager) {
mCameraManager = cameraManager;
try {
@@ -101,7 +99,6 @@
* @param cameraId The camera2 id string of the camera.
* @return the camera metadata vendor Id associated with the given camera
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public long getMetadataVendorId(@NonNull String cameraId) {
long vendorId = mMetadataVendorIdMap.containsKey(cameraId) ?
mMetadataVendorIdMap.get(cameraId) : Long.MAX_VALUE;
@@ -123,7 +120,6 @@
* CameraCharacteristics.
* @return true if the extension is supported, otherwise false
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public abstract boolean isExtensionAvailable(@NonNull String cameraId,
@NonNull CharacteristicsMap charsMap);
@@ -144,7 +140,6 @@
* physical camera ids and their
* CameraCharacteristics.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public abstract void initialize(@NonNull String cameraId, @NonNull CharacteristicsMap map);
/**
@@ -159,7 +154,6 @@
* be identical to the supported preview output format returned here.
* @param cameraId The camera2 id string of the camera.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
@NonNull
public abstract Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(
@NonNull String cameraId);
@@ -179,7 +173,6 @@
* writes the output to the output surface.
* @param cameraId The camera2 id string of the camera.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
@NonNull
public abstract Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
@NonNull String cameraId);
@@ -189,7 +182,6 @@
* implements all the interactions required for starting an extension
* and cleanup.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
@NonNull
public abstract SessionProcessor getSessionProcessor();
@@ -227,7 +219,6 @@
* @return The list of supported orthogonal capture keys, or empty
* list if no capture settings are not supported.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
@NonNull
public abstract List<CaptureRequest.Key> getAvailableCaptureRequestKeys(
@NonNull String cameraId);
@@ -245,7 +236,6 @@
* @return The list of supported capture result keys, or
* empty list if capture results are not supported.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
@NonNull
public abstract List<CaptureResult.Key> getAvailableCaptureResultKeys(
@NonNull String cameraId);
@@ -270,7 +260,6 @@
* {@link CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP} and
* {@link CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP}.
*/
- @FlaggedApi(Flags.FLAG_CAMERA_EXTENSIONS_CHARACTERISTICS_GET)
@NonNull
public abstract List<Pair<CameraCharacteristics.Key, Object>>
getAvailableCharacteristicsKeyValues();
@@ -377,7 +366,6 @@
return false;
}
- @FlaggedApi(Flags.FLAG_CAMERA_EXTENSIONS_CHARACTERISTICS_GET)
@Override
public CameraMetadataNative getAvailableCharacteristicsKeyValues(String cameraId) {
List<Pair<CameraCharacteristics.Key, Object>> entries =
diff --git a/core/java/android/hardware/camera2/extension/CameraExtensionService.java b/core/java/android/hardware/camera2/extension/CameraExtensionService.java
index 01698d5..9cc4f16 100644
--- a/core/java/android/hardware/camera2/extension/CameraExtensionService.java
+++ b/core/java/android/hardware/camera2/extension/CameraExtensionService.java
@@ -42,7 +42,6 @@
* @hide
*/
@SystemApi
-@FlaggedApi(Flags.FLAG_CONCERT_MODE)
public abstract class CameraExtensionService extends Service {
private static final String TAG = "CameraExtensionService";
private CameraUsageTracker mCameraUsageTracker;
@@ -87,10 +86,8 @@
}
};
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
protected CameraExtensionService() { }
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
@Override
@NonNull
public final IBinder onBind(@Nullable Intent intent) {
@@ -186,7 +183,6 @@
* unexpectedly.
* @return true if the registration is successful, false otherwise
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public abstract boolean onRegisterClient(@NonNull IBinder token);
/**
@@ -194,7 +190,6 @@
*
* @param token Binder token
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public abstract void onUnregisterClient(@NonNull IBinder token);
/**
@@ -204,7 +199,6 @@
* extension type
* @return Valid advanced extender of the requested type
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
@NonNull
public abstract AdvancedExtender onInitializeAdvancedExtension(@Extension int extensionType);
}
diff --git a/core/java/android/hardware/camera2/extension/CameraOutputSurface.java b/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
index 32139b8..e8b20e3 100644
--- a/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
+++ b/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
@@ -42,11 +42,9 @@
* @hide
*/
@SystemApi
-@FlaggedApi(Flags.FLAG_CONCERT_MODE)
public final class CameraOutputSurface {
private final OutputSurface mOutputSurface;
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
CameraOutputSurface(@NonNull OutputSurface surface) {
mOutputSurface = surface;
}
@@ -59,7 +57,6 @@
* @param size Requested size of the camera
* output
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public CameraOutputSurface(@NonNull Surface surface,
@NonNull Size size) {
mOutputSurface = new OutputSurface();
@@ -75,7 +72,6 @@
/**
* Return the current output {@link Surface}
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
@NonNull
public Surface getSurface() {
return mOutputSurface.surface;
@@ -84,7 +80,6 @@
/**
* Return the current requested output size
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
@NonNull
public android.util.Size getSize() {
if (mOutputSurface.size != null) {
@@ -96,7 +91,6 @@
/**
* Return the current surface output {@link android.graphics.ImageFormat}
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public @ImageFormat.Format int getImageFormat() {
return mOutputSurface.imageFormat;
}
diff --git a/core/java/android/hardware/camera2/extension/CharacteristicsMap.java b/core/java/android/hardware/camera2/extension/CharacteristicsMap.java
index 495abc8..e578f6e 100644
--- a/core/java/android/hardware/camera2/extension/CharacteristicsMap.java
+++ b/core/java/android/hardware/camera2/extension/CharacteristicsMap.java
@@ -36,7 +36,6 @@
* @hide
*/
@SystemApi
-@FlaggedApi(Flags.FLAG_CONCERT_MODE)
public class CharacteristicsMap {
private final HashMap<String, CameraCharacteristics> mCharMap;
@@ -46,7 +45,6 @@
* @param charsMap Maps camera ids to respective
* {@link CameraCharacteristics}
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
CharacteristicsMap(@NonNull Map<String, CameraMetadataNative> charsMap) {
mCharMap = new HashMap<>();
for (Map.Entry<String, CameraMetadataNative> entry : charsMap.entrySet()) {
@@ -59,7 +57,6 @@
*
* @return Set of the camera ids stored in the map
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
@NonNull
public Set<String> getCameraIds() {
return mCharMap.keySet();
@@ -74,7 +71,6 @@
* @return Valid {@link CameraCharacteristics} instance of null
* in case the camera id is not part of the map
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
@Nullable
public CameraCharacteristics get(@NonNull String cameraId) {
return mCharMap.get(cameraId);
diff --git a/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java b/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java
index 32de1ce..43dfaa5 100644
--- a/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java
+++ b/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java
@@ -43,7 +43,6 @@
* @hide
*/
@SystemApi
-@FlaggedApi(Flags.FLAG_CONCERT_MODE)
public class ExtensionConfiguration {
private final int mSessionType;
private final int mSessionTemplateId;
@@ -65,7 +64,6 @@
* @param sessionParams An optional set of camera capture
* session parameter values
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public ExtensionConfiguration(@CameraDevice.SessionOperatingMode int sessionType,
@CameraDevice.RequestTemplate int sessionTemplateId,
@NonNull List<ExtensionOutputConfiguration> outputs,
@@ -87,7 +85,6 @@
mColorSpace = colorSpace;
}
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
CameraSessionConfig getCameraSessionConfig() {
if (mOutputs.isEmpty()) {
return null;
diff --git a/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java b/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java
index 8a47430..ff0d8d7b 100644
--- a/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java
+++ b/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java
@@ -35,7 +35,6 @@
* @hide
*/
@SystemApi
-@FlaggedApi(Flags.FLAG_CONCERT_MODE)
public class ExtensionOutputConfiguration {
private final List<CameraOutputSurface> mSurfaces;
private final String mPhysicalCameraId;
@@ -57,7 +56,6 @@
* @param surfaceGroupId In case of surface group, this field must
* contain the surface group id
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public ExtensionOutputConfiguration(@NonNull List<CameraOutputSurface> outputs,
int outputConfigId, @Nullable String physicalCameraId, int surfaceGroupId) {
mSurfaces = outputs;
diff --git a/core/java/android/hardware/camera2/extension/RequestProcessor.java b/core/java/android/hardware/camera2/extension/RequestProcessor.java
index 0ad27c2..936d57b 100644
--- a/core/java/android/hardware/camera2/extension/RequestProcessor.java
+++ b/core/java/android/hardware/camera2/extension/RequestProcessor.java
@@ -45,19 +45,16 @@
* @hide
*/
@SystemApi
-@FlaggedApi(Flags.FLAG_CONCERT_MODE)
public final class RequestProcessor {
private final static String TAG = "RequestProcessor";
private final IRequestProcessorImpl mRequestProcessor;
private final long mVendorId;
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
RequestProcessor (@NonNull IRequestProcessorImpl requestProcessor, long vendorId) {
mRequestProcessor = requestProcessor;
mVendorId = vendorId;
}
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public interface RequestCallback {
/**
* This method is called when the camera device has started
@@ -76,7 +73,6 @@
* @param frameNumber the frame number for this capture
*
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
void onCaptureStarted(@NonNull Request request, long frameNumber, long timestamp);
/**
@@ -117,7 +113,6 @@
* which includes a subset of the {@link
* TotalCaptureResult} fields.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
void onCaptureProgressed(@NonNull Request request, @NonNull CaptureResult partialResult);
/**
@@ -138,7 +133,6 @@
* parameters and the state of the camera
* system during capture.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
void onCaptureCompleted(@NonNull Request request,
@Nullable TotalCaptureResult totalCaptureResult);
@@ -163,7 +157,6 @@
* @param failure The output failure from the capture, including the
* failure reason and the frame number.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
void onCaptureFailed(@NonNull Request request, @NonNull CaptureFailure failure);
/**
@@ -182,7 +175,6 @@
* @param outputStreamId The output stream id that the buffer will not
* be produced for
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
void onCaptureBufferLost(@NonNull Request request, long frameNumber, int outputStreamId);
/**
@@ -203,7 +195,6 @@
* or {@link CaptureFailure#getFrameNumber}) in
* the capture sequence.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
void onCaptureSequenceCompleted(int sequenceId, long frameNumber);
/**
@@ -221,17 +212,14 @@
* @param sequenceId A sequence ID returned by the RequestProcessor
* capture family of methods
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
void onCaptureSequenceAborted(int sequenceId);
}
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public final static class Request {
private final List<Integer> mOutputIds;
private final List<Pair<CaptureRequest.Key, Object>> mParameters;
private final @CameraDevice.RequestTemplate int mTemplateId;
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public Request(@NonNull List<Integer> outputConfigIds,
@NonNull List<Pair<CaptureRequest.Key, Object>> parameters,
@CameraDevice.RequestTemplate int templateId) {
@@ -244,7 +232,6 @@
* Gets the target ids of {@link ExtensionOutputConfiguration} which identifies
* corresponding Surface to be the targeted for the request.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
@NonNull
List<Integer> getOutputConfigIds() {
return mOutputIds;
@@ -253,7 +240,6 @@
/**
* Gets all the parameters.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
@NonNull
public List<Pair<CaptureRequest.Key, Object>> getParameters() {
return mParameters;
@@ -265,7 +251,6 @@
*
* @see CameraDevice.RequestTemplate
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
Integer getTemplateId() {
return mTemplateId;
}
@@ -322,7 +307,6 @@
* @param callback Request callback implementation
* @return the id of the capture sequence
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public int submit(@NonNull Request request, @NonNull Executor executor,
@NonNull RequestCallback callback) throws CameraAccessException {
ArrayList<Request> requests = new ArrayList<>(1);
@@ -355,7 +339,6 @@
* @param callback Request callback implementation
* @return the id of the capture sequence
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public int submitBurst(@NonNull List<Request> requests, @NonNull Executor executor,
@NonNull RequestCallback callback) throws CameraAccessException {
List<android.hardware.camera2.extension.Request> parcelableRequests =
@@ -386,7 +369,6 @@
* @param callback Request callback implementation
* @return the id of the capture sequence
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public int setRepeating(@NonNull Request request, @NonNull Executor executor,
@NonNull RequestCallback callback) throws CameraAccessException {
ArrayList<Request> requests = new ArrayList<>(1);
@@ -413,7 +395,6 @@
/**
* Abort all ongoing capture requests.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public void abortCaptures() {
try {
mRequestProcessor.abortCaptures();
@@ -425,7 +406,6 @@
/**
* Stop the current repeating request.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public void stopRepeating() {
try {
mRequestProcessor.stopRepeating();
diff --git a/core/java/android/hardware/camera2/extension/SessionProcessor.java b/core/java/android/hardware/camera2/extension/SessionProcessor.java
index eead4ef..cf9f30d 100644
--- a/core/java/android/hardware/camera2/extension/SessionProcessor.java
+++ b/core/java/android/hardware/camera2/extension/SessionProcessor.java
@@ -76,7 +76,6 @@
* @hide
*/
@SystemApi
-@FlaggedApi(Flags.FLAG_CONCERT_MODE)
public abstract class SessionProcessor {
private static final String TAG = "SessionProcessor";
private CameraUsageTracker mCameraUsageTracker;
@@ -84,7 +83,6 @@
/**
* Initialize a session process instance
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public SessionProcessor() {}
void setCameraUsageTracker(CameraUsageTracker tracker) {
@@ -97,7 +95,6 @@
* @hide
*/
@SystemApi
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public interface CaptureCallback {
/**
* This method is called when the camera device has started
@@ -116,7 +113,6 @@
* first frame in a multi-frame capture,
* in nanoseconds.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
void onCaptureStarted(int captureSequenceId, long timestamp);
/**
@@ -126,7 +122,6 @@
*
* @param captureSequenceId id of the current capture sequence
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
void onCaptureProcessStarted(int captureSequenceId);
/**
@@ -139,7 +134,6 @@
* @param captureSequenceId id of the current capture sequence
* @param failure The capture failure reason
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
void onCaptureFailed(int captureSequenceId, @CaptureFailure.FailureReason int failure);
/**
@@ -154,7 +148,6 @@
*
* @param captureSequenceId id of the current capture sequence
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
void onCaptureSequenceCompleted(int captureSequenceId);
/**
@@ -162,7 +155,6 @@
*
* @param captureSequenceId id of the current capture sequence
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
void onCaptureSequenceAborted(int captureSequenceId);
/**
@@ -192,7 +184,6 @@
* settings and results are always supported and
* applied by the corresponding framework.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
void onCaptureCompleted(long shutterTimestamp, int requestId,
@NonNull Map<CaptureResult.Key, Object> results);
}
@@ -231,7 +222,6 @@
* ensure this list will always produce a valid camera capture
* session.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
@NonNull
public abstract ExtensionConfiguration initSession(@NonNull IBinder token,
@NonNull String cameraId, @NonNull CharacteristicsMap map,
@@ -247,7 +237,6 @@
* @param token Binder token that can be used to unlink any previously
* linked death notifier callbacks
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public abstract void deInitSession(@NonNull IBinder token);
/**
@@ -268,7 +257,6 @@
*
*
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public abstract void onCaptureSessionStart(@NonNull RequestProcessor requestProcessor,
@NonNull String statsKey);
@@ -279,7 +267,6 @@
* will no longer accept any requests after onCaptureSessionEnd()
* returns.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public abstract void onCaptureSessionEnd();
/**
@@ -293,7 +280,6 @@
* @param callback a callback to report the status.
* @return the id of the capture sequence.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public abstract int startRepeating(@NonNull Executor executor,
@NonNull CaptureCallback callback);
@@ -305,7 +291,6 @@
* forward calling {@link RequestProcessor#setRepeating} will simply
* do nothing.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public abstract void stopRepeating();
/**
@@ -326,7 +311,6 @@
* @param callback a callback to report the status.
* @return the id of the capture sequence.
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public abstract int startMultiFrameCapture(@NonNull Executor executor,
@NonNull CaptureCallback callback);
@@ -338,7 +322,6 @@
* the value.
*@param captureRequest Request that includes all client parameter
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public abstract void setParameters(@NonNull CaptureRequest captureRequest);
/**
@@ -357,7 +340,6 @@
* @return the id of the capture sequence.
*
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public abstract int startTrigger(@NonNull CaptureRequest captureRequest,
@NonNull Executor executor, @NonNull CaptureCallback callback);
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index 323712d..fc03b51 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -873,17 +873,15 @@
@Override
public void onCaptureProcessFailed(int captureSequenceId, int captureFailureReason) {
- if (Flags.concertMode()) {
- final long ident = Binder.clearCallingIdentity();
- try {
- mClientExecutor.execute(
- () -> mClientCallbacks.onCaptureFailed(
- CameraAdvancedExtensionSessionImpl.this, mClientRequest,
- captureFailureReason
- ));
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mClientExecutor.execute(
+ () -> mClientCallbacks.onCaptureFailed(
+ CameraAdvancedExtensionSessionImpl.this, mClientRequest,
+ captureFailureReason
+ ));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 0cd1c8c..ef7f3f8 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -1797,57 +1797,49 @@
return false;
}
- if (Flags.concertMode()) {
- long[] tsArray = new long[samples.length];
- float[] intrinsicsArray = new float[samples.length * 5];
- for (int i = 0; i < samples.length; i++) {
- tsArray[i] = samples[i].getTimestampNanos();
- System.arraycopy(samples[i].getLensIntrinsics(), 0, intrinsicsArray, 5 * i, 5);
+ long[] tsArray = new long[samples.length];
+ float[] intrinsicsArray = new float[samples.length * 5];
+ for (int i = 0; i < samples.length; i++) {
+ tsArray[i] = samples[i].getTimestampNanos();
+ System.arraycopy(samples[i].getLensIntrinsics(), 0, intrinsicsArray, 5 * i, 5);
- }
- setBase(CaptureResult.STATISTICS_LENS_INTRINSIC_SAMPLES, intrinsicsArray);
- setBase(CaptureResult.STATISTICS_LENS_INTRINSIC_TIMESTAMPS, tsArray);
-
- return true;
- } else {
- return false;
}
+ setBase(CaptureResult.STATISTICS_LENS_INTRINSIC_SAMPLES, intrinsicsArray);
+ setBase(CaptureResult.STATISTICS_LENS_INTRINSIC_TIMESTAMPS, tsArray);
+
+ return true;
}
private LensIntrinsicsSample[] getLensIntrinsicSamples() {
- if (Flags.concertMode()) {
- long[] timestamps = getBase(CaptureResult.STATISTICS_LENS_INTRINSIC_TIMESTAMPS);
- float[] intrinsics = getBase(CaptureResult.STATISTICS_LENS_INTRINSIC_SAMPLES);
+ long[] timestamps = getBase(CaptureResult.STATISTICS_LENS_INTRINSIC_TIMESTAMPS);
+ float[] intrinsics = getBase(CaptureResult.STATISTICS_LENS_INTRINSIC_SAMPLES);
- if (timestamps == null) {
- if (intrinsics != null) {
- throw new AssertionError("timestamps is null but intrinsics is not");
- }
-
- return null;
+ if (timestamps == null) {
+ if (intrinsics != null) {
+ throw new AssertionError("timestamps is null but intrinsics is not");
}
- if (intrinsics == null) {
- throw new AssertionError("timestamps is not null but intrinsics is");
- } else if ((intrinsics.length % 5) != 0) {
- throw new AssertionError("intrinsics are not multiple of 5");
- }
-
- if ((intrinsics.length / 5) != timestamps.length) {
- throw new AssertionError(String.format(
- "timestamps has %d entries but intrinsics has %d", timestamps.length,
- intrinsics.length / 5));
- }
-
- LensIntrinsicsSample[] samples = new LensIntrinsicsSample[timestamps.length];
- for (int i = 0; i < timestamps.length; i++) {
- float[] currentIntrinsic = Arrays.copyOfRange(intrinsics, 5 * i, 5 * i + 5);
- samples[i] = new LensIntrinsicsSample(timestamps[i], currentIntrinsic);
- }
- return samples;
- } else {
return null;
}
+
+ if (intrinsics == null) {
+ throw new AssertionError("timestamps is not null but intrinsics is");
+ } else if ((intrinsics.length % 5) != 0) {
+ throw new AssertionError("intrinsics are not multiple of 5");
+ }
+
+ if ((intrinsics.length / 5) != timestamps.length) {
+ throw new AssertionError(String.format(
+ "timestamps has %d entries but intrinsics has %d", timestamps.length,
+ intrinsics.length / 5));
+ }
+
+ LensIntrinsicsSample[] samples = new LensIntrinsicsSample[timestamps.length];
+ for (int i = 0; i < timestamps.length; i++) {
+ float[] currentIntrinsic = Arrays.copyOfRange(intrinsics, 5 * i, 5 * i + 5);
+ samples[i] = new LensIntrinsicsSample(timestamps[i], currentIntrinsic);
+ }
+ return samples;
}
private Capability[] getExtendedSceneModeCapabilities() {
diff --git a/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java b/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java
index 9a4ec5c..9157ef10 100644
--- a/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java
+++ b/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java
@@ -31,7 +31,6 @@
* Immutable class to store an
* {@link CaptureResult#STATISTICS_LENS_INTRINSICS_SAMPLES lens intrinsics intra-frame sample}.
*/
-@FlaggedApi(Flags.FLAG_CONCERT_MODE)
public final class LensIntrinsicsSample {
/**
* Create a new {@link LensIntrinsicsSample}.
@@ -46,7 +45,6 @@
*
* @throws IllegalArgumentException if lensIntrinsics length is different from 5
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public LensIntrinsicsSample(final long timestampNs, @NonNull final float[] lensIntrinsics) {
mTimestampNs = timestampNs;
Preconditions.checkArgument(lensIntrinsics.length == 5);
@@ -61,7 +59,6 @@
*
* @return a long value (guaranteed to be finite)
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
public long getTimestampNanos() {
return mTimestampNs;
}
@@ -72,7 +69,6 @@
* @return a floating point value (guaranteed to be finite)
* @see CaptureResult#LENS_INTRINSIC_CALIBRATION
*/
- @FlaggedApi(Flags.FLAG_CONCERT_MODE)
@NonNull
public float[] getLensIntrinsics() {
return mLensIntrinsics;
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 9612a53..7185719 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -1445,7 +1445,7 @@
* system's display configuration.
*/
public static final String CACHE_KEY_DISPLAY_INFO_PROPERTY =
- "cache_key.display_info";
+ PropertyInvalidatedCache.createSystemCacheKey("display_info");
/**
* Invalidates the contents of the display info cache for all applications. Can only
diff --git a/core/java/android/hardware/fingerprint/FingerprintCallback.java b/core/java/android/hardware/fingerprint/FingerprintCallback.java
index e4fbe6e..24e9f9d 100644
--- a/core/java/android/hardware/fingerprint/FingerprintCallback.java
+++ b/core/java/android/hardware/fingerprint/FingerprintCallback.java
@@ -189,7 +189,7 @@
mEnrollmentCallback.onAcquired(acquireInfo == FINGERPRINT_ACQUIRED_GOOD);
}
final String msg = getAcquiredString(context, acquireInfo, vendorCode);
- if (msg == null) {
+ if (msg == null || msg.isEmpty()) {
return;
}
// emulate HAL 2.1 behavior and send real acquiredInfo
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index 8592ded..177ee6f 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -20,15 +20,15 @@
import static com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_MOUSE_KEYS;
import static com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_SLOW_KEYS_FLAG;
import static com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_STICKY_KEYS_FLAG;
-import static com.android.hardware.input.Flags.FLAG_KEYBOARD_REPEAT_KEYS;
import static com.android.hardware.input.Flags.keyboardA11yBounceKeysFlag;
import static com.android.hardware.input.Flags.keyboardA11ySlowKeysFlag;
import static com.android.hardware.input.Flags.keyboardA11yStickyKeysFlag;
import static com.android.hardware.input.Flags.keyboardA11yMouseKeys;
-import static com.android.hardware.input.Flags.keyboardRepeatKeys;
import static com.android.hardware.input.Flags.touchpadTapDragging;
import static com.android.hardware.input.Flags.touchpadVisualizer;
import static com.android.input.flags.Flags.enableInputFilterRustImpl;
+import static com.android.input.flags.Flags.FLAG_KEYBOARD_REPEAT_KEYS;
+import static com.android.input.flags.Flags.keyboardRepeatKeys;
import android.Manifest;
import android.annotation.FlaggedApi;
@@ -800,7 +800,7 @@
*
* <p>
* ‘Repeat keys’ is a feature which allows users to generate key repeats when a particular
- * key on the physical keyboard is held down. This accessibility feature allows the user
+ * key on the physical keyboard is held down. This feature allows the user
* to configure the timeout before the key repeats begin as well as the delay
* between successive key repeats.
* </p>
@@ -812,7 +812,31 @@
}
/**
- * Get Accessibility repeat keys timeout duration in milliseconds.
+ * Whether "Repeat keys" feature is enabled.
+ * Repeat keys is ON by default.
+ * The repeat keys timeout and delay would have the default values in the default ON case.
+ *
+ * <p>
+ * 'Repeat keys’ is a feature which allows users to generate key repeats when a particular
+ * key on the physical keyboard is held down. This feature allows the user
+ * to configure the timeout before the key repeats begin as well as the delay
+ * between successive key repeats.
+ * </p>
+ *
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(FLAG_KEYBOARD_REPEAT_KEYS)
+ public static boolean isRepeatKeysEnabled(@NonNull Context context) {
+ if (!isRepeatKeysFeatureFlagEnabled()) {
+ return true;
+ }
+ return Settings.Secure.getIntForUser(context.getContentResolver(),
+ Settings.Secure.KEY_REPEAT_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
+ }
+
+ /**
+ * Get repeat keys timeout duration in milliseconds.
* The default key repeat timeout is {@link ViewConfiguration#DEFAULT_KEY_REPEAT_TIMEOUT_MS}.
*
* @param context The application context
@@ -823,7 +847,7 @@
*
* <p>
* ‘Repeat keys’ is a feature which allows users to generate key repeats when a particular
- * key on the physical keyboard is held down. This accessibility feature allows the user
+ * key on the physical keyboard is held down. This feature allows the user
* to configure the timeout before the key repeats begin as well as the delay
* between successive key repeats.
* </p>
@@ -832,14 +856,17 @@
*/
@TestApi
@FlaggedApi(FLAG_KEYBOARD_REPEAT_KEYS)
- public static int getAccessibilityRepeatKeysTimeout(@NonNull Context context) {
+ public static int getRepeatKeysTimeout(@NonNull Context context) {
+ if (!isRepeatKeysFeatureFlagEnabled()) {
+ return ViewConfiguration.getKeyRepeatTimeout();
+ }
return Settings.Secure.getIntForUser(context.getContentResolver(),
Settings.Secure.KEY_REPEAT_TIMEOUT_MS, ViewConfiguration.getKeyRepeatTimeout(),
UserHandle.USER_CURRENT);
}
/**
- * Get Accessibility repeat keys delay rate in milliseconds.
+ * Get repeat keys delay rate in milliseconds.
* The default key repeat delay is {@link ViewConfiguration#DEFAULT_KEY_REPEAT_DELAY_MS}.
*
* @param context The application context
@@ -850,7 +877,7 @@
*
* <p>
* ‘Repeat keys’ is a feature which allows users to generate key repeats when a particular
- * key on the physical keyboard is held down. This accessibility feature allows the user
+ * key on the physical keyboard is held down. This feature allows the user
* to configure the timeout before the key repeats begin as well as the delay
* between successive key repeats.
* </p>
@@ -859,14 +886,41 @@
*/
@TestApi
@FlaggedApi(FLAG_KEYBOARD_REPEAT_KEYS)
- public static int getAccessibilityRepeatKeysDelay(@NonNull Context context) {
+ public static int getRepeatKeysDelay(@NonNull Context context) {
+ if (!isRepeatKeysFeatureFlagEnabled()) {
+ return ViewConfiguration.getKeyRepeatDelay();
+ }
return Settings.Secure.getIntForUser(context.getContentResolver(),
Settings.Secure.KEY_REPEAT_DELAY_MS, ViewConfiguration.getKeyRepeatDelay(),
UserHandle.USER_CURRENT);
}
/**
- * Set Accessibility repeat keys timeout duration in milliseconds.
+ * Set repeat keys feature enabled/disabled.
+ *
+ * <p>
+ * 'Repeat keys’ is a feature which allows users to generate key repeats when a particular
+ * key on the physical keyboard is held down. This feature allows the user
+ * to configure the timeout before the key repeats begin as well as the delay
+ * between successive key repeats.
+ * </p>
+ *
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(FLAG_KEYBOARD_REPEAT_KEYS)
+ @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+ public static void setRepeatKeysEnabled(@NonNull Context context,
+ boolean enabled) {
+ if (!isRepeatKeysFeatureFlagEnabled()) {
+ return;
+ }
+ Settings.Secure.putIntForUser(context.getContentResolver(),
+ Settings.Secure.KEY_REPEAT_ENABLED, enabled ? 1 : 0, UserHandle.USER_CURRENT);
+ }
+
+ /**
+ * Set repeat keys timeout duration in milliseconds.
*
* @param timeoutTimeMillis time duration for which a key should be pressed after which the
* pressed key will be repeated. The timeout must be between
@@ -875,7 +929,7 @@
*
* <p>
* ‘Repeat keys’ is a feature which allows users to generate key repeats when a particular
- * key on the physical keyboard is held down. This accessibility feature allows the user
+ * key on the physical keyboard is held down. This feature allows the user
* to configure the timeout before the key repeats begin as well as the delay
* between successive key repeats.
* </p>
@@ -885,8 +939,12 @@
@TestApi
@FlaggedApi(FLAG_KEYBOARD_REPEAT_KEYS)
@RequiresPermission(Manifest.permission.WRITE_SETTINGS)
- public static void setAccessibilityRepeatKeysTimeout(@NonNull Context context,
+ public static void setRepeatKeysTimeout(@NonNull Context context,
int timeoutTimeMillis) {
+ if (!isRepeatKeysFeatureFlagEnabled()
+ && !isRepeatKeysEnabled(context)) {
+ return;
+ }
if (timeoutTimeMillis < MIN_KEY_REPEAT_TIMEOUT_MILLIS
|| timeoutTimeMillis > MAX_KEY_REPEAT_TIMEOUT_MILLIS) {
throw new IllegalArgumentException(
@@ -900,7 +958,7 @@
}
/**
- * Set Accessibility repeat key delay duration in milliseconds.
+ * Set repeat key delay duration in milliseconds.
*
* @param delayTimeMillis Time duration between successive key repeats when a key is
* pressed down. The delay duration must be between
@@ -908,7 +966,7 @@
* {@link #MAX_KEY_REPEAT_DELAY_MILLIS}
* <p>
* ‘Repeat keys’ is a feature which allows users to generate key repeats when a particular
- * key on the physical keyboard is held down. This accessibility feature allows the user
+ * key on the physical keyboard is held down. This feature allows the user
* to configure the timeout before the key repeats begin as well as the delay
* between successive key repeats.
* </p>
@@ -918,8 +976,12 @@
@TestApi
@FlaggedApi(FLAG_KEYBOARD_REPEAT_KEYS)
@RequiresPermission(Manifest.permission.WRITE_SETTINGS)
- public static void setAccessibilityRepeatKeysDelay(@NonNull Context context,
+ public static void setRepeatKeysDelay(@NonNull Context context,
int delayTimeMillis) {
+ if (!isRepeatKeysFeatureFlagEnabled()
+ && !isRepeatKeysEnabled(context)) {
+ return;
+ }
if (delayTimeMillis < MIN_KEY_REPEAT_DELAY_MILLIS
|| delayTimeMillis > MAX_KEY_REPEAT_DELAY_MILLIS) {
throw new IllegalArgumentException(
diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java
index 0cabc4c..bdbec55 100644
--- a/core/java/android/hardware/input/KeyGestureEvent.java
+++ b/core/java/android/hardware/input/KeyGestureEvent.java
@@ -22,8 +22,6 @@
import android.view.Display;
import android.view.KeyCharacterMap;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.AnnotationValidations;
import com.android.internal.util.FrameworkStatsLog;
import java.lang.annotation.Retention;
@@ -171,6 +169,14 @@
}
/**
+ * Tests whether this keyboard shortcut event has the given modifiers (i.e. all of the given
+ * modifiers were pressed when this shortcut was triggered).
+ */
+ public boolean hasModifiers(int modifiers) {
+ return (getModifierState() & modifiers) == modifiers;
+ }
+
+ /**
* Key gesture event builder used to create a KeyGestureEvent for tests in Java.
*
* @hide
diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig
index 983bbc3..75683f6 100644
--- a/core/java/android/hardware/input/input_framework.aconfig
+++ b/core/java/android/hardware/input/input_framework.aconfig
@@ -138,3 +138,10 @@
description: "Controls whether external mouse vertical scrolling can be reversed"
bug: "352598211"
}
+
+flag {
+ name: "mouse_swap_primary_button"
+ namespace: "input"
+ description: "Controls whether the connected mice's primary buttons, left and right, can be swapped."
+ bug: "352598211"
+}
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 6f11d3a..af93c96 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -35,7 +35,6 @@
import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
import com.android.server.vcn.util.PersistableBundleUtils;
@@ -434,7 +433,14 @@
@NonNull
public int[] getExposedCapabilities() {
// Sorted set guarantees ordering
- return ArrayUtils.convertToIntArray(new ArrayList<>(mExposedCapabilities));
+ final int[] caps = new int[mExposedCapabilities.size()];
+
+ int i = 0;
+ for (int c : mExposedCapabilities) {
+ caps[i++] = c;
+ }
+
+ return caps;
}
/**
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkSpecifier.java b/core/java/android/net/vcn/VcnUnderlyingNetworkSpecifier.java
index a975637..e1d1b3c6 100644
--- a/core/java/android/net/vcn/VcnUnderlyingNetworkSpecifier.java
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkSpecifier.java
@@ -24,7 +24,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
-import com.android.internal.util.ArrayUtils;
import java.util.Arrays;
import java.util.Objects;
@@ -114,8 +113,13 @@
@Override
public boolean canBeSatisfiedBy(NetworkSpecifier other) {
if (other instanceof TelephonyNetworkSpecifier) {
- return ArrayUtils.contains(
- mSubIds, ((TelephonyNetworkSpecifier) other).getSubscriptionId());
+ final int targetSubId = ((TelephonyNetworkSpecifier) other).getSubscriptionId();
+ for (int subId : mSubIds) {
+ if (targetSubId == subId) {
+ return true;
+ }
+ }
+ return false;
}
// TODO(b/180140053): Allow matching against WifiNetworkAgentSpecifier
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index f3efd89..8b267bf 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -141,6 +141,7 @@
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* integer containing the charge counter present in the battery.
+ * It shows the available battery power in µAh
* {@hide}
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -166,6 +167,76 @@
public static final String EXTRA_CHARGING_STATUS = "android.os.extra.CHARGING_STATUS";
/**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * Int value representing the battery's capacity level. These constants are key indicators of
+ * battery status and system capabilities, guiding power management decisions for both the
+ * system and apps:
+ * {@link #BATTERY_CAPACITY_LEVEL_UNSUPPORTED}: Feature not supported on this device.
+ * {@link #BATTERY_CAPACITY_LEVEL_UNKNOWN}: Battery status is unavailable or uninitialized.
+ * {@link #BATTERY_CAPACITY_LEVEL_CRITICAL}: Battery is critically low and the Android
+ * framework has been notified to schedule a shutdown by this value
+ * {@link #BATTERY_CAPACITY_LEVEL_LOW}: Android framework must limit background jobs to
+ * avoid impacting charging speed
+ * {@link #BATTERY_CAPACITY_LEVEL_NORMAL}: Battery level and charging rates are normal,
+ * battery temperature is within normal range and adapter power is enough to charge the
+ * battery at an acceptable rate. Android framework can run light background tasks without
+ * affecting charging performance severely.
+ * {@link #BATTERY_CAPACITY_LEVEL_HIGH}: Battery level is high, battery temperature is
+ * within normal range and adapter power is enough to charge the battery at an acceptable
+ * rate while running background loads. Android framework can run background tasks without
+ * affecting charging or battery performance.
+ * {@link #BATTERY_CAPACITY_LEVEL_FULL}: The battery is full, battery temperature is
+ * within normal range and adapter power is enough to sustain running background loads.
+ * Android framework can run background tasks without affecting the battery level or
+ * battery performance.
+ */
+
+ @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
+ public static final String EXTRA_CAPACITY_LEVEL = "android.os.extra.CAPACITY_LEVEL";
+
+ /**
+ * Battery capacity level is unsupported. @see EXTRA_CAPACITY_LEVEL
+ */
+ @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
+ public static final int BATTERY_CAPACITY_LEVEL_UNSUPPORTED = -1;
+
+ /**
+ * Battery capacity level is unknown. @see EXTRA_CAPACITY_LEVEL
+ */
+ @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
+ public static final int BATTERY_CAPACITY_LEVEL_UNKNOWN = 0;
+
+ /**
+ * Battery capacity level is critical. @see EXTRA_CAPACITY_LEVEL
+ */
+ @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
+ public static final int BATTERY_CAPACITY_LEVEL_CRITICAL = 1;
+
+ /**
+ * Battery capacity level is low. @see EXTRA_CAPACITY_LEVEL
+ */
+ @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
+ public static final int BATTERY_CAPACITY_LEVEL_LOW = 2;
+
+ /**
+ * Battery capacity level is normal. @see EXTRA_CAPACITY_LEVEL
+ */
+ @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
+ public static final int BATTERY_CAPACITY_LEVEL_NORMAL = 3;
+
+ /**
+ * Battery capacity level is high. @see EXTRA_CAPACITY_LEVEL
+ */
+ @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
+ public static final int BATTERY_CAPACITY_LEVEL_HIGH = 4;
+
+ /**
+ * Battery capacity level is full. @see EXTRA_CAPACITY_LEVEL
+ */
+ @FlaggedApi(FLAG_BATTERY_PART_STATUS_API)
+ public static final int BATTERY_CAPACITY_LEVEL_FULL = 5;
+
+ /**
* Extra for {@link android.content.Intent#ACTION_BATTERY_LEVEL_CHANGED}:
* Contains list of Bundles representing battery events
* @hide
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index c22f46c..80546cd 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -650,13 +650,13 @@
* weakly referenced by JNI so the strong references here are needed to keep the callbacks
* around until the proxy is GC'ed.
*/
- private List<IFrozenStateChangeCallback> mFrozenStateChangeCallbacks =
+ private List<FrozenStateChangeCallback> mFrozenStateChangeCallbacks =
Collections.synchronizedList(new ArrayList<>());
/**
- * See {@link IBinder#addFrozenStateChangeCallback(IFrozenStateChangeCallback)}
+ * See {@link IBinder#addFrozenStateChangeCallback(FrozenStateChangeCallback)}
*/
- public void addFrozenStateChangeCallback(IFrozenStateChangeCallback callback)
+ public void addFrozenStateChangeCallback(FrozenStateChangeCallback callback)
throws RemoteException {
addFrozenStateChangeCallbackNative(callback);
mFrozenStateChangeCallbacks.add(callback);
@@ -665,16 +665,16 @@
/**
* See {@link IBinder#removeFrozenStateChangeCallback}
*/
- public boolean removeFrozenStateChangeCallback(IFrozenStateChangeCallback callback) {
+ public boolean removeFrozenStateChangeCallback(FrozenStateChangeCallback callback) {
mFrozenStateChangeCallbacks.remove(callback);
return removeFrozenStateChangeCallbackNative(callback);
}
- private native void addFrozenStateChangeCallbackNative(IFrozenStateChangeCallback callback)
+ private native void addFrozenStateChangeCallbackNative(FrozenStateChangeCallback callback)
throws RemoteException;
private native boolean removeFrozenStateChangeCallbackNative(
- IFrozenStateChangeCallback callback);
+ FrozenStateChangeCallback callback);
/**
* Perform a dump on the remote object
@@ -762,10 +762,9 @@
}
private static void invokeFrozenStateChangeCallback(
- IFrozenStateChangeCallback callback, IBinder binderProxy, int stateIndex) {
+ FrozenStateChangeCallback callback, IBinder binderProxy, int stateIndex) {
try {
- callback.onFrozenStateChanged(binderProxy,
- IFrozenStateChangeCallback.State.values()[stateIndex]);
+ callback.onFrozenStateChanged(binderProxy, stateIndex);
} catch (RuntimeException exc) {
Log.w("BinderNative", "Uncaught exception from frozen state change callback",
exc);
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 80f39bf..d0828c3 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -16,8 +16,10 @@
package android.os;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.util.Log;
import android.util.Printer;
@@ -819,16 +821,25 @@
}
/**
+ * WARNING: This API is dangerous because if the implementation
+ * of equals() is broken, it would delete unrelated events. For example,
+ * if object.equals() always returns true, it'd remove all messages.
+ *
+ * For this reason, never expose this API to non-platform code. i.e.
+ * this shouldn't be exposed to SystemApi.PRIVILEGED_APPS.
+ *
* Remove any pending posts of messages with code 'what' and whose obj is
* 'object' that are in the message queue. If <var>object</var> is null,
* all messages will be removed.
- * <p>
- * Similar to {@link #removeMessages(int, Object)} but uses object equality
+ *
+ * <p>Similar to {@link #removeMessages(int, Object)} but uses object equality
* ({@link Object#equals(Object)}) instead of reference equality (==) in
* determining whether object is the message's obj'.
*
*@hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @FlaggedApi(android.os.Flags.FLAG_MAINLINE_VCN_PLATFORM_API)
public final void removeEqualMessages(int what, @Nullable Object object) {
mQueue.removeEqualMessages(this, what, disallowNullArgumentIfShared(object));
}
@@ -843,12 +854,25 @@
}
/**
+ * WARNING: This API is dangerous because if the implementation
+ * of equals() is broken, it would delete unrelated events. For example,
+ * if object.equals() always returns true, it'd remove all messages.
+ *
+ * For this reason, never expose this API to non-platform code. i.e.
+ * this shouldn't be exposed to SystemApi.PRIVILEGED_APPS.
+ *
* Remove any pending posts of callbacks and sent messages whose
* <var>obj</var> is <var>token</var>. If <var>token</var> is null,
* all callbacks and messages will be removed.
*
+ * <p>Similar to {@link #removeCallbacksAndMessages(Object)} but uses object
+ * equality ({@link Object#equals(Object)}) instead of reference equality (==) in
+ * determining whether object is the message's obj'.
+ *
*@hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @FlaggedApi(android.os.Flags.FLAG_MAINLINE_VCN_PLATFORM_API)
public final void removeCallbacksAndEqualMessages(@Nullable Object token) {
mQueue.removeCallbacksAndEqualMessages(this, disallowNullArgumentIfShared(token));
}
@@ -864,6 +888,8 @@
* Return whether there are any messages or callbacks currently scheduled on this handler.
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @FlaggedApi(android.os.Flags.FLAG_MAINLINE_VCN_PLATFORM_API)
public final boolean hasMessagesOrCallbacks() {
return mQueue.hasMessages(this);
}
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 8185e8e..a997f4c8 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -16,11 +16,15 @@
package android.os;
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import java.io.FileDescriptor;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* Base interface for a remotable object, the core part of a lightweight
@@ -377,9 +381,24 @@
*/
public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags);
- /** @hide */
- interface IFrozenStateChangeCallback {
- enum State {FROZEN, UNFROZEN};
+ /**
+ * A callback interface for receiving frozen state change events.
+ */
+ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+ interface FrozenStateChangeCallback {
+ /**
+ * @hide
+ */
+ @IntDef(prefix = {"STATE_"}, value = {
+ STATE_FROZEN,
+ STATE_UNFROZEN,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface State {
+ }
+
+ int STATE_FROZEN = 0;
+ int STATE_UNFROZEN = 1;
/**
* Interface for receiving a callback when the process hosting an IBinder
@@ -387,13 +406,13 @@
* @param who The IBinder whose hosting process has changed state.
* @param state The latest state.
*/
- void onFrozenStateChanged(@NonNull IBinder who, State state);
+ void onFrozenStateChanged(@NonNull IBinder who, @State int state);
}
/**
- * {@link addFrozenStateChangeCallback} provides a callback mechanism to notify about process
- * frozen/unfrozen events. Upon registration and any subsequent state changes, the callback is
- * invoked with the latest process frozen state.
+ * This method provides a callback mechanism to notify about process frozen/unfrozen events.
+ * Upon registration and any subsequent state changes, the callback is invoked with the latest
+ * process frozen state.
*
* <p>If the listener process (the one using this API) is itself frozen, state change events
* might be combined into a single one with the latest frozen state. This single event would
@@ -410,19 +429,19 @@
*
* <p>@throws {@link UnsupportedOperationException} if the kernel binder driver does not support
* this feature.
- * @hide
*/
- default void addFrozenStateChangeCallback(@NonNull IFrozenStateChangeCallback callback)
+ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+ default void addFrozenStateChangeCallback(@NonNull FrozenStateChangeCallback callback)
throws RemoteException {
throw new UnsupportedOperationException();
}
/**
- * Unregister a {@link IFrozenStateChangeCallback}. The callback will no longer be invoked when
+ * Unregister a {@link FrozenStateChangeCallback}. The callback will no longer be invoked when
* the hosting process changes its frozen state.
- * @hide
*/
- default boolean removeFrozenStateChangeCallback(@NonNull IFrozenStateChangeCallback callback) {
+ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+ default boolean removeFrozenStateChangeCallback(@NonNull FrozenStateChangeCallback callback) {
throw new UnsupportedOperationException();
}
}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 00ba3bf..18f9b2b 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -139,7 +139,7 @@
boolean isUserForeground(int userId);
boolean isUserVisible(int userId);
int[] getVisibleUsers();
- int getMainDisplayIdAssignedToUser();
+ int getMainDisplayIdAssignedToUser(int userId);
boolean isForegroundUserAdmin();
boolean isUserNameSet(int userId);
boolean hasRestrictedProfiles(int userId);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 026013c..e4c12b6 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1144,9 +1144,10 @@
}
private static final String CACHE_KEY_IS_POWER_SAVE_MODE_PROPERTY =
- "cache_key.is_power_save_mode";
+ PropertyInvalidatedCache.createSystemCacheKey("is_power_save_mode");
- private static final String CACHE_KEY_IS_INTERACTIVE_PROPERTY = "cache_key.is_interactive";
+ private static final String CACHE_KEY_IS_INTERACTIVE_PROPERTY =
+ PropertyInvalidatedCache.createSystemCacheKey("is_interactive");
private static final int MAX_CACHE_ENTRIES = 1;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1ca4574..461f1e0 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -3706,9 +3706,13 @@
* @hide
*/
@TestApi
+ @UserHandleAware(
+ requiresAnyOfPermissionsIfNotCaller = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS})
public int getMainDisplayIdAssignedToUser() {
try {
- return mService.getMainDisplayIdAssignedToUser();
+ return mService.getMainDisplayIdAssignedToUser(mUserId);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 39bd15c..f670601 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -153,6 +153,14 @@
}
flag {
+ name: "binder_frozen_state_change_callback"
+ is_exported: true
+ namespace: "system_performance"
+ description: "Guards the frozen state change callback API."
+ bug: "361157077"
+}
+
+flag {
name: "message_queue_tail_tracking"
namespace: "system_performance"
description: "track tail of message queue."
@@ -208,3 +216,11 @@
bug: "346294653"
is_exported: true
}
+
+flag {
+ name: "mainline_vcn_platform_api"
+ namespace: "vcn"
+ description: "Expose platform APIs to mainline VCN"
+ is_exported: true
+ bug: "366598445"
+}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 7e51cb0..e98397d 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -1796,7 +1796,8 @@
}
/** @hide */
- public static final String CACHE_KEY_PACKAGE_INFO = "cache_key.package_info";
+ public static final String CACHE_KEY_PACKAGE_INFO =
+ PropertyInvalidatedCache.createSystemCacheKey("package_info");
/** @hide */
private static final PropertyInvalidatedCache<PermissionQuery, Integer> sPermissionCache =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e32625e..b8a8be1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -111,6 +111,7 @@
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.net.URISyntaxException;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -3022,6 +3023,9 @@
/** @hide - Private call() method to query the 'configuration' table */
public static final String CALL_METHOD_LIST_CONFIG = "LIST_config";
+ /** @hide - Private call() method to query the 'configuration' tables' namespaces */
+ public static final String CALL_METHOD_LIST_NAMESPACES_CONFIG = "LIST_namespaces_config";
+
/** @hide - Private call() method to disable / re-enable syncs to the 'configuration' table */
public static final String CALL_METHOD_SET_SYNC_DISABLED_MODE_CONFIG =
"SET_SYNC_DISABLED_MODE_config";
@@ -9154,15 +9158,27 @@
public static final String MULTI_PRESS_TIMEOUT = "multi_press_timeout";
/**
+ * Whether to enable key repeats for Physical Keyboard.
+ *
+ * If set to false, continuous key presses on
+ * physical keyboard will not cause the pressed key to repeated.
+ * @hide
+ */
+ @Readable
+ public static final String KEY_REPEAT_ENABLED = "key_repeat_enabled";
+
+ /**
* The duration before a key repeat begins in milliseconds.
* @hide
*/
+ @Readable
public static final String KEY_REPEAT_TIMEOUT_MS = "key_repeat_timeout";
/**
* The duration between successive key repeats in milliseconds.
* @hide
*/
+ @Readable
public static final String KEY_REPEAT_DELAY_MS = "key_repeat_delay";
/**
@@ -20458,6 +20474,10 @@
*
* The keys take the form {@code namespace/flag}, and the values are the flag values.
*
+ * Note: this API is _not_ performant, and may make a large number of
+ * Binder calls. It is intended for use in testing and debugging, and
+ * should not be used in performance-sensitive code.
+ *
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@@ -20469,13 +20489,33 @@
Bundle arg = new Bundle();
arg.putInt(Settings.CALL_METHOD_USER_KEY, resolver.getUserId());
IContentProvider cp = sProviderHolder.getProvider(resolver);
- Bundle b = cp.call(resolver.getAttributionSource(),
- sProviderHolder.mUri.getAuthority(), CALL_METHOD_LIST_CONFIG, null, arg);
- if (b != null) {
- Map<String, String> flagsToValues =
- (HashMap) b.getSerializable(Settings.NameValueTable.VALUE,
- java.util.HashMap.class);
- allFlags.putAll(flagsToValues);
+
+ if (Flags.reduceBinderTransactionSizeForGetAllProperties()) {
+ Bundle b = cp.call(resolver.getAttributionSource(),
+ sProviderHolder.mUri.getAuthority(),
+ CALL_METHOD_LIST_NAMESPACES_CONFIG, null, arg);
+ if (b != null) {
+ HashSet<String> namespaces =
+ (HashSet) b.getSerializable(Settings.NameValueTable.VALUE,
+ java.util.HashSet.class);
+ for (String namespace : namespaces) {
+ Map<String, String> keyValues =
+ getStrings(namespace, new ArrayList());
+ for (String key : keyValues.keySet()) {
+ allFlags.put(namespace + "/" + key, keyValues.get(key));
+ }
+ }
+ }
+ } else {
+ Bundle b = cp.call(resolver.getAttributionSource(),
+ sProviderHolder.mUri.getAuthority(),
+ CALL_METHOD_LIST_CONFIG, null, arg);
+ if (b != null) {
+ Map<String, String> flagsToValues =
+ (HashMap) b.getSerializable(Settings.NameValueTable.VALUE,
+ java.util.HashMap.class);
+ allFlags.putAll(flagsToValues);
+ }
}
} catch (RemoteException e) {
Log.w(TAG, "Can't query configuration table for " + CONTENT_URI, e);
diff --git a/core/java/android/provider/flags.aconfig b/core/java/android/provider/flags.aconfig
index 5c0f873..4c63673 100644
--- a/core/java/android/provider/flags.aconfig
+++ b/core/java/android/provider/flags.aconfig
@@ -52,3 +52,14 @@
description: "Enable the new ContactsContract Default Account APIs."
bug: "359957527"
}
+
+flag {
+ name: "reduce_binder_transaction_size_for_get_all_properties"
+ namespace: "core_experiments_team_internal"
+ description: "Reduce Binder transaction size in getAllProperties calls"
+ bug: "362652574"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 384add5..2ab16e9 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -2397,7 +2397,11 @@
// it hasn't changed and there is no need to update.
ret = mBlastBufferQueue.createSurface();
} else {
- mBlastBufferQueue.update(mBbqSurfaceControl, width, height, format);
+ if (mBbqSurfaceControl != null && mBbqSurfaceControl.isValid()) {
+ mBlastBufferQueue.update(mBbqSurfaceControl, width, height, format);
+ } else {
+ Log.w(TAG, "Skipping BlastBufferQueue update - invalid surface control");
+ }
}
return ret;
diff --git a/core/java/android/text/ClientFlags.java b/core/java/android/text/ClientFlags.java
index c2ad508..ca88764 100644
--- a/core/java/android/text/ClientFlags.java
+++ b/core/java/android/text/ClientFlags.java
@@ -16,21 +16,14 @@
package android.text;
-import com.android.text.flags.Flags;
-
/**
* An aconfig feature flags that can be accessible from application process without
* ContentProvider IPCs.
*
* When you add new flags, you have to add flag string to {@link TextFlags#TEXT_ACONFIGS_FLAGS}.
*
+ * TODO(nona): Remove this class.
* @hide
*/
public class ClientFlags {
- /**
- * @see Flags#fixMisalignedContextMenu()
- */
- public static boolean fixMisalignedContextMenu() {
- return TextFlags.isFeatureEnabled(Flags.FLAG_FIX_MISALIGNED_CONTEXT_MENU);
- }
}
diff --git a/core/java/android/text/TextFlags.java b/core/java/android/text/TextFlags.java
index 076721f..f69a333 100644
--- a/core/java/android/text/TextFlags.java
+++ b/core/java/android/text/TextFlags.java
@@ -19,11 +19,10 @@
import android.annotation.NonNull;
import android.app.AppGlobals;
-import com.android.text.flags.Flags;
-
/**
* Flags in the "text" namespace.
*
+ * TODO(nona): Remove this class.
* @hide
*/
public final class TextFlags {
@@ -55,7 +54,6 @@
* List of text flags to be transferred to the application process.
*/
public static final String[] TEXT_ACONFIGS_FLAGS = {
- Flags.FLAG_FIX_MISALIGNED_CONTEXT_MENU,
};
/**
@@ -64,7 +62,6 @@
* The order must be the same to the TEXT_ACONFIG_FLAGS.
*/
public static final boolean[] TEXT_ACONFIG_DEFAULT_VALUE = {
- Flags.fixMisalignedContextMenu(),
};
/**
diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig
index 3846972..c83285a 100644
--- a/core/java/android/text/flags/flags.aconfig
+++ b/core/java/android/text/flags/flags.aconfig
@@ -84,16 +84,6 @@
}
flag {
- name: "fix_misaligned_context_menu"
- namespace: "text"
- description: "Fix the context menu misalignment and incosistent icon size."
- bug: "332542108"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "missing_getter_apis"
namespace: "text"
description: "Fix the lint warning about missing getters."
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 6b4340a..5c41516 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -38,6 +38,7 @@
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -55,7 +56,6 @@
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.window.flags.Flags;
import java.io.PrintWriter;
import java.util.Objects;
@@ -146,7 +146,7 @@
forceConsumingTypes |= type;
}
- if (Flags.enableCaptionCompatInsetForceConsumptionAlways()
+ if (ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS.isTrue()
&& (flags & FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR) != 0) {
forceConsumingOpaqueCaptionBar = true;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9ff5031..d46e1f2 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -125,11 +125,11 @@
import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
+import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme;
import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay;
-import static com.android.window.flags.Flags.enableCaptionCompatInsetForceConsumption;
import static com.android.window.flags.Flags.insetsControlChangedItem;
import static com.android.window.flags.Flags.insetsControlSeq;
import static com.android.window.flags.Flags.setScPropertiesInClient;
@@ -3214,10 +3214,10 @@
typesToShow |= Type.navigationBars();
}
if (captionIsHiddenByFlags && !captionWasHiddenByFlags
- && enableCaptionCompatInsetForceConsumption()) {
+ && ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isTrue()) {
typesToHide |= Type.captionBar();
} else if (!captionIsHiddenByFlags && captionWasHiddenByFlags
- && enableCaptionCompatInsetForceConsumption()) {
+ && ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isTrue()) {
typesToShow |= Type.captionBar();
}
if (typesToHide != 0) {
diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java
index b9751c8..d90455a 100644
--- a/core/java/android/view/inputmethod/ImeTracker.java
+++ b/core/java/android/view/inputmethod/ImeTracker.java
@@ -920,7 +920,8 @@
final Configuration.Builder builder = Configuration.Builder.withSurface(
cujType,
jankContext.getDisplayContext(),
- jankContext.getTargetSurfaceControl())
+ jankContext.getTargetSurfaceControl(),
+ jankContext.getDisplayContext().getMainThreadHandler())
.setTag(String.format(Locale.US, "%d@%d@%s", animType,
useSeparatedThread ? 0 : 1, jankContext.getHostPackageName()));
InteractionJankMonitor.getInstance().begin(builder);
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index e1154ca..06820cd 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1003,6 +1003,55 @@
public int getActionTag() {
return SET_EMPTY_VIEW_ACTION_TAG;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(RemoteViewsProto.Action.SET_EMPTY_VIEW_ACTION);
+ out.write(RemoteViewsProto.SetEmptyViewAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.write(RemoteViewsProto.SetEmptyViewAction.EMPTY_VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.SET_EMPTY_VIEW_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.SetEmptyViewAction.VIEW_ID:
+ values.put(RemoteViewsProto.SetEmptyViewAction.VIEW_ID,
+ in.readString(RemoteViewsProto.SetEmptyViewAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.SetEmptyViewAction.EMPTY_VIEW_ID:
+ values.put(RemoteViewsProto.SetEmptyViewAction.EMPTY_VIEW_ID,
+ in.readString(RemoteViewsProto.SetEmptyViewAction.EMPTY_VIEW_ID));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values, new long[]{RemoteViewsProto.SetEmptyViewAction.VIEW_ID,
+ RemoteViewsProto.SetEmptyViewAction.EMPTY_VIEW_ID});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetEmptyViewAction.VIEW_ID);
+ int emptyViewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetEmptyViewAction.EMPTY_VIEW_ID);
+ return new SetEmptyView(viewId, emptyViewId);
+ };
+ }
}
private static class SetPendingIntentTemplate extends Action {
@@ -1243,6 +1292,68 @@
mItems.visitUris(visitor);
}
+
+ @Override
+ public boolean canWriteToProto() {
+ // Skip actions that do not contain items (intent only actions)
+ return mItems != null;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ if (mItems == null) return;
+ final long token = out.start(
+ RemoteViewsProto.Action.SET_REMOTE_COLLECTION_ITEM_LIST_ADAPTER_ACTION);
+ out.write(RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ final long itemsToken = out.start(
+ RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.ITEMS);
+ mItems.writeToProto(context, out, /* attached= */ true);
+ out.end(itemsToken);
+ out.end(token);
+ }
+ }
+
+ private PendingResources<Action> createSetRemoteCollectionItemListAdapterActionFromProto(
+ ProtoInputStream in) throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(
+ RemoteViewsProto.Action.SET_REMOTE_COLLECTION_ITEM_LIST_ADAPTER_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.VIEW_ID:
+ values.put(RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.VIEW_ID,
+ in.readString(
+ RemoteViewsProto
+ .SetRemoteCollectionItemListAdapterAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.ITEMS:
+ final long itemsToken = in.start(
+ RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.ITEMS);
+ values.put(RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.ITEMS,
+ RemoteCollectionItems.createFromProto(in));
+ in.end(itemsToken);
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values,
+ new long[]{RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.VIEW_ID,
+ RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.ITEMS});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.VIEW_ID);
+ return new SetRemoteCollectionItemListAdapterAction(viewId,
+ ((PendingResources<RemoteCollectionItems>) values.get(
+ RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.ITEMS))
+ .create(context, resources, rootData, depth));
+ };
}
/**
@@ -2036,6 +2147,68 @@
public int getActionTag() {
return SET_DRAWABLE_TINT_TAG;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(RemoteViewsProto.Action.SET_DRAWABLE_TINT_ACTION);
+ out.write(RemoteViewsProto.SetDrawableTintAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.write(RemoteViewsProto.SetDrawableTintAction.COLOR_FILTER, mColorFilter);
+ out.write(RemoteViewsProto.SetDrawableTintAction.FILTER_MODE,
+ PorterDuff.modeToInt(mFilterMode));
+ out.write(RemoteViewsProto.SetDrawableTintAction.TARGET_BACKGROUND, mTargetBackground);
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.SET_DRAWABLE_TINT_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.SetDrawableTintAction.VIEW_ID:
+ values.put(RemoteViewsProto.SetDrawableTintAction.VIEW_ID,
+ in.readString(RemoteViewsProto.SetDrawableTintAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.SetDrawableTintAction.TARGET_BACKGROUND:
+ values.put(RemoteViewsProto.SetDrawableTintAction.TARGET_BACKGROUND,
+ in.readBoolean(
+ RemoteViewsProto.SetDrawableTintAction.TARGET_BACKGROUND));
+ break;
+ case (int) RemoteViewsProto.SetDrawableTintAction.COLOR_FILTER:
+ values.put(RemoteViewsProto.SetDrawableTintAction.COLOR_FILTER,
+ in.readInt(RemoteViewsProto.SetDrawableTintAction.COLOR_FILTER));
+ break;
+ case (int) RemoteViewsProto.SetDrawableTintAction.FILTER_MODE:
+ values.put(RemoteViewsProto.SetDrawableTintAction.FILTER_MODE,
+ PorterDuff.intToMode(in.readInt(
+ RemoteViewsProto.SetDrawableTintAction.FILTER_MODE)));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values, new long[]{RemoteViewsProto.SetDrawableTintAction.VIEW_ID});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetDrawableTintAction.VIEW_ID);
+ return new SetDrawableTint(viewId, (boolean) values.get(
+ RemoteViewsProto.SetDrawableTintAction.TARGET_BACKGROUND, false),
+ (int) values.get(RemoteViewsProto.SetDrawableTintAction.COLOR_FILTER, 0),
+ (PorterDuff.Mode) values.get(
+ RemoteViewsProto.SetDrawableTintAction.FILTER_MODE));
+ };
+ }
}
/**
@@ -2047,7 +2220,7 @@
* target {@link View#getBackground()}.
* <p>
*/
- private class SetRippleDrawableColor extends Action {
+ private static class SetRippleDrawableColor extends Action {
ColorStateList mColorStateList;
SetRippleDrawableColor(@IdRes int id, ColorStateList colorStateList) {
@@ -2082,6 +2255,58 @@
public int getActionTag() {
return SET_RIPPLE_DRAWABLE_COLOR_TAG;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(RemoteViewsProto.Action.SET_RIPPLE_DRAWABLE_COLOR_ACTION);
+ out.write(RemoteViewsProto.SetRippleDrawableColorAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ writeColorStateListToProto(out, mColorStateList,
+ RemoteViewsProto.SetRippleDrawableColorAction.COLOR_STATE_LIST);
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.SET_RIPPLE_DRAWABLE_COLOR_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.SetRippleDrawableColorAction.VIEW_ID:
+ values.put(RemoteViewsProto.SetRippleDrawableColorAction.VIEW_ID,
+ in.readString(
+ RemoteViewsProto.SetRippleDrawableColorAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.SetRippleDrawableColorAction.COLOR_STATE_LIST:
+ values.put(RemoteViewsProto.SetRippleDrawableColorAction.COLOR_STATE_LIST,
+ createColorStateListFromProto(in,
+ RemoteViewsProto
+ .SetRippleDrawableColorAction.COLOR_STATE_LIST));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values,
+ new long[]{RemoteViewsProto.SetRippleDrawableColorAction.VIEW_ID,
+ RemoteViewsProto.SetRippleDrawableColorAction.COLOR_STATE_LIST});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetRippleDrawableColorAction.VIEW_ID);
+ return new SetRippleDrawableColor(viewId, (ColorStateList) values.get(
+ RemoteViewsProto.SetRippleDrawableColorAction.COLOR_STATE_LIST));
+ };
+ }
}
/**
@@ -2987,6 +3212,82 @@
public int getActionTag() {
return RESOURCE_REFLECTION_ACTION_TAG;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(RemoteViewsProto.Action.RESOURCE_REFLECTION_ACTION);
+ out.write(RemoteViewsProto.ResourceReflectionAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.write(RemoteViewsProto.ResourceReflectionAction.METHOD_NAME, mMethodName);
+ out.write(RemoteViewsProto.ResourceReflectionAction.PARAMETER_TYPE, mType);
+ out.write(RemoteViewsProto.ResourceReflectionAction.RESOURCE_TYPE, mResourceType);
+ if (mResId != 0) {
+ out.write(RemoteViewsProto.ResourceReflectionAction.RES_ID,
+ appResources.getResourceName(mResId));
+ }
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.RESOURCE_REFLECTION_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.ResourceReflectionAction.VIEW_ID:
+ values.put(RemoteViewsProto.ResourceReflectionAction.VIEW_ID,
+ in.readString(RemoteViewsProto.ResourceReflectionAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.ResourceReflectionAction.METHOD_NAME:
+ values.put(RemoteViewsProto.ResourceReflectionAction.METHOD_NAME,
+ in.readString(
+ RemoteViewsProto.ResourceReflectionAction.METHOD_NAME));
+ break;
+ case (int) RemoteViewsProto.ResourceReflectionAction.RESOURCE_TYPE:
+ values.put(RemoteViewsProto.ResourceReflectionAction.RESOURCE_TYPE,
+ in.readInt(
+ RemoteViewsProto.ResourceReflectionAction.RESOURCE_TYPE));
+ break;
+ case (int) RemoteViewsProto.ResourceReflectionAction.RES_ID:
+ values.put(RemoteViewsProto.ResourceReflectionAction.RES_ID,
+ in.readString(RemoteViewsProto.ResourceReflectionAction.RES_ID));
+ break;
+ case (int) RemoteViewsProto.ResourceReflectionAction.PARAMETER_TYPE:
+ values.put(RemoteViewsProto.ResourceReflectionAction.PARAMETER_TYPE,
+ in.readInt(
+ RemoteViewsProto.ResourceReflectionAction.PARAMETER_TYPE));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values, new long[]{RemoteViewsProto.ResourceReflectionAction.VIEW_ID,
+ RemoteViewsProto.ResourceReflectionAction.METHOD_NAME,
+ RemoteViewsProto.ResourceReflectionAction.PARAMETER_TYPE});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.ResourceReflectionAction.VIEW_ID);
+
+ int resId = (values.indexOfKey(RemoteViewsProto.ResourceReflectionAction.RES_ID)
+ >= 0) ? getAsIdentifier(resources, values,
+ RemoteViewsProto.ResourceReflectionAction.RES_ID) : 0;
+ return new ResourceReflectionAction(viewId,
+ (String) values.get(RemoteViewsProto.ResourceReflectionAction.METHOD_NAME),
+ (int) values.get(RemoteViewsProto.ResourceReflectionAction.PARAMETER_TYPE),
+ (int) values.get(RemoteViewsProto.ResourceReflectionAction.RESOURCE_TYPE,
+ 0), resId);
+ };
+ }
}
private static final class AttributeReflectionAction extends BaseReflectionAction {
@@ -4593,6 +4894,61 @@
public int getActionTag() {
return SET_INT_TAG_TAG;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(RemoteViewsProto.Action.SET_INT_TAG_ACTION);
+ out.write(RemoteViewsProto.SetIntTagAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.write(RemoteViewsProto.SetIntTagAction.KEY,
+ appResources.getResourceName(mKey)); // rebase
+ out.write(RemoteViewsProto.SetIntTagAction.TAG, mTag);
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.SET_INT_TAG_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.SetIntTagAction.VIEW_ID:
+ values.put(RemoteViewsProto.SetIntTagAction.VIEW_ID,
+ in.readString(RemoteViewsProto.SetIntTagAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.SetIntTagAction.KEY:
+ values.put(RemoteViewsProto.SetIntTagAction.KEY,
+ in.readString(RemoteViewsProto.SetIntTagAction.KEY));
+ break;
+ case (int) RemoteViewsProto.SetIntTagAction.TAG:
+ values.put(RemoteViewsProto.SetIntTagAction.TAG,
+ in.readInt(RemoteViewsProto.SetIntTagAction.TAG));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values, new long[]{RemoteViewsProto.SetIntTagAction.VIEW_ID,
+ RemoteViewsProto.SetIntTagAction.KEY});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetIntTagAction.VIEW_ID);
+ int keyId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetIntTagAction.KEY);
+ return new SetIntTagAction(viewId, keyId,
+ (int) values.get(RemoteViewsProto.SetIntTagAction.TAG, 0));
+ };
+ }
}
private static class SetCompoundButtonCheckedAction extends Action {
@@ -4643,6 +4999,56 @@
public int getActionTag() {
return SET_COMPOUND_BUTTON_CHECKED_TAG;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(
+ RemoteViewsProto.Action.SET_COMPOUND_BUTTON_CHECKED_ACTION);
+ out.write(RemoteViewsProto.SetCompoundButtonCheckedAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.write(RemoteViewsProto.SetCompoundButtonCheckedAction.CHECKED, mChecked);
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.SET_COMPOUND_BUTTON_CHECKED_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.SetCompoundButtonCheckedAction.VIEW_ID:
+ values.put(RemoteViewsProto.SetCompoundButtonCheckedAction.VIEW_ID,
+ in.readString(
+ RemoteViewsProto.SetCompoundButtonCheckedAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.SetCompoundButtonCheckedAction.CHECKED:
+ values.put(RemoteViewsProto.SetCompoundButtonCheckedAction.CHECKED,
+ in.readBoolean(
+ RemoteViewsProto.SetCompoundButtonCheckedAction.CHECKED));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values,
+ new long[]{RemoteViewsProto.SetCompoundButtonCheckedAction.VIEW_ID});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetCompoundButtonCheckedAction.VIEW_ID);
+ return new SetCompoundButtonCheckedAction(viewId, (boolean) values.get(
+ RemoteViewsProto.SetCompoundButtonCheckedAction.CHECKED, false));
+ };
+ }
}
private static class SetRadioGroupCheckedAction extends Action {
@@ -4707,6 +5113,61 @@
public int getActionTag() {
return SET_RADIO_GROUP_CHECKED;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(RemoteViewsProto.Action.SET_RADIO_GROUP_CHECKED_ACTION);
+ out.write(RemoteViewsProto.SetRadioGroupCheckedAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ if (mCheckedId != -1) {
+ out.write(RemoteViewsProto.SetRadioGroupCheckedAction.CHECKED_ID,
+ appResources.getResourceName(mCheckedId));
+ }
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.SET_RADIO_GROUP_CHECKED_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.SetRadioGroupCheckedAction.VIEW_ID:
+ values.put(RemoteViewsProto.SetRadioGroupCheckedAction.VIEW_ID,
+ in.readString(RemoteViewsProto.SetRadioGroupCheckedAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.SetRadioGroupCheckedAction.CHECKED_ID:
+ values.put(RemoteViewsProto.SetRadioGroupCheckedAction.CHECKED_ID,
+ in.readString(
+ RemoteViewsProto.SetRadioGroupCheckedAction.CHECKED_ID));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values,
+ new long[]{RemoteViewsProto.SetRadioGroupCheckedAction.VIEW_ID});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetRadioGroupCheckedAction.VIEW_ID);
+
+ int checkedId = (values.indexOfKey(
+ RemoteViewsProto.SetRadioGroupCheckedAction.CHECKED_ID) >= 0)
+ ? getAsIdentifier(resources, values,
+ RemoteViewsProto.SetRadioGroupCheckedAction.CHECKED_ID) : -1;
+ return new SetRadioGroupCheckedAction(viewId, checkedId);
+ };
+ }
}
private static class SetViewOutlinePreferredRadiusAction extends Action {
@@ -8450,6 +8911,7 @@
public static PendingResources<RemoteCollectionItems> createFromProto(ProtoInputStream in)
throws Exception {
final LongSparseArray<Object> values = new LongSparseArray<>();
+
values.put(RemoteViewsProto.RemoteCollectionItems.IDS, new ArrayList<Long>());
values.put(RemoteViewsProto.RemoteCollectionItems.VIEWS,
new ArrayList<PendingResources<RemoteViews>>());
@@ -9207,6 +9669,22 @@
return ReflectionAction.createFromProto(in);
case (int) RemoteViewsProto.Action.REMOVE_FROM_PARENT_ACTION:
return RemoveFromParentAction.createFromProto(in);
+ case (int) RemoteViewsProto.Action.RESOURCE_REFLECTION_ACTION:
+ return ResourceReflectionAction.createFromProto(in);
+ case (int) RemoteViewsProto.Action.SET_COMPOUND_BUTTON_CHECKED_ACTION:
+ return SetCompoundButtonCheckedAction.createFromProto(in);
+ case (int) RemoteViewsProto.Action.SET_DRAWABLE_TINT_ACTION:
+ return SetDrawableTint.createFromProto(in);
+ case (int) RemoteViewsProto.Action.SET_EMPTY_VIEW_ACTION:
+ return SetEmptyView.createFromProto(in);
+ case (int) RemoteViewsProto.Action.SET_INT_TAG_ACTION:
+ return SetIntTagAction.createFromProto(in);
+ case (int) RemoteViewsProto.Action.SET_RADIO_GROUP_CHECKED_ACTION:
+ return SetRadioGroupCheckedAction.createFromProto(in);
+ case (int) RemoteViewsProto.Action.SET_REMOTE_COLLECTION_ITEM_LIST_ADAPTER_ACTION:
+ return rv.createSetRemoteCollectionItemListAdapterActionFromProto(in);
+ case (int) RemoteViewsProto.Action.SET_RIPPLE_DRAWABLE_COLOR_ACTION:
+ return SetRippleDrawableColor.createFromProto(in);
default:
throw new RuntimeException("Unhandled field while reading Action proto!\n"
+ ProtoUtils.currentFieldToString(in));
diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java
index 3cfde87..8bb4c52 100644
--- a/core/java/android/window/TransitionFilter.java
+++ b/core/java/android/window/TransitionFilter.java
@@ -187,6 +187,7 @@
/** If non-null, requires the change to specifically have or not-have a custom animation. */
public Boolean mCustomAnimation = null;
+ public IBinder mTaskFragmentToken = null;
public Requirement() {
}
@@ -204,12 +205,19 @@
// 0: null, 1: false, 2: true
final int customAnimRaw = in.readInt();
mCustomAnimation = customAnimRaw == 0 ? null : Boolean.valueOf(customAnimRaw == 2);
+ mTaskFragmentToken = in.readStrongBinder();
}
/** Go through changes and find if at-least one change matches this filter */
boolean matches(@NonNull TransitionInfo info) {
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
+
+ if (mTaskFragmentToken != null
+ && !mTaskFragmentToken.equals(change.getTaskFragmentToken())) {
+ continue;
+ }
+
if (mMustBeIndependent && !TransitionInfo.isIndependent(change, info)) {
// Only look at independent animating windows.
continue;
@@ -313,6 +321,7 @@
dest.writeStrongBinder(mLaunchCookie);
int customAnimRaw = mCustomAnimation == null ? 0 : (mCustomAnimation ? 2 : 1);
dest.writeInt(customAnimRaw);
+ dest.writeStrongBinder(mTaskFragmentToken);
}
@NonNull
@@ -357,6 +366,9 @@
if (mCustomAnimation != null) {
out.append(" customAnim=").append(mCustomAnimation.booleanValue());
}
+ if (mTaskFragmentToken != null) {
+ out.append(" taskFragmentToken=").append(mTaskFragmentToken);
+ }
out.append("}");
return out.toString();
}
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index ec79f94..14505f5 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -49,6 +49,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.Surface;
@@ -681,6 +682,7 @@
private float mSnapshotLuma;
private ComponentName mActivityComponent = null;
private AnimationOptions mAnimationOptions = null;
+ private IBinder mTaskFragmentToken = null;
public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) {
mContainer = container;
@@ -712,6 +714,7 @@
mSnapshotLuma = in.readFloat();
mActivityComponent = in.readTypedObject(ComponentName.CREATOR);
mAnimationOptions = in.readTypedObject(AnimationOptions.CREATOR);
+ mTaskFragmentToken = in.readStrongBinder();
}
private Change localRemoteCopy() {
@@ -737,6 +740,7 @@
out.mSnapshotLuma = mSnapshotLuma;
out.mActivityComponent = mActivityComponent;
out.mAnimationOptions = mAnimationOptions;
+ out.mTaskFragmentToken = mTaskFragmentToken;
return out;
}
@@ -854,6 +858,14 @@
mAnimationOptions = options;
}
+ /**
+ * Sets the client-defined TaskFragment token. Only set this if the window is a
+ * client-organized TaskFragment.
+ */
+ public void setTaskFragmentToken(@Nullable IBinder token) {
+ mTaskFragmentToken = token;
+ }
+
/** @return the container that is changing. May be null if non-remotable (eg. activity) */
@Nullable
public WindowContainerToken getContainer() {
@@ -1009,6 +1021,15 @@
return mAnimationOptions;
}
+ /**
+ * Returns the client-defined TaskFragment token. {@code null} if this window is not a
+ * client-organized TaskFragment.
+ */
+ @Nullable
+ public IBinder getTaskFragmentToken() {
+ return mTaskFragmentToken;
+ }
+
/** @hide */
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -1035,6 +1056,7 @@
dest.writeFloat(mSnapshotLuma);
dest.writeTypedObject(mActivityComponent, flags);
dest.writeTypedObject(mAnimationOptions, flags);
+ dest.writeStrongBinder(mTaskFragmentToken);
}
@NonNull
@@ -1110,6 +1132,9 @@
if (mAnimationOptions != null) {
sb.append(" opt=").append(mAnimationOptions);
}
+ if (mTaskFragmentToken != null) {
+ sb.append(" taskFragmentToken=").append(mTaskFragmentToken);
+ }
sb.append('}');
return sb.toString();
}
diff --git a/core/java/android/window/flags/DesktopModeFlags.java b/core/java/android/window/flags/DesktopModeFlags.java
index 5c53d66..944a106 100644
--- a/core/java/android/window/flags/DesktopModeFlags.java
+++ b/core/java/android/window/flags/DesktopModeFlags.java
@@ -17,7 +17,9 @@
package android.window.flags;
import android.annotation.Nullable;
-import android.content.Context;
+import android.app.ActivityThread;
+import android.app.Application;
+import android.content.ContentResolver;
import android.provider.Settings;
import android.util.Log;
@@ -39,9 +41,30 @@
*/
public enum DesktopModeFlags {
// All desktop mode related flags to be overridden by developer option toggle will be added here
- DESKTOP_WINDOWING_MODE(
+ ENABLE_DESKTOP_WINDOWING_MODE(
Flags::enableDesktopWindowingMode, /* shouldOverrideByDevOption= */ true),
- DYNAMIC_INITIAL_BOUNDS(Flags::enableWindowingDynamicInitialBounds, false);
+ ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS(Flags::enableWindowingDynamicInitialBounds, true),
+ ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION(
+ Flags::enableCaptionCompatInsetForceConsumption, true),
+ ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS(
+ Flags::enableCaptionCompatInsetForceConsumptionAlways, true),
+ ENABLE_CASCADING_WINDOWS(Flags::enableCascadingWindows, true),
+ ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY(
+ Flags::enableDesktopWindowingWallpaperActivity, true),
+ ENABLE_DESKTOP_WINDOWING_MODALS_POLICY(Flags::enableDesktopWindowingModalsPolicy, true),
+ ENABLE_THEMED_APP_HEADERS(Flags::enableThemedAppHeaders, true),
+ ENABLE_DESKTOP_WINDOWING_QUICK_SWITCH(Flags::enableDesktopWindowingQuickSwitch, true),
+ ENABLE_APP_HEADER_WITH_TASK_DENSITY(Flags::enableAppHeaderWithTaskDensity, true),
+ ENABLE_TASK_STACK_OBSERVER_IN_SHELL(Flags::enableTaskStackObserverInShell, true),
+ ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS(Flags::enableDesktopWindowingSizeConstraints, true),
+ DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE(Flags::disableNonResizableAppSnapResizing, true),
+ ENABLE_WINDOWING_SCALED_RESIZING(Flags::enableWindowingScaledResizing, true),
+ ENABLE_DESKTOP_WINDOWING_TASK_LIMIT(Flags::enableDesktopWindowingTaskLimit, true),
+ ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION(Flags::enableDesktopWindowingBackNavigation, true),
+ ENABLE_WINDOWING_EDGE_DRAG_RESIZE(Flags::enableWindowingEdgeDragResize, true),
+ ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS(
+ Flags::enableDesktopWindowingTaskbarRunningApps, true),
+ ENABLE_DESKTOP_WINDOWING_TRANSITIONS(Flags::enableDesktopWindowingTransitions, false);
private static final String TAG = "DesktopModeFlagsUtil";
// Function called to obtain aconfig flag value.
@@ -62,14 +85,15 @@
* Determines state of flag based on the actual flag and desktop mode developer option
* overrides.
*/
- public boolean isEnabled(Context context) {
+ public boolean isTrue() {
+ Application application = ActivityThread.currentApplication();
if (!Flags.showDesktopWindowingDevOption()
|| !mShouldOverrideByDevOption
- || context.getContentResolver() == null) {
+ || application == null) {
return mFlagFunction.get();
} else {
boolean shouldToggleBeEnabledByDefault = Flags.enableDesktopWindowingMode();
- return switch (getToggleOverride(context)) {
+ return switch (getToggleOverride(application.getContentResolver())) {
case OVERRIDE_UNSET -> mFlagFunction.get();
// When toggle override matches its default state, don't override flags. This
// helps users reset their feature overrides.
@@ -79,14 +103,14 @@
}
}
- private ToggleOverride getToggleOverride(Context context) {
+ private ToggleOverride getToggleOverride(ContentResolver contentResolver) {
// If cached, return it
if (sCachedToggleOverride != null) {
return sCachedToggleOverride;
}
// Otherwise, fetch and cache it
- ToggleOverride override = getToggleOverrideFromSystem(context);
+ ToggleOverride override = getToggleOverrideFromSystem(contentResolver);
sCachedToggleOverride = override;
Log.d(TAG, "Toggle override initialized to: " + override);
return override;
@@ -95,9 +119,9 @@
/**
* Returns {@link ToggleOverride} from Settings.Global set by toggle.
*/
- private ToggleOverride getToggleOverrideFromSystem(Context context) {
+ private ToggleOverride getToggleOverrideFromSystem(ContentResolver contentResolver) {
int settingValue = Settings.Global.getInt(
- context.getContentResolver(),
+ contentResolver,
Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES,
ToggleOverride.OVERRIDE_UNSET.getSetting()
);
@@ -105,12 +129,13 @@
}
/** Override state of desktop mode developer option toggle. */
- private enum ToggleOverride {
+ public enum ToggleOverride {
OVERRIDE_UNSET,
OVERRIDE_OFF,
OVERRIDE_ON;
- int getSetting() {
+ /** Returns the integer representation of this {@code ToggleOverride}. */
+ public int getSetting() {
return switch (this) {
case OVERRIDE_ON -> 1;
case OVERRIDE_OFF -> 0;
@@ -118,7 +143,8 @@
};
}
- static ToggleOverride fromSetting(int setting, @Nullable ToggleOverride fallback) {
+ /** Returns the {@code ToggleOverride} corresponding to a given integer setting. */
+ public static ToggleOverride fromSetting(int setting, @Nullable ToggleOverride fallback) {
return switch (setting) {
case 1 -> OVERRIDE_ON;
case 0 -> OVERRIDE_OFF;
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 13648de..9ae3fc1 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -122,3 +122,10 @@
description: "Requires apps to opt-in to overlay pass through touches and provide APIs to opt-in"
bug: "358129114"
}
+
+flag {
+ namespace: "windowing_sdk"
+ name: "wlinfo_oncreate"
+ description: "Makes WindowLayoutInfo accessible without racing in the Activity#onCreate()"
+ bug: "337820752"
+}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index c7e1fba..ef08e49 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -330,9 +330,10 @@
* @param cujType the specific {@link Cuj.CujType}.
* @return boolean true if the tracker is started successfully, false otherwise.
*/
- public boolean begin(SurfaceControl surface, Context context, @Cuj.CujType int cujType) {
+ public boolean begin(SurfaceControl surface, Context context, Handler handler,
+ @Cuj.CujType int cujType) {
try {
- return begin(Configuration.Builder.withSurface(cujType, context, surface));
+ return begin(Configuration.Builder.withSurface(cujType, context, surface, handler));
} catch (IllegalArgumentException ex) {
Log.d(TAG, "Build configuration failed!", ex);
return false;
@@ -348,11 +349,12 @@
* @param tag a tag containing extra information about the interaction.
* @return boolean true if the tracker is started successfully, false otherwise.
*/
- public boolean begin(SurfaceControl surface, Context context, @Cuj.CujType int cujType,
+ public boolean begin(SurfaceControl surface, Context context, Handler handler,
+ @Cuj.CujType int cujType,
String tag) {
try {
final Configuration.Builder builder =
- Configuration.Builder.withSurface(cujType, context, surface);
+ Configuration.Builder.withSurface(cujType, context, surface, handler);
if (!TextUtils.isEmpty(tag)) {
builder.setTag(tag);
}
@@ -689,20 +691,23 @@
private SurfaceControl mAttrSurfaceControl;
private final @Cuj.CujType int mAttrCujType;
private boolean mAttrDeferMonitor = true;
+ private Handler mHandler = null;
/**
* Creates a builder which instruments only surface.
* @param cuj The enum defined in {@link Cuj.CujType}.
* @param context context
* @param surfaceControl surface control
+ * @param uiThreadHandler UI thread for that surface
* @return builder
*/
public static Builder withSurface(@Cuj.CujType int cuj, @NonNull Context context,
- @NonNull SurfaceControl surfaceControl) {
+ @NonNull SurfaceControl surfaceControl, @NonNull Handler uiThreadHandler) {
return new Builder(cuj)
.setContext(context)
.setSurfaceControl(surfaceControl)
- .setSurfaceOnly(true);
+ .setSurfaceOnly(true)
+ .setHandler(uiThreadHandler);
}
/**
@@ -722,6 +727,18 @@
}
/**
+ * Specifies the UI thread handler. If not provided, the View's one will be used.
+ * If only a surface is provided without handler, the app main thread will be used.
+ *
+ * @param uiThreadHandler handler associated to the cuj UI thread
+ * @return builder
+ */
+ public Builder setHandler(Handler uiThreadHandler) {
+ mHandler = uiThreadHandler;
+ return this;
+ }
+
+ /**
* Specifies a view, must be set if {@link #setSurfaceOnly(boolean)} is set to false.
* @param view an attached view
* @return builder
@@ -798,13 +815,13 @@
return new Configuration(
mAttrCujType, mAttrView, mAttrTag, mAttrTimeout,
mAttrSurfaceOnly, mAttrContext, mAttrSurfaceControl,
- mAttrDeferMonitor);
+ mAttrDeferMonitor, mHandler);
}
}
private Configuration(@Cuj.CujType int cuj, View view, @NonNull String tag, long timeout,
boolean surfaceOnly, Context context, SurfaceControl surfaceControl,
- boolean deferMonitor) {
+ boolean deferMonitor, Handler handler) {
mCujType = cuj;
mTag = tag;
mSessionName = generateSessionName(Cuj.getNameOfCuj(cuj), tag);
@@ -816,8 +833,16 @@
: (view != null ? view.getContext().getApplicationContext() : null);
mSurfaceControl = surfaceControl;
mDeferMonitor = deferMonitor;
+ if (handler != null) {
+ mHandler = handler;
+ } else if (mSurfaceOnly) {
+ Log.w(TAG, "No UIThread provided for " + mSessionName
+ + " (surface only). Defaulting to app main thread.");
+ mHandler = mContext.getMainThreadHandler();
+ } else {
+ mHandler = mView.getHandler();
+ }
validate();
- mHandler = mSurfaceOnly ? mContext.getMainThreadHandler() : mView.getHandler();
}
@VisibleForTesting
@@ -858,6 +883,12 @@
shouldThrow = true;
msg.append("Must pass in a valid surface control if only instrument surface; ");
}
+ if (mHandler == null) {
+ shouldThrow = true;
+ msg.append(
+ "Must pass a UI thread handler when only a surface control is "
+ + "provided.");
+ }
} else {
if (!hasValidView()) {
shouldThrow = true;
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 4708be8..6faea17 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -38,6 +38,8 @@
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.flags.Flags.customizableWindowHeaders;
+import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
+import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL;
@@ -114,7 +116,6 @@
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.BackgroundFallback;
import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
-import com.android.window.flags.Flags;
import java.util.List;
import java.util.concurrent.Executor;
@@ -1217,14 +1218,15 @@
final boolean hideCaptionBar = fullscreen
|| (requestedVisibleTypes & WindowInsets.Type.captionBar()) == 0;
- final boolean consumingCaptionBar = Flags.enableCaptionCompatInsetForceConsumption()
- && ((mLastForceConsumingTypes & WindowInsets.Type.captionBar()) != 0
+ final boolean consumingCaptionBar =
+ ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isTrue()
+ && ((mLastForceConsumingTypes & WindowInsets.Type.captionBar()) != 0
&& hideCaptionBar);
final boolean isOpaqueCaptionBar = customizableWindowHeaders()
&& (appearance & APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND) == 0;
final boolean consumingOpaqueCaptionBar =
- Flags.enableCaptionCompatInsetForceConsumptionAlways()
+ ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS.isTrue()
&& mLastForceConsumingOpaqueCaptionBar
&& isOpaqueCaptionBar;
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
index e440dc9..fbc058c 100644
--- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -210,6 +210,8 @@
DataSourceParams
.PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP)
.build();
+ // NOTE: Registering that datasource is an async operation, so there may be no data traced
+ // for some messages logged right after the construction of this class.
mDataSource.register(params);
this.mViewerConfigInputStreamProvider = viewerConfigInputStreamProvider;
this.mViewerConfigReader = viewerConfigReader;
@@ -223,17 +225,17 @@
"ServiceManager returned a null ProtoLog Configuration Service");
try {
- var args = new ProtoLogConfigurationService.RegisterClientArgs();
+ var args = new ProtoLogConfigurationServiceImpl.RegisterClientArgs();
if (viewerConfigFilePath != null) {
args.setViewerConfigFile(viewerConfigFilePath);
}
final var groupArgs = Stream.of(groups)
- .map(group -> new ProtoLogConfigurationService.RegisterClientArgs
+ .map(group -> new ProtoLogConfigurationServiceImpl.RegisterClientArgs
.GroupConfig(group.name(), group.isLogToLogcat()))
- .toArray(
- ProtoLogConfigurationService.RegisterClientArgs.GroupConfig[]::new);
+ .toArray(ProtoLogConfigurationServiceImpl
+ .RegisterClientArgs.GroupConfig[]::new);
args.setGroups(groupArgs);
mProtoLogConfigurationService.registerClient(this, args);
diff --git a/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java b/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java
index 7031d69..d65aaae 100644
--- a/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java
+++ b/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java
@@ -16,434 +16,32 @@
package com.android.internal.protolog;
-import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.GROUPS;
-import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.Group.ID;
-import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.Group.NAME;
-import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.Group.TAG;
-import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MESSAGES;
-import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.GROUP_ID;
-import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.LEVEL;
-import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.LOCATION;
-import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.MESSAGE;
-import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.MESSAGE_ID;
-
import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemService;
-import android.content.Context;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.ShellCallback;
-import android.tracing.perfetto.DataSourceParams;
-import android.tracing.perfetto.InitArguments;
-import android.tracing.perfetto.Producer;
-import android.util.Log;
-import android.util.proto.ProtoInputStream;
-import android.util.proto.ProtoOutputStream;
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-/**
- * The ProtoLog service is responsible for orchestrating centralized actions of the protolog tracing
- * system. Currently this service has the following roles:
- * - Handle shell commands to toggle logging ProtoLog messages for specified groups to logcat.
- * - Handle viewer config dumping (the mapping from message hash to message string) for all protolog
- * clients. This is for two reasons: firstly, because client processes might be frozen so might
- * not response to the request to dump their viewer config when the trace is stopped; secondly,
- * multiple processes might be running the same code with the same viewer config, this centralized
- * service ensures we don't dump the same viewer config multiple times across processes.
- * <p>
- * {@link com.android.internal.protolog.IProtoLogClient ProtoLog clients} register themselves to
- * this service on initialization.
- * <p>
- * This service is intended to run on the system server, such that it never gets frozen.
- */
-@SystemService(Context.PROTOLOG_CONFIGURATION_SERVICE)
-public final class ProtoLogConfigurationService extends IProtoLogConfigurationService.Stub {
- private static final String LOG_TAG = "ProtoLogConfigurationService";
-
- private final ProtoLogDataSource mDataSource;
-
- /**
- * Keeps track of how many of each viewer config file is currently registered.
- * Use to keep track of which viewer config files are actively being used in tracing and might
- * need to be dumped on flush.
- */
- private final Map<String, Integer> mConfigFileCounts = new HashMap<>();
- /**
- * Keeps track of the viewer config file of each client if available.
- */
- private final Map<IProtoLogClient, String> mClientConfigFiles = new HashMap<>();
-
- /**
- * Keeps track of all the protolog groups that have been registered by clients and are still
- * being actively traced.
- */
- private final Set<String> mRegisteredGroups = new HashSet<>();
- /**
- * Keeps track of all the clients that are actively tracing a given protolog group.
- */
- private final Map<String, Set<IProtoLogClient>> mGroupToClients = new HashMap<>();
-
- /**
- * Keeps track of whether or not a given group should be logged to logcat.
- * True when logging to logcat, false otherwise.
- */
- private final Map<String, Boolean> mLogGroupToLogcatStatus = new TreeMap<>();
-
- /**
- * Keeps track of all the tracing instance ids that are actively running for ProtoLog.
- */
- private final Set<Integer> mRunningInstances = new HashSet<>();
-
- private final ViewerConfigFileTracer mViewerConfigFileTracer;
-
- public ProtoLogConfigurationService() {
- this(ProtoLogDataSource::new, ProtoLogConfigurationService::dumpTransitionTraceConfig);
- }
-
- @VisibleForTesting
- public ProtoLogConfigurationService(@NonNull ProtoLogDataSourceBuilder dataSourceBuilder) {
- this(dataSourceBuilder, ProtoLogConfigurationService::dumpTransitionTraceConfig);
- }
-
- @VisibleForTesting
- public ProtoLogConfigurationService(@NonNull ViewerConfigFileTracer tracer) {
- this(ProtoLogDataSource::new, tracer);
- }
-
- @VisibleForTesting
- public ProtoLogConfigurationService(
- @NonNull ProtoLogDataSourceBuilder dataSourceBuilder,
- @NonNull ViewerConfigFileTracer tracer) {
- mDataSource = dataSourceBuilder.build(
- this::onTracingInstanceStart,
- this::onTracingInstanceFlush,
- this::onTracingInstanceStop
- );
-
- // Initialize the Perfetto producer and register the Perfetto ProtoLog datasource to be
- // receive the lifecycle callbacks of the datasource and write the viewer configs if and
- // when required to the datasource.
- Producer.init(InitArguments.DEFAULTS);
- final var params = new DataSourceParams.Builder()
- .setBufferExhaustedPolicy(DataSourceParams.PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP)
- .build();
- mDataSource.register(params);
-
- mViewerConfigFileTracer = tracer;
- }
-
- public static class RegisterClientArgs extends IRegisterClientArgs.Stub {
- /**
- * The viewer config file to be registered for this client ProtoLog process.
- */
- @Nullable
- private String mViewerConfigFile = null;
- /**
- * The list of all groups that this client protolog process supports and might trace.
- */
- @NonNull
- private String[] mGroups = new String[0];
- /**
- * The default logcat status of the ProtoLog client. True is logging to logcat, false
- * otherwise. The indices should match the indices in {@link mGroups}.
- */
- @NonNull
- private boolean[] mLogcatStatus = new boolean[0];
-
- public record GroupConfig(@NonNull String group, boolean logToLogcat) {}
-
- /**
- * Specify groups to register with this client that will be used for protologging in this
- * process.
- * @param groups to register with this client.
- * @return self
- */
- public RegisterClientArgs setGroups(GroupConfig... groups) {
- mGroups = new String[groups.length];
- mLogcatStatus = new boolean[groups.length];
-
- for (int i = 0; i < groups.length; i++) {
- mGroups[i] = groups[i].group;
- mLogcatStatus[i] = groups[i].logToLogcat;
- }
-
- return this;
- }
-
- /**
- * Set the viewer config file that the logs in this process are using.
- * @param viewerConfigFile The file path of the viewer config.
- * @return self
- */
- public RegisterClientArgs setViewerConfigFile(@NonNull String viewerConfigFile) {
- mViewerConfigFile = viewerConfigFile;
-
- return this;
- }
-
- @Override
- @NonNull
- public String[] getGroups() {
- return mGroups;
- }
-
- @Override
- @NonNull
- public boolean[] getGroupsDefaultLogcatStatus() {
- return mLogcatStatus;
- }
-
- @Nullable
- @Override
- public String getViewerConfigFile() {
- return mViewerConfigFile;
- }
- }
-
- @FunctionalInterface
- public interface ViewerConfigFileTracer {
- /**
- * Write the viewer config data to the trace buffer.
- *
- * @param dataSource The target datasource to write the viewer config to.
- * @param viewerConfigFilePath The path of the viewer config file which contains the data we
- * want to write to the trace buffer.
- * @throws FileNotFoundException if the viewerConfigFilePath is invalid.
- */
- void trace(@NonNull ProtoLogDataSource dataSource, @NonNull String viewerConfigFilePath);
- }
-
- @Override
- public void registerClient(@NonNull IProtoLogClient client, @NonNull IRegisterClientArgs args)
- throws RemoteException {
- client.asBinder().linkToDeath(() -> onClientBinderDeath(client), /* flags */ 0);
-
- final String viewerConfigFile = args.getViewerConfigFile();
- if (viewerConfigFile != null) {
- registerViewerConfigFile(client, viewerConfigFile);
- }
-
- registerGroups(client, args.getGroups(), args.getGroupsDefaultLogcatStatus());
- }
-
- @Override
- public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
- @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback callback,
- @NonNull ResultReceiver resultReceiver) throws RemoteException {
- new ProtoLogCommandHandler(this)
- .exec(this, in, out, err, args, callback, resultReceiver);
- }
-
+public interface ProtoLogConfigurationService extends IProtoLogConfigurationService {
/**
* Get the list of groups clients have registered to the protolog service.
* @return The list of ProtoLog groups registered with this service.
*/
@NonNull
- public String[] getGroups() {
- return mRegisteredGroups.toArray(new String[0]);
- }
-
- /**
- * Enable logging target groups to logcat.
- * @param groups we want to enable logging them to logcat for.
- */
- public void enableProtoLogToLogcat(String... groups) {
- toggleProtoLogToLogcat(true, groups);
- }
-
- /**
- * Disable logging target groups to logcat.
- * @param groups we want to disable from being logged to logcat.
- */
- public void disableProtoLogToLogcat(String... groups) {
- toggleProtoLogToLogcat(false, groups);
- }
+ String[] getGroups();
/**
* Check if a group is logging to logcat
* @param group The group we want to check for
* @return True iff we are logging this group to logcat.
*/
- public boolean isLoggingToLogcat(@NonNull String group) {
- final Boolean isLoggingToLogcat = mLogGroupToLogcatStatus.get(group);
+ boolean isLoggingToLogcat(@NonNull String group);
- if (isLoggingToLogcat == null) {
- throw new RuntimeException(
- "Trying to get logcat logging status of non-registered group " + group);
- }
+ /**
+ * Enable logging target groups to logcat.
+ * @param groups we want to enable logging them to logcat for.
+ */
+ void enableProtoLogToLogcat(@NonNull String... groups);
- return isLoggingToLogcat;
- }
-
- private void registerViewerConfigFile(
- @NonNull IProtoLogClient client, @NonNull String viewerConfigFile) {
- final var count = mConfigFileCounts.getOrDefault(viewerConfigFile, 0);
- mConfigFileCounts.put(viewerConfigFile, count + 1);
- mClientConfigFiles.put(client, viewerConfigFile);
- }
-
- private void registerGroups(@NonNull IProtoLogClient client, @NonNull String[] groups,
- @NonNull boolean[] logcatStatuses) throws RemoteException {
- if (groups.length != logcatStatuses.length) {
- throw new RuntimeException(
- "Expected groups and logcatStatuses to have the same length, "
- + "but groups has length " + groups.length
- + " and logcatStatuses has length " + logcatStatuses.length);
- }
-
- for (int i = 0; i < groups.length; i++) {
- String group = groups[i];
- boolean logcatStatus = logcatStatuses[i];
-
- mRegisteredGroups.add(group);
-
- mGroupToClients.putIfAbsent(group, new HashSet<>());
- mGroupToClients.get(group).add(client);
-
- if (!mLogGroupToLogcatStatus.containsKey(group)) {
- mLogGroupToLogcatStatus.put(group, logcatStatus);
- }
-
- boolean requestedLogToLogcat = mLogGroupToLogcatStatus.get(group);
- if (requestedLogToLogcat != logcatStatus) {
- client.toggleLogcat(requestedLogToLogcat, new String[] { group });
- }
- }
- }
-
- private void toggleProtoLogToLogcat(boolean enabled, @NonNull String[] groups) {
- final var clientToGroups = new HashMap<IProtoLogClient, Set<String>>();
-
- for (String group : groups) {
- final var clients = mGroupToClients.get(group);
-
- if (clients == null) {
- // No clients associated to this group
- Log.w(LOG_TAG, "Attempting to toggle log to logcat for group " + group
- + " with no registered clients.");
- continue;
- }
-
- for (IProtoLogClient client : clients) {
- clientToGroups.putIfAbsent(client, new HashSet<>());
- clientToGroups.get(client).add(group);
- }
- }
-
- for (IProtoLogClient client : clientToGroups.keySet()) {
- try {
- client.toggleLogcat(enabled, clientToGroups.get(client).toArray(new String[0]));
- } catch (RemoteException e) {
- throw new RuntimeException(
- "Failed to toggle logcat status for groups on client", e);
- }
- }
-
- for (String group : groups) {
- mLogGroupToLogcatStatus.put(group, enabled);
- }
- }
-
- private void onTracingInstanceStart(int instanceIdx, ProtoLogDataSource.ProtoLogConfig config) {
- mRunningInstances.add(instanceIdx);
- }
-
- private void onTracingInstanceFlush() {
- for (String fileName : mConfigFileCounts.keySet()) {
- mViewerConfigFileTracer.trace(mDataSource, fileName);
- }
- }
-
- private void onTracingInstanceStop(int instanceIdx, ProtoLogDataSource.ProtoLogConfig config) {
- mRunningInstances.remove(instanceIdx);
- }
-
- private static void dumpTransitionTraceConfig(@NonNull ProtoLogDataSource dataSource,
- @NonNull String viewerConfigFilePath) {
- Utils.dumpViewerConfig(dataSource, () -> {
- try {
- return new ProtoInputStream(new FileInputStream(viewerConfigFilePath));
- } catch (FileNotFoundException e) {
- throw new RuntimeException(
- "Failed to load viewer config file " + viewerConfigFilePath, e);
- }
- });
- }
-
- private void onClientBinderDeath(@NonNull IProtoLogClient client) {
- // Dump the tracing config now if no other client is going to dump the same config file.
- String configFile = mClientConfigFiles.get(client);
- if (configFile != null) {
- final var newCount = mConfigFileCounts.get(configFile) - 1;
- mConfigFileCounts.put(configFile, newCount);
- boolean lastProcessWithViewerConfig = newCount == 0;
- if (lastProcessWithViewerConfig) {
- mViewerConfigFileTracer.trace(mDataSource, configFile);
- }
- }
- }
-
- private static void writeViewerConfigGroup(
- @NonNull ProtoInputStream pis, @NonNull ProtoOutputStream os) throws IOException {
- final long inGroupToken = pis.start(GROUPS);
- final long outGroupToken = os.start(GROUPS);
-
- while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
- switch (pis.getFieldNumber()) {
- case (int) ID -> {
- int id = pis.readInt(ID);
- os.write(ID, id);
- }
- case (int) NAME -> {
- String name = pis.readString(NAME);
- os.write(NAME, name);
- }
- case (int) TAG -> {
- String tag = pis.readString(TAG);
- os.write(TAG, tag);
- }
- default ->
- throw new RuntimeException(
- "Unexpected field id " + pis.getFieldNumber());
- }
- }
-
- pis.end(inGroupToken);
- os.end(outGroupToken);
- }
-
- private static void writeViewerConfigMessage(
- @NonNull ProtoInputStream pis, @NonNull ProtoOutputStream os) throws IOException {
- final long inMessageToken = pis.start(MESSAGES);
- final long outMessagesToken = os.start(MESSAGES);
-
- while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
- switch (pis.getFieldNumber()) {
- case (int) MESSAGE_ID -> os.write(MESSAGE_ID,
- pis.readLong(MESSAGE_ID));
- case (int) MESSAGE -> os.write(MESSAGE, pis.readString(MESSAGE));
- case (int) LEVEL -> os.write(LEVEL, pis.readInt(LEVEL));
- case (int) GROUP_ID -> os.write(GROUP_ID, pis.readInt(GROUP_ID));
- case (int) LOCATION -> os.write(LOCATION, pis.readString(LOCATION));
- default ->
- throw new RuntimeException(
- "Unexpected field id " + pis.getFieldNumber());
- }
- }
-
- pis.end(inMessageToken);
- os.end(outMessagesToken);
- }
+ /**
+ * Disable logging target groups to logcat.
+ * @param groups we want to disable from being logged to logcat.
+ */
+ void disableProtoLogToLogcat(@NonNull String... groups);
}
diff --git a/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java b/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
new file mode 100644
index 0000000..e382ac1
--- /dev/null
+++ b/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.protolog;
+
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.GROUPS;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.Group.ID;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.Group.NAME;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.Group.TAG;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MESSAGES;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.GROUP_ID;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.LEVEL;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.LOCATION;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.MESSAGE;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.MESSAGE_ID;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.tracing.perfetto.DataSourceParams;
+import android.tracing.perfetto.InitArguments;
+import android.tracing.perfetto.Producer;
+import android.util.Log;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+/**
+ * The ProtoLog service is responsible for orchestrating centralized actions of the protolog tracing
+ * system. Currently this service has the following roles:
+ * - Handle shell commands to toggle logging ProtoLog messages for specified groups to logcat.
+ * - Handle viewer config dumping (the mapping from message hash to message string) for all protolog
+ * clients. This is for two reasons: firstly, because client processes might be frozen so might
+ * not response to the request to dump their viewer config when the trace is stopped; secondly,
+ * multiple processes might be running the same code with the same viewer config, this centralized
+ * service ensures we don't dump the same viewer config multiple times across processes.
+ * <p>
+ * {@link com.android.internal.protolog.IProtoLogClient ProtoLog clients} register themselves to
+ * this service on initialization.
+ * <p>
+ * This service is intended to run on the system server, such that it never gets frozen.
+ */
+@SystemService(Context.PROTOLOG_CONFIGURATION_SERVICE)
+public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationService.Stub
+ implements ProtoLogConfigurationService {
+ private static final String LOG_TAG = "ProtoLogConfigurationService";
+
+ private final ProtoLogDataSource mDataSource;
+
+ /**
+ * Keeps track of how many of each viewer config file is currently registered.
+ * Use to keep track of which viewer config files are actively being used in tracing and might
+ * need to be dumped on flush.
+ */
+ private final Map<String, Integer> mConfigFileCounts = new HashMap<>();
+ /**
+ * Keeps track of the viewer config file of each client if available.
+ */
+ private final Map<IProtoLogClient, String> mClientConfigFiles = new HashMap<>();
+
+ /**
+ * Keeps track of all the protolog groups that have been registered by clients and are still
+ * being actively traced.
+ */
+ private final Set<String> mRegisteredGroups = new HashSet<>();
+ /**
+ * Keeps track of all the clients that are actively tracing a given protolog group.
+ */
+ private final Map<String, Set<IProtoLogClient>> mGroupToClients = new HashMap<>();
+
+ /**
+ * Keeps track of whether or not a given group should be logged to logcat.
+ * True when logging to logcat, false otherwise.
+ */
+ private final Map<String, Boolean> mLogGroupToLogcatStatus = new TreeMap<>();
+
+ /**
+ * Keeps track of all the tracing instance ids that are actively running for ProtoLog.
+ */
+ private final Set<Integer> mRunningInstances = new HashSet<>();
+
+ private final ViewerConfigFileTracer mViewerConfigFileTracer;
+
+ public ProtoLogConfigurationServiceImpl() {
+ this(ProtoLogDataSource::new, ProtoLogConfigurationServiceImpl::dumpTransitionTraceConfig);
+ }
+
+ @VisibleForTesting
+ public ProtoLogConfigurationServiceImpl(@NonNull ProtoLogDataSourceBuilder dataSourceBuilder) {
+ this(dataSourceBuilder, ProtoLogConfigurationServiceImpl::dumpTransitionTraceConfig);
+ }
+
+ @VisibleForTesting
+ public ProtoLogConfigurationServiceImpl(@NonNull ViewerConfigFileTracer tracer) {
+ this(ProtoLogDataSource::new, tracer);
+ }
+
+ @VisibleForTesting
+ public ProtoLogConfigurationServiceImpl(
+ @NonNull ProtoLogDataSourceBuilder dataSourceBuilder,
+ @NonNull ViewerConfigFileTracer tracer) {
+ mDataSource = dataSourceBuilder.build(
+ this::onTracingInstanceStart,
+ this::onTracingInstanceFlush,
+ this::onTracingInstanceStop
+ );
+
+ // Initialize the Perfetto producer and register the Perfetto ProtoLog datasource to be
+ // receive the lifecycle callbacks of the datasource and write the viewer configs if and
+ // when required to the datasource.
+ Producer.init(InitArguments.DEFAULTS);
+ final var params = new DataSourceParams.Builder()
+ .setBufferExhaustedPolicy(DataSourceParams.PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP)
+ .build();
+ mDataSource.register(params);
+
+ mViewerConfigFileTracer = tracer;
+ }
+
+ public static class RegisterClientArgs extends IRegisterClientArgs.Stub {
+ /**
+ * The viewer config file to be registered for this client ProtoLog process.
+ */
+ @Nullable
+ private String mViewerConfigFile = null;
+ /**
+ * The list of all groups that this client protolog process supports and might trace.
+ */
+ @NonNull
+ private String[] mGroups = new String[0];
+ /**
+ * The default logcat status of the ProtoLog client. True is logging to logcat, false
+ * otherwise. The indices should match the indices in {@link mGroups}.
+ */
+ @NonNull
+ private boolean[] mLogcatStatus = new boolean[0];
+
+ public record GroupConfig(@NonNull String group, boolean logToLogcat) {}
+
+ /**
+ * Specify groups to register with this client that will be used for protologging in this
+ * process.
+ * @param groups to register with this client.
+ * @return self
+ */
+ public RegisterClientArgs setGroups(GroupConfig... groups) {
+ mGroups = new String[groups.length];
+ mLogcatStatus = new boolean[groups.length];
+
+ for (int i = 0; i < groups.length; i++) {
+ mGroups[i] = groups[i].group;
+ mLogcatStatus[i] = groups[i].logToLogcat;
+ }
+
+ return this;
+ }
+
+ /**
+ * Set the viewer config file that the logs in this process are using.
+ * @param viewerConfigFile The file path of the viewer config.
+ * @return self
+ */
+ public RegisterClientArgs setViewerConfigFile(@NonNull String viewerConfigFile) {
+ mViewerConfigFile = viewerConfigFile;
+
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public String[] getGroups() {
+ return mGroups;
+ }
+
+ @Override
+ @NonNull
+ public boolean[] getGroupsDefaultLogcatStatus() {
+ return mLogcatStatus;
+ }
+
+ @Nullable
+ @Override
+ public String getViewerConfigFile() {
+ return mViewerConfigFile;
+ }
+ }
+
+ @FunctionalInterface
+ public interface ViewerConfigFileTracer {
+ /**
+ * Write the viewer config data to the trace buffer.
+ *
+ * @param dataSource The target datasource to write the viewer config to.
+ * @param viewerConfigFilePath The path of the viewer config file which contains the data we
+ * want to write to the trace buffer.
+ * @throws FileNotFoundException if the viewerConfigFilePath is invalid.
+ */
+ void trace(@NonNull ProtoLogDataSource dataSource, @NonNull String viewerConfigFilePath);
+ }
+
+ @Override
+ public void registerClient(@NonNull IProtoLogClient client, @NonNull IRegisterClientArgs args)
+ throws RemoteException {
+ client.asBinder().linkToDeath(() -> onClientBinderDeath(client), /* flags */ 0);
+
+ final String viewerConfigFile = args.getViewerConfigFile();
+ if (viewerConfigFile != null) {
+ registerViewerConfigFile(client, viewerConfigFile);
+ }
+
+ registerGroups(client, args.getGroups(), args.getGroupsDefaultLogcatStatus());
+ }
+
+ @Override
+ public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
+ @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback callback,
+ @NonNull ResultReceiver resultReceiver) throws RemoteException {
+ new ProtoLogCommandHandler(this)
+ .exec(this, in, out, err, args, callback, resultReceiver);
+ }
+
+ /**
+ * Get the list of groups clients have registered to the protolog service.
+ * @return The list of ProtoLog groups registered with this service.
+ */
+ @Override
+ @NonNull
+ public String[] getGroups() {
+ return mRegisteredGroups.toArray(new String[0]);
+ }
+
+ /**
+ * Enable logging target groups to logcat.
+ * @param groups we want to enable logging them to logcat for.
+ */
+ @Override
+ public void enableProtoLogToLogcat(@NonNull String... groups) {
+ toggleProtoLogToLogcat(true, groups);
+ }
+
+ /**
+ * Disable logging target groups to logcat.
+ * @param groups we want to disable from being logged to logcat.
+ */
+ @Override
+ public void disableProtoLogToLogcat(@NonNull String... groups) {
+ toggleProtoLogToLogcat(false, groups);
+ }
+
+ /**
+ * Check if a group is logging to logcat
+ * @param group The group we want to check for
+ * @return True iff we are logging this group to logcat.
+ */
+ @Override
+ public boolean isLoggingToLogcat(@NonNull String group) {
+ final Boolean isLoggingToLogcat = mLogGroupToLogcatStatus.get(group);
+
+ if (isLoggingToLogcat == null) {
+ throw new RuntimeException(
+ "Trying to get logcat logging status of non-registered group " + group);
+ }
+
+ return isLoggingToLogcat;
+ }
+
+ private void registerViewerConfigFile(
+ @NonNull IProtoLogClient client, @NonNull String viewerConfigFile) {
+ final var count = mConfigFileCounts.getOrDefault(viewerConfigFile, 0);
+ mConfigFileCounts.put(viewerConfigFile, count + 1);
+ mClientConfigFiles.put(client, viewerConfigFile);
+ }
+
+ private void registerGroups(@NonNull IProtoLogClient client, @NonNull String[] groups,
+ @NonNull boolean[] logcatStatuses) throws RemoteException {
+ if (groups.length != logcatStatuses.length) {
+ throw new RuntimeException(
+ "Expected groups and logcatStatuses to have the same length, "
+ + "but groups has length " + groups.length
+ + " and logcatStatuses has length " + logcatStatuses.length);
+ }
+
+ for (int i = 0; i < groups.length; i++) {
+ String group = groups[i];
+ boolean logcatStatus = logcatStatuses[i];
+
+ mRegisteredGroups.add(group);
+
+ mGroupToClients.putIfAbsent(group, new HashSet<>());
+ mGroupToClients.get(group).add(client);
+
+ if (!mLogGroupToLogcatStatus.containsKey(group)) {
+ mLogGroupToLogcatStatus.put(group, logcatStatus);
+ }
+
+ boolean requestedLogToLogcat = mLogGroupToLogcatStatus.get(group);
+ if (requestedLogToLogcat != logcatStatus) {
+ client.toggleLogcat(requestedLogToLogcat, new String[] { group });
+ }
+ }
+ }
+
+ private void toggleProtoLogToLogcat(boolean enabled, @NonNull String[] groups) {
+ final var clientToGroups = new HashMap<IProtoLogClient, Set<String>>();
+
+ for (String group : groups) {
+ final var clients = mGroupToClients.get(group);
+
+ if (clients == null) {
+ // No clients associated to this group
+ Log.w(LOG_TAG, "Attempting to toggle log to logcat for group " + group
+ + " with no registered clients.");
+ continue;
+ }
+
+ for (IProtoLogClient client : clients) {
+ clientToGroups.putIfAbsent(client, new HashSet<>());
+ clientToGroups.get(client).add(group);
+ }
+ }
+
+ for (IProtoLogClient client : clientToGroups.keySet()) {
+ try {
+ client.toggleLogcat(enabled, clientToGroups.get(client).toArray(new String[0]));
+ } catch (RemoteException e) {
+ throw new RuntimeException(
+ "Failed to toggle logcat status for groups on client", e);
+ }
+ }
+
+ for (String group : groups) {
+ mLogGroupToLogcatStatus.put(group, enabled);
+ }
+ }
+
+ private void onTracingInstanceStart(int instanceIdx, ProtoLogDataSource.ProtoLogConfig config) {
+ mRunningInstances.add(instanceIdx);
+ }
+
+ private void onTracingInstanceFlush() {
+ for (String fileName : mConfigFileCounts.keySet()) {
+ mViewerConfigFileTracer.trace(mDataSource, fileName);
+ }
+ }
+
+ private void onTracingInstanceStop(int instanceIdx, ProtoLogDataSource.ProtoLogConfig config) {
+ mRunningInstances.remove(instanceIdx);
+ }
+
+ private static void dumpTransitionTraceConfig(@NonNull ProtoLogDataSource dataSource,
+ @NonNull String viewerConfigFilePath) {
+ Utils.dumpViewerConfig(dataSource, () -> {
+ try {
+ return new ProtoInputStream(new FileInputStream(viewerConfigFilePath));
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(
+ "Failed to load viewer config file " + viewerConfigFilePath, e);
+ }
+ });
+ }
+
+ private void onClientBinderDeath(@NonNull IProtoLogClient client) {
+ // Dump the tracing config now if no other client is going to dump the same config file.
+ String configFile = mClientConfigFiles.get(client);
+ if (configFile != null) {
+ final var newCount = mConfigFileCounts.get(configFile) - 1;
+ mConfigFileCounts.put(configFile, newCount);
+ boolean lastProcessWithViewerConfig = newCount == 0;
+ if (lastProcessWithViewerConfig) {
+ mViewerConfigFileTracer.trace(mDataSource, configFile);
+ }
+ }
+ }
+
+ private static void writeViewerConfigGroup(
+ @NonNull ProtoInputStream pis, @NonNull ProtoOutputStream os) throws IOException {
+ final long inGroupToken = pis.start(GROUPS);
+ final long outGroupToken = os.start(GROUPS);
+
+ while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (pis.getFieldNumber()) {
+ case (int) ID -> {
+ int id = pis.readInt(ID);
+ os.write(ID, id);
+ }
+ case (int) NAME -> {
+ String name = pis.readString(NAME);
+ os.write(NAME, name);
+ }
+ case (int) TAG -> {
+ String tag = pis.readString(TAG);
+ os.write(TAG, tag);
+ }
+ default ->
+ throw new RuntimeException(
+ "Unexpected field id " + pis.getFieldNumber());
+ }
+ }
+
+ pis.end(inGroupToken);
+ os.end(outGroupToken);
+ }
+
+ private static void writeViewerConfigMessage(
+ @NonNull ProtoInputStream pis, @NonNull ProtoOutputStream os) throws IOException {
+ final long inMessageToken = pis.start(MESSAGES);
+ final long outMessagesToken = os.start(MESSAGES);
+
+ while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (pis.getFieldNumber()) {
+ case (int) MESSAGE_ID -> os.write(MESSAGE_ID,
+ pis.readLong(MESSAGE_ID));
+ case (int) MESSAGE -> os.write(MESSAGE, pis.readString(MESSAGE));
+ case (int) LEVEL -> os.write(LEVEL, pis.readInt(LEVEL));
+ case (int) GROUP_ID -> os.write(GROUP_ID, pis.readInt(GROUP_ID));
+ case (int) LOCATION -> os.write(LOCATION, pis.readString(LOCATION));
+ default ->
+ throw new RuntimeException(
+ "Unexpected field id " + pis.getFieldNumber());
+ }
+ }
+
+ pis.end(inMessageToken);
+ os.end(outMessagesToken);
+ }
+}
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index b73cacb..bdb33c4 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -33,8 +33,6 @@
import android.widget.RadioButton;
import android.widget.TextView;
-import com.android.text.flags.Flags;
-
/**
* The item view for each item in the ListView-based MenuViews.
*/
@@ -283,10 +281,7 @@
private void insertIconView() {
LayoutInflater inflater = getInflater();
- mIconView = (ImageView) inflater.inflate(
- !Flags.fixMisalignedContextMenu()
- ? com.android.internal.R.layout.list_menu_item_fixed_size_icon :
- com.android.internal.R.layout.list_menu_item_icon,
+ mIconView = (ImageView) inflater.inflate(com.android.internal.R.layout.list_menu_item_icon,
this, false);
addContentView(mIconView, 0);
}
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index c43a8c6..8e2536a 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -35,8 +35,6 @@
import android.widget.PopupWindow.OnDismissListener;
import android.widget.TextView;
-import com.android.text.flags.Flags;
-
import java.util.Objects;
/**
@@ -122,8 +120,7 @@
mMenu = menu;
mOverflowOnly = overflowOnly;
final LayoutInflater inflater = LayoutInflater.from(context);
- mAdapter = new MenuAdapter(menu, inflater, mOverflowOnly,
- Flags.fixMisalignedContextMenu() ? ITEM_LAYOUT_MATERIAL : ITEM_LAYOUT);
+ mAdapter = new MenuAdapter(menu, inflater, mOverflowOnly, ITEM_LAYOUT_MATERIAL);
mPopupStyleAttr = popupStyleAttr;
mPopupStyleRes = popupStyleRes;
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 90cb10a..9a4ff8f 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -290,7 +290,6 @@
"libasync_safe",
"libbinderthreadstateutils",
"libdmabufinfo",
- "libgif",
"libgui_window_info_static",
"libkernelconfigs",
"libnativehelper_lazy",
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index a022842..b1221ee 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -190,18 +190,25 @@
return -1;
}
- jbyte* bufferBytes = NULL;
- if (buffer) {
- bufferBytes = (jbyte*)env->GetPrimitiveArrayCritical(buffer, NULL);
+ bool is_dir_in = (endpoint & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN;
+ std::unique_ptr<jbyte[]> bufferBytes(new (std::nothrow) jbyte[length]);
+ if (!bufferBytes) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return -1;
}
- jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes + start, length, timeout);
-
- if (bufferBytes) {
- env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0);
+ if (!is_dir_in && buffer) {
+ env->GetByteArrayRegion(buffer, start, length, bufferBytes.get());
}
- return result;
+ jint bytes_transferred =
+ usb_device_bulk_transfer(device, endpoint, bufferBytes.get(), length, timeout);
+
+ if (bytes_transferred > 0 && is_dir_in) {
+ env->SetByteArrayRegion(buffer, start, bytes_transferred, bufferBytes.get());
+ }
+
+ return bytes_transferred;
}
static jobject
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index f2c70b5..8003bb7 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -1747,9 +1747,9 @@
{"linkToDeathNative", "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
{"unlinkToDeathNative", "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
{"addFrozenStateChangeCallbackNative",
- "(Landroid/os/IBinder$IFrozenStateChangeCallback;)V", (void*)android_os_BinderProxy_addFrozenStateChangeCallback},
+ "(Landroid/os/IBinder$FrozenStateChangeCallback;)V", (void*)android_os_BinderProxy_addFrozenStateChangeCallback},
{"removeFrozenStateChangeCallbackNative",
- "(Landroid/os/IBinder$IFrozenStateChangeCallback;)Z", (void*)android_os_BinderProxy_removeFrozenStateChangeCallback},
+ "(Landroid/os/IBinder$FrozenStateChangeCallback;)Z", (void*)android_os_BinderProxy_removeFrozenStateChangeCallback},
{"getNativeFinalizer", "()J", (void*)android_os_BinderProxy_getNativeFinalizer},
{"getExtension", "()Landroid/os/IBinder;", (void*)android_os_BinderProxy_getExtension},
};
@@ -1774,7 +1774,7 @@
"(Landroid/os/IBinder$DeathRecipient;Landroid/os/IBinder;)V");
gBinderProxyOffsets.mInvokeFrozenStateChangeCallback =
GetStaticMethodIDOrDie(env, clazz, "invokeFrozenStateChangeCallback",
- "(Landroid/os/IBinder$IFrozenStateChangeCallback;Landroid/os/"
+ "(Landroid/os/IBinder$FrozenStateChangeCallback;Landroid/os/"
"IBinder;I)V");
gBinderProxyOffsets.mNativeData = GetFieldIDOrDie(env, clazz, "mNativeData", "J");
diff --git a/core/jni/jni_wrappers.h b/core/jni/jni_wrappers.h
index 3b29e30..21b5b13 100644
--- a/core/jni/jni_wrappers.h
+++ b/core/jni/jni_wrappers.h
@@ -69,9 +69,47 @@
return static_cast<T>(res);
}
+// Inline variable that specifies the method binding format.
+// The expected format is 'XX${method}XX', where ${method} represents the original method name.
+// This variable is shared across all translation units. This is treated as a global variable as
+// per C++ 17.
+inline std::string jniMethodFormat;
+
+inline static void setJniMethodFormat(std::string value) {
+ jniMethodFormat = value;
+}
+
+// Potentially translates the given JNINativeMethods if setJniMethodFormat has been set.
+// Has no effect otherwise
+inline const JNINativeMethod* maybeRenameJniMethods(const JNINativeMethod* gMethods,
+ int numMethods) {
+ if (jniMethodFormat.empty()) {
+ return gMethods;
+ }
+ // Make a copy of gMethods with reformatted method names.
+ JNINativeMethod* modifiedMethods = new JNINativeMethod[numMethods];
+ LOG_ALWAYS_FATAL_IF(!modifiedMethods, "Failed to allocate a copy of the JNI methods");
+
+ size_t methodNamePos = jniMethodFormat.find("${method}");
+ LOG_ALWAYS_FATAL_IF(methodNamePos == std::string::npos,
+ "Invalid jniMethodFormat: could not find '${method}' in pattern");
+
+ for (int i = 0; i < numMethods; i++) {
+ modifiedMethods[i] = gMethods[i];
+ std::string modifiedName = jniMethodFormat;
+ modifiedName.replace(methodNamePos, 9, gMethods[i].name);
+ char* modifiedNameChars = new char[modifiedName.length() + 1];
+ LOG_ALWAYS_FATAL_IF(!modifiedNameChars, "Failed to allocate the new method name");
+ std::strcpy(modifiedNameChars, modifiedName.c_str());
+ modifiedMethods[i].name = modifiedNameChars;
+ }
+ return modifiedMethods;
+}
+
static inline int RegisterMethodsOrDie(JNIEnv* env, const char* className,
const JNINativeMethod* gMethods, int numMethods) {
- int res = jniRegisterNativeMethods(env, className, gMethods, numMethods);
+ const JNINativeMethod* modifiedMethods = maybeRenameJniMethods(gMethods, numMethods);
+ int res = jniRegisterNativeMethods(env, className, modifiedMethods, numMethods);
LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
return res;
}
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index cb7c226..606e829 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -401,6 +401,7 @@
optional SettingProto long_press_timeout = 35 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto key_press_timeout_ms = 96 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto key_press_delay_ms = 97 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto key_repeat_enabled = 102 [ (android.privacy).dest = DEST_AUTOMATIC ];
message ManagedProfile {
option (android.msg_privacy).dest = DEST_EXPLICIT;
@@ -735,5 +736,5 @@
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 102;
+ // Next tag = 103;
}
diff --git a/core/proto/android/service/graphicsstats.proto b/core/proto/android/service/graphicsstats.proto
index bb654f0..d836563 100644
--- a/core/proto/android/service/graphicsstats.proto
+++ b/core/proto/android/service/graphicsstats.proto
@@ -62,6 +62,9 @@
// HWUI renders pipeline type: GL or Vulkan
optional PipelineType pipeline = 8;
+
+ // The UID of the app
+ optional int32 uid = 9;
}
message GraphicsStatsJankSummaryProto {
diff --git a/core/proto/android/widget/remoteviews.proto b/core/proto/android/widget/remoteviews.proto
index 47c97b0..f477d32 100644
--- a/core/proto/android/widget/remoteviews.proto
+++ b/core/proto/android/widget/remoteviews.proto
@@ -299,6 +299,14 @@
NightModeReflectionAction night_mode_reflection_action = 5;
ReflectionAction reflection_action = 6;
RemoveFromParentAction remove_from_parent_action = 7;
+ ResourceReflectionAction resource_reflection_action = 8;
+ SetCompoundButtonCheckedAction set_compound_button_checked_action = 9;
+ SetDrawableTintAction set_drawable_tint_action = 10;
+ SetEmptyViewAction set_empty_view_action = 11;
+ SetIntTagAction set_int_tag_action = 12;
+ SetRadioGroupCheckedAction set_radio_group_checked_action = 13;
+ SetRemoteCollectionItemListAdapterAction set_remote_collection_item_list_adapter_action = 14;
+ SetRippleDrawableColorAction set_ripple_drawable_color_action = 15;
}
}
@@ -374,6 +382,52 @@
message RemoveFromParentAction {
optional string view_id = 1;
}
+
+ message ResourceReflectionAction {
+ optional string view_id = 1;
+ optional string method_name = 2;
+ optional int32 resource_type = 3;
+ optional string res_id = 4;
+ optional int32 parameter_type = 5;
+ }
+
+ message SetCompoundButtonCheckedAction {
+ optional string view_id = 1;
+ optional bool checked = 2;
+ }
+
+ message SetDrawableTintAction {
+ optional string view_id = 1;
+ optional bool target_background = 2;
+ optional int32 color_filter = 3;
+ optional int32 filter_mode = 4;
+ }
+
+ message SetEmptyViewAction {
+ optional string view_id = 1;
+ optional string empty_view_id = 2;
+ }
+
+ message SetIntTagAction {
+ optional string view_id = 1;
+ optional string key = 2;
+ optional int32 tag = 3;
+ }
+
+ message SetRadioGroupCheckedAction {
+ optional string view_id = 1;
+ optional string checked_id = 2;
+ }
+
+ message SetRemoteCollectionItemListAdapterAction {
+ optional string view_id = 1;
+ optional RemoteCollectionItems items = 2;
+ }
+
+ message SetRippleDrawableColorAction {
+ optional string view_id = 1;
+ optional android.content.res.ColorStateListProto color_state_list = 2;
+ }
}
diff --git a/core/res/res/layout/miniresolver.xml b/core/res/res/layout/miniresolver.xml
index e60e0b0..db1c779 100644
--- a/core/res/res/layout/miniresolver.xml
+++ b/core/res/res/layout/miniresolver.xml
@@ -122,7 +122,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
- android:maxLines="2"
+ android:layout_toStartOf="@id/button_open"
+ android:layout_marginEnd="8dp"
android:background="@drawable/resolver_outlined_button_bg"
style="?android:attr/borderlessButtonStyle"
android:paddingHorizontal="16dp"
@@ -136,7 +137,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
- android:maxLines="2"
android:paddingHorizontal="16dp"
android:background="@drawable/resolver_button_bg"
style="?android:attr/borderlessButtonStyle"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 9352413..1cd2150 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Stel ’n skermslot"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Stel skermslot"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Stel ’n skermslot op dié toestel om jou privaat ruimte te gebruik"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Stel ’n skermslot op dié toestel om privaat ruimte uit te vee"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Program is nie beskikbaar nie"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nie op die oomblik beskikbaar nie."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> is nie beskikbaar nie"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 10855c8..484afc3 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"ማያ ገጽ መቆለፊያን ያቀናብሩ"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ማያ ገጽ መቆለፊያውን ያቀናብሩ"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"የግል ቦታዎን ለመጠቀም፣ በዚህ መሣሪያ ላይ ማያ ገጽ መቆለፊያን ያቀናብሩ"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"የግል ቦታን ለመሰረዝ በዚህ መሣሪያ ላይ ማያ ገፅ መቆለፊያ ያቀናብሩ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"መተግበሪያ አይገኝም"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> አሁን አይገኝም።"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> አይገኝም"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 623ef23..75e93d1 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -2014,8 +2014,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"ضبط قفل شاشة"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ضبط قفل الشاشة"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"لاستخدام مساحتك الخاصة، يجب ضبط قفل شاشة على هذا الجهاز"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"لحذف المساحة الخاصة، يجب ضبط قفل شاشة على هذا الجهاز"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"التطبيق غير متاح"</string>
<string name="app_blocked_message" msgid="542972921087873023">"تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> غير متاح الآن."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"تطبيق <xliff:g id="ACTIVITY">%1$s</xliff:g> غير متاح"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index ba1095b..e64c85e 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"এটা স্ক্ৰীন লক ছেট কৰক"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"স্ক্ৰীন লক ছেট কৰা"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"আপোনাৰ প্ৰাইভেট স্পে\'চ ব্যৱহাৰ কৰিবলৈ এই ডিভাইচটোত স্ক্ৰীন লক ছেট কৰক"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"প্ৰাইভেট স্পে’চ মচিবলৈ, এই ডিভাইচটোত এটা স্ক্ৰীন লক ছেট কৰক"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"এপ্টো উপলব্ধ নহয়"</string>
<string name="app_blocked_message" msgid="542972921087873023">"এই মুহূৰ্তত <xliff:g id="APP_NAME">%1$s</xliff:g> উপলব্ধ নহয়।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> উপলব্ধ নহয়"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 1b574d1..25dc429 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ekran kilidi ayarlayın"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ekran kilidi ayarlayın"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Bu cihazda ekran kilidi ayarlamaqla şəxsi sahədən istifadə edin"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Bu cihazda ekran kilidi ayarlamaqla şəxsi sahəni silin"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Tətbiq əlçatan deyil"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> hazırda əlçatan deyil."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> əlçatan deyil"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 2116a6ef..7413703 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -2011,8 +2011,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Podesite otključavanje ekrana"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Podesi otključavanje ekrana"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Da biste koristili privatni prostor, podesite otključavanje ekrana na ovom uređaju"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Da biste izbrisali privatan prostor, podesite otključavanje ekrana na ovom uređaju"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – nije dostupno"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 0219b6c..a5af4b9 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -2012,8 +2012,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Наладзьце блакіроўку экрана"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Наладзіць блакіроўку экрана"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Каб выкарыстоўваць прыватную прастору, на прыладзе неабходна наладзіць блакіроўку экрана"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Каб выдаліць прыватную прастору, на прыладзе неабходна наладзіць блакіроўку экрана"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Праграма недаступная"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" цяпер недаступная."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недаступна: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 019068b..0871bfd 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -992,7 +992,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="8583732939138432793">"ভুল পিন কোড৷"</string>
<string name="keyguard_label_text" msgid="3841953694564168384">"আনলক করতে, মেনু টিপুন তারপর ০ টিপুন৷"</string>
<string name="emergency_call_dialog_number_for_display" msgid="2978165477085612673">"জরুরী নম্বর"</string>
- <string name="lockscreen_carrier_default" msgid="6192313772955399160">"কোনো পরিষেবা নেই"</string>
+ <string name="lockscreen_carrier_default" msgid="6192313772955399160">"কোনও পরিষেবা নেই"</string>
<string name="lockscreen_screen_locked" msgid="7364905540516041817">"স্ক্রীণ লক করা আছে৷"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"আনলক করতে বা জরুরি কল করতে মেনু টিপুন৷"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"আনলক করতে মেনু টিপুন৷"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index bdd9f15..50f2221 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -191,7 +191,7 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="4562226280528716090">"Pokušali ste izbrisati previše sadržaja iz kategorije <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="5557552311566179924">"Pohrana tableta je puna. Izbrišite fajlove kako biste oslobodili prostor."</string>
<string name="low_memory" product="watch" msgid="3479447988234030194">"Prostor za gledanje je pun. Izbrišite neke fajlove da oslobodite prostor."</string>
- <string name="low_memory" product="tv" msgid="6663680413790323318">"Pohrana Android TV uređaja je puna. Izbrišite neke fajlove da oslobodite prostor."</string>
+ <string name="low_memory" product="tv" msgid="6663680413790323318">"Pohrana na uređaju Android TV je puna. Izbrišite neke fajlove da oslobodite prostor."</string>
<string name="low_memory" product="default" msgid="2539532364144025569">"Pohrana telefona je puna. Izbrišite fajlove kako biste oslobodili prostor."</string>
<string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{CA certifikat je instaliran}one{CA certifikati su instalirani}few{CA certifikati su instalirani}other{CA certifikati su instalirani}}"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Od nepoznate treće strane"</string>
@@ -2011,8 +2011,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Postavite zaključavanje ekrana"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Postavite zaključavanje ekrana"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Za upotrebu privatnog prostora postavite zaključavanje ekrana na uređaju"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Da izbrišete privatni prostor, postavite zaključavanje ekrana na uređaju"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Nedostupno: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
@@ -2066,7 +2065,7 @@
<string name="app_category_maps" msgid="6395725487922533156">"Mape i navigacija"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktivnost"</string>
<string name="app_category_accessibility" msgid="6643521607848547683">"Pristupačnost"</string>
- <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Memorija uređaja"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Pohrana na uređaju"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Otklanjanje grešaka putem USB-a"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"sat"</string>
<string name="time_picker_minute_label" msgid="8307452311269824553">"minuta"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 8aa1224..2fea7fb 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -2012,8 +2012,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Nastavte si zámek obrazovky"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Nastavit zámek obrazovky"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Pokud chcete používat soukromý prostor, nastavte na tomto zařízení zámek obrazovky"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Pokud chcete vymazat soukromý prostor, nastavte na tomto zařízení zámek obrazovky"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikace není k dispozici"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> v tuto chvíli není k dispozici."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> není k dispozici"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 95e61b9..d0f1615 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Konfigurer en skærmlås"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Konfigurer skærmlås"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Konfigurer en skærmlås på enheden for at bruge dit private område"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Konfigurer en skærmlås på enheden for at slette det private område"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgængelig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgængelig lige nu."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> er ikke understøttet"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 41c1e4b..da0e9bd 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Displaysperre einrichten"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Displaysperre einrichten"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Richte zur Nutzung des vertraulichen Profils auf dem Gerät die Displaysperre ein"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Um das vertrauliche Profil zu löschen, richte auf dem Gerät eine Displaysperre ein"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App ist nicht verfügbar"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ist derzeit nicht verfügbar."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nicht verfügbar"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 12d2756..cbb30fd 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -2011,8 +2011,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Configurar bloqueo de pantalla"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Configurar bloqueo de pantalla"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para usar tu espacio privado, configura un bloqueo de pantalla"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Para borrar el espacio privado, configura un bloqueo de pantalla."</string>
<string name="app_blocked_title" msgid="7353262160455028160">"La app no está disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible en este momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no disponible"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index c6ee8ef..23024f0 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -2011,8 +2011,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Define un bloqueo de pantalla"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Establecer bloqueo de pantalla"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para usar el espacio privado, define un bloqueo de pantalla"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Para eliminar el espacio privado, define un método de desbloqueo de pantalla en este dispositivo"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"La aplicación no está disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"En estos momentos, <xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no disponible"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 4389b4b..326b3db 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Seadistage ekraanilukk"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Seadistage ekraanilukk"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Seadistage oma privaatse ruumi jaoks seadmele ekraanilukk"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Privaatse ruumi kustutamiseks määrake selles seadmes ekraanilukk"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Rakendus ei ole saadaval"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei ole praegu saadaval."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ei ole saadaval"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 56b10d1..d092f46 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ezarri pantailaren blokeoa"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ezarri pantailaren blokeoa"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Eremu pribatua erabiltzeko, ezarri pantailaren blokeoa gailuan"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Eremu pribatua ezabatzeko, ezarri pantaila blokeatzeko aukera bat gailuan"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikazioa ez dago erabilgarri"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ez dago erabilgarri une honetan."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ez dago erabilgarri"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 34edd03..e37106d 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"قفل صفحه تنظیم کنید"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"تنظیم قفل صفحه"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"برای استفاده از فضای خصوصی، قفل صفحه تنظیم کنید"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"برای حذف کردن فضای خصوصی، قفل صفحه در این دستگاه تنظیم کنید"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"برنامه در دسترس نیست"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> درحالحاضر در دسترس نیست."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> دردسترس نیست"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index ecc7a3f..672e508 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Näytön lukituksen asettaminen"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Aseta näytön lukitus"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Edellyttää näytön lukitusta"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Jos haluat poistaa yksityisen tilan, aseta laitteelle näytön lukitus"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Sovellus ei ole käytettävissä"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei ole nyt käytettävissä."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ei käytettävissä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 86b83a0..bc11e547 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -2011,8 +2011,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Config. Verrouillage d\'écran"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Config. Verrouillage d\'écran"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Configurez verrouillage de l\'écran pour utiliser Espace privé"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Réglez le verrouillage de l\'écran pour supprimer l\'espace privé"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"L\'appli n\'est pas accessible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas accessible pour le moment."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non accessible"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 5fa4a3b..03cf463 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -2011,8 +2011,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Activer verrouillage écran"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Activer verrouillage écran"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Pour utiliser votre espace privé, activez le verrouillage de l\'écran sur cet appareil"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Pour supprimer un espace privé, définissez un verrouillage de l\'écran sur cet appareil."</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Application non disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas disponible pour le moment."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponible"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 2f3cffa..430d649 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1937,7 +1937,7 @@
<string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"Noite da semana"</string>
<string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Fin de semana"</string>
<string name="zen_mode_default_events_name" msgid="2280682960128512257">"Evento"</string>
- <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Durmindo"</string>
+ <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Mentres durmo"</string>
<string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Xestionada por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Activada"</string>
<string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Desactivada"</string>
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Define un bloqueo de pantalla"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Define un bloqueo de pantalla"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para usar o espazo privado, define un bloqueo de pantalla"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Para eliminar o espazo privado, define un bloqueo de pantalla neste dispositivo"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"A aplicación non está dispoñible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"A aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> non está dispoñible neste momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non está dispoñible"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index aa190a5..14b512e 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"સ્ક્રીન લૉક સેટ કરો"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"સ્ક્રીન લૉક સેટ કરો"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"તમારી ખાનગી સ્પેસનો ઉપયોગ કરવા, આ ડિવાઇસ પર સ્ક્રીન લૉક સેટ કરો"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"ખાનગી સ્પેસનો ડિલીટ કરવા, આ ડિવાઇસ પર સ્ક્રીન લૉક સેટ કરો"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ઍપ ઉપલબ્ધ નથી"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> હાલમાં ઉપલબ્ધ નથી."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ઉપલબ્ધ નથી"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 4c76cff..0386387f 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"स्क्रीन लॉक सेट करें"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"स्क्रीन लॉक सेट करें"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"प्राइवेट स्पेस के लिए, इस डिवाइस पर स्क्रीन लॉक सेट करें"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"प्राइवेट स्पेस मिटाने के लिए, इस डिवाइस पर स्क्रीन लॉक सेट करें"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ऐप्लिकेशन उपलब्ध नहीं है"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> इस समय उपलब्ध नहीं है."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध नहीं है"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index bf972b8..54dc55d 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -2011,8 +2011,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Postavite zaključavanje zaslona"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Postavi zaključavanje zaslona"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Da biste upotrebljavali privatni prostor, postavite zaključavanje zaslona na ovom uređaju"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Za upotrebu privatnog prostora postavite zaključavanje zaslona."</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutačno nije dostupna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – nije dostupno"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 357328c..179de200 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Állítson be képernyőzárat"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Képernyőzár beállítása"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"A privát terület használatához állítson be képernyőzárat"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"A privát terület törléséhez állítson be képernyőzárat ezen az eszközön."</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Az alkalmazás nem hozzáférhető"</string>
<string name="app_blocked_message" msgid="542972921087873023">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> jelenleg nem hozzáférhető."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"A(z) <xliff:g id="ACTIVITY">%1$s</xliff:g> nem áll rendelkezése"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 5405bb2..312a105 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1937,7 +1937,7 @@
<string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"Աշխատանքային օր"</string>
<string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Շաբաթ-կիրակի"</string>
<string name="zen_mode_default_events_name" msgid="2280682960128512257">"Միջոցառում"</string>
- <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Քնի ժամանակ"</string>
+ <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Քնի ժամ"</string>
<string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Կառավարվում է <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի կողմից"</string>
<string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Միացված է"</string>
<string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Անջատված է"</string>
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Կարգավորեք էկրանի կողպումը"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Կարգավորել էկրանի կողպումը"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Մասնավոր տարածքն օգտագործելու համար այս սարքում կարգավորեք էկրանի կողպումը"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Մասնավոր տարածքը ջնջելու համար սահմանեք էկրանի կողպում այս սարքում"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Հավելվածը հասանելի չէ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածն այս պահին հասանելի չէ։"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>՝ անհասանելի է"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index f5a2a14..e830d6d 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Setel kunci layar"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Setel kunci layar"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Untuk menggunakan ruang privasi, setel kunci layar di perangkat ini"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Untuk menghapus ruang privasi, setel kunci layar di perangkat ini"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikasi tidak tersedia"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia saat ini."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> tidak tersedia"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index baeaa3f..307fb52 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Stilltu skjálás"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Stilla skjálás"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Stilltu skjálás í tækinu til að nota leynirými"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Stilltu skjálás í tækinu til að eyða leynirými"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Forrit er ekki tiltækt"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ekki tiltækt núna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ekki í boði"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 48766b8..08ea1f1 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -2011,8 +2011,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Imposta un blocco schermo"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Imposta il blocco schermo"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Per utilizzare il tuo spazio privato, imposta un blocco schermo sul dispositivo"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Per eliminare lo spazio privato, imposta un blocco schermo sul dispositivo"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"L\'app non è disponibile"</string>
<string name="app_blocked_message" msgid="542972921087873023">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> non è al momento disponibile."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non disponibile"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index d3f0d98..1c1918c 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1407,7 +1407,7 @@
<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">"ניפוי באגים ב-USB מחובר"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"לכיבוי של ניפוי הבאגים ב-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>
@@ -2011,8 +2011,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"הגדרת נעילת מסך"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"הגדרה של נעילת מסך"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"כדי להשתמש במרחב הפרטי יש להגדיר נעילת מסך במכשיר"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"כדי למחוק את המרחב הפרטי, צריך להגדיר נעילת מסך במכשיר הזה."</string>
<string name="app_blocked_title" msgid="7353262160455028160">"האפליקציה לא זמינה"</string>
<string name="app_blocked_message" msgid="542972921087873023">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא זמינה בשלב זה."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> לא זמינה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index bcea959..36d956c 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1936,8 +1936,8 @@
<string name="zen_mode_downtime_feature_name" msgid="5886005761431427128">"ダウンタイム"</string>
<string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"平日の夜"</string>
<string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"週末"</string>
- <string name="zen_mode_default_events_name" msgid="2280682960128512257">"予定"</string>
- <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"睡眠中"</string>
+ <string name="zen_mode_default_events_name" msgid="2280682960128512257">"予定モード"</string>
+ <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"おやすみモード"</string>
<string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> によって管理されています"</string>
<string name="zen_mode_implicit_activated" msgid="2634285680776672994">"ON"</string>
<string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"OFF"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 29dfbba..0997b4b 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Экран құлпын орнатыңыз"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Экран құлпын орнату"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Құпия кеңістігіңізді қолдану үшін осы құрылғыда экран құлпын орнатыңыз."</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Құпия кеңістікті жою үшін құрылғыға экран құлпын орнатыңыз."</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Қолданба қолжетімді емес"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> қазір қолжетімді емес."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> қолжетімсіз"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index aeea5dc..696bd79 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"កំណត់ការចាក់សោអេក្រង់"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"កំណត់ការចាក់សោអេក្រង់"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ដើម្បីប្រើលំហឯកជនរបស់អ្នក សូមកំណត់ការចាក់សោអេក្រង់នៅលើឧបករណ៍នេះ"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"ដើម្បីលុបលំហឯកជនរបស់អ្នក សូមកំណត់ការចាក់សោអេក្រង់នៅលើឧបករណ៍នេះ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"មិនអាចប្រើកម្មវិធីនេះបានទេ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"មិនអាចប្រើ <xliff:g id="APP_NAME">%1$s</xliff:g> នៅពេលនេះបានទេ។"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"មិនអាចប្រើ <xliff:g id="ACTIVITY">%1$s</xliff:g> បានទេ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5ed6959..5f0e1f9 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"화면 잠금 설정"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"화면 잠금 설정"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"비공개 스페이스를 사용하려면 이 기기에 화면 잠금을 설정하세요"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"비공개 스페이스를 삭제하려면 이 기기에 화면 잠금을 설정하세요"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"앱을 사용할 수 없습니다"</string>
<string name="app_blocked_message" msgid="542972921087873023">"현재 <xliff:g id="APP_NAME">%1$s</xliff:g> 앱을 사용할 수 없습니다."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 사용할 수 없음"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 0c3a5e1..514b9cf 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Экран кулпусун коюп алыңыз"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Экран кулпусун коюу"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Жеке мейкиндикти колдонуу үчүн бул түзмөктүн экранын кулпулаңыз"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Жеке мейкиндикти өчүрүү үчүн бул түзмөктө экран кулпусун коюңуз"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Колдонмо учурда жеткиликсиз"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> учурда жеткиликсиз"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> жеткиликсиз"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 56945c2..e617a4c 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -2012,8 +2012,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ekrano užrako nustatymas"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Nustatykite ekrano užraktą"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Jei norite naudoti privačią erdvę, nustatykite ekrano užraktą šiame įrenginyje"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Jei norite ištrinti privačią erdvę, nustatykite ekrano užraktą šiame įrenginyje"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Programa nepasiekiama."</string>
<string name="app_blocked_message" msgid="542972921087873023">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ šiuo metu nepasiekiama."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"„<xliff:g id="ACTIVITY">%1$s</xliff:g>“ nepasiekiama"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 8b271d9..b04dd45 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -2011,8 +2011,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Iestatiet ekrāna bloķēšanu"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Iestatīt ekrāna bloķēšanu"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Lai izmantotu privāto telpu, iestatiet ekrāna bloķēšanu."</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Lai dzēstu privāto telpu, iestatiet ekrāna bloķēšanu šajā ierīcē."</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Lietotne nav pieejama"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> pašlaik nav pieejama."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nav pieejams"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index a5ce587..b0d6351 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Поставете заклучување екран"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Поставете заклучување екран"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"За да користите „Приватен простор“, поставете заклучување екран на уредов"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"За да го избришете „Приватниот простор“, поставете заклучување екран на уредов"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Апликацијата не е достапна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> не е достапна во моментов."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> е недостапна"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index ef9d6c8..cc545e2 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"സ്ക്രീൻ ലോക്ക് സജ്ജീകരിക്കൂ"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"സ്ക്രീൻ ലോക്ക് സജ്ജീകരിക്കൂ"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"സ്വകാര്യ സ്പേസിന്, ഇതിൽ സ്ക്രീൻ ലോക്ക് സജ്ജീകരിക്കൂ"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"സ്വകാര്യ സ്പേസ് ഇല്ലാതാക്കാൻ, ഈ ഉപകരണത്തിൽ സ്ക്രീൻ ലോക്ക് സജ്ജീകരിക്കൂ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ആപ്പ് ലഭ്യമല്ല"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ഇപ്പോൾ ലഭ്യമല്ല."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ലഭ്യമല്ല"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 01a175a..87ce94b 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Дэлгэцийн түгжээ тохируулах"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Дэлгэцийн түгжээ тохируулах"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Хаалттай орон зайгаа ашиглах бол уг төхөөрөмжид дэлгэцийн түгжээ тохируулна уу"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Хаалттай орон зайг устгахын тулд энэ төхөөрөмж дээр дэлгэцийн түгжээ тохируулна уу"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Апп боломжгүй байна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> яг одоо боломжгүй байна."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> боломжгүй байна"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index f9b70ff..03cabc3 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"स्क्रीन लॉक सेट करा"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"स्क्रीन लॉक सेट करा"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"तुमची खाजगी स्पेस वापरण्यास, या डिव्हाइसवर स्क्रीन लॉक सेट करा"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"खाजगी स्पेस हटवण्यासाठी, या डिव्हाइसवर स्क्रीन लॉक सेट करा"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ॲप उपलब्ध नाही"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> आता उपलब्ध नाही."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध नाही"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index b30d48d..83a1d56 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Tetapkan kunci skrin"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Tetapkan kunci skrin"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Tetapkan kunci skrin pada peranti untuk menggunakan ruang privasi"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Untuk memadamkan ruang peribadi, tetapkan kunci skrin pada peranti ini"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Apl tidak tersedia"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia sekarang."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> tidak tersedia"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index b78e2cb..e4e75c1 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"ဖန်သားပြင်လော့ခ် သတ်မှတ်ပါ"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ဖန်သားပြင်လော့ခ် သတ်မှတ်ရန်"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"သင့်သီးသန့်နေရာသုံးရန် ဤစက်၌ ဖန်သားပြင်လော့ခ် သတ်မှတ်ပါ"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"သီးသန့်နေရာကို ဖျက်ရန်အတွက် ဤစက်တွင် ဖန်သားပြင်လော့ခ် သတ်မှတ်ပါ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"အက်ပ်ကို မရနိုင်ပါ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကို ယခု မရနိုင်ပါ။"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> မရနိုင်ပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 8002e90..6d24bdf 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Angi en skjermlås"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Angi skjermlås"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"For å bruke det private området, angi en skjermlås på enheten"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Før du kan slette det private området, må du angi en skjermlås på denne enheten"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgjengelig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgjengelig for øyeblikket."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> er utilgjengelig"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 784cce4..133429b 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1937,7 +1937,7 @@
<string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"हरेक हप्तादिनको राति"</string>
<string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"शनिवार"</string>
<string name="zen_mode_default_events_name" msgid="2280682960128512257">"कार्यक्रम"</string>
- <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"निदाएका बेला"</string>
+ <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"शयन"</string>
<string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले व्यवस्थापन गरेको"</string>
<string name="zen_mode_implicit_activated" msgid="2634285680776672994">"अन छ"</string>
<string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"अफ छ"</string>
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"स्क्रिन लक सेटअप गर्नुहोस्"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"स्क्रिन लक सेटअप गर्नुहोस्"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"निजी स्पेस प्रयोग गर्न यो डिभाइसमा स्क्रिन लक सेटअप गर्नुहोस्"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"निजी स्पेस मेटाउन यो डिभाइसमा स्क्रिन लक सेटअप गर्नुहोस्"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"एप उपलब्ध छैन"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> अहिले उपलब्ध छैन।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध छैन"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 6180b1b..d2ec4ba 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Schermvergrendeling instellen"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Schermvergrendeling instellen"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Als je je privégedeelte wilt gebruiken, stel je een schermvergrendeling op dit apparaat in"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Als je het privégedeelte wilt verwijderen, stel je een schermvergrendeling op dit apparaat in"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App is niet beschikbaar"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is momenteel niet beschikbaar."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> niet beschikbaar"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index e6e20fa..85a6aec 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"ଏକ ସ୍କ୍ରିନ ଲକ ସେଟ କରନ୍ତୁ"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ସ୍କ୍ରିନ ଲକ ସେଟ କରନ୍ତୁ"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ଆପଣଙ୍କ ପ୍ରାଇଭେଟ ସ୍ପେସ ବ୍ୟବହାର କରିବାକୁ ଏହି ଡିଭାଇସରେ ଏକ ସ୍କ୍ରିନ ଲକ ସେଟ କରନ୍ତୁ"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"ପ୍ରାଇଭେଟ ସ୍ପେସକୁ ଡିଲିଟ କରିବା ପାଇଁ ଏହି ଡିଭାଇସରେ ଏକ ସ୍କ୍ରିନ ଲକ ସେଟ କରନ୍ତୁ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ଆପ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବର୍ତ୍ତମାନ ଉପଲବ୍ଧ ନାହିଁ।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ଉପଲବ୍ଧ ନାହିଁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 8afb731..51d71ff 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"ਸਕ੍ਰੀਨ ਲਾਕ ਸੈੱਟ ਕਰੋ"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ਸਕ੍ਰੀਨ ਲਾਕ ਸੈੱਟ ਕਰੋ"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ਆਪਣੀ ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ ਵਰਤਣ ਲਈ, ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਕ੍ਰੀਨ ਲਾਕ ਸੈੱਟ ਕਰੋ"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ ਨੂੰ ਮਿਟਾਉਣ ਲਈ, ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਕ੍ਰੀਨ ਲਾਕ ਸੈੱਟ ਕਰੋ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ਐਪ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਇਸ ਵੇਲੇ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 14320ffe..49c30c7 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -2012,8 +2012,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ustaw blokadę ekranu"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ustaw blokadę ekranu"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Aby korzystać z przestrzeni prywatnej, ustaw na tym urządzeniu blokadę ekranu"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Aby usunąć przestrzeń prywatną, ustaw na tym urządzeniu blokadę ekranu"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacja jest niedostępna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest obecnie niedostępna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – brak dostępu"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index e8e125c..ff07066 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -2011,8 +2011,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Defina um bloqueio de tela"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Definir bloqueio de tela"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para usar o espaço privado, defina um bloqueio de tela neste dispositivo"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Para excluir o espaço privado, defina um bloqueio de tela neste dispositivo"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string>
<string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 910c5cf..12245b9 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1938,7 +1938,7 @@
<string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"Dias da semana à noite"</string>
<string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Fim de semana"</string>
<string name="zen_mode_default_events_name" msgid="2280682960128512257">"Evento"</string>
- <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"A dormir"</string>
+ <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Dormir"</string>
<string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Gerido por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Ativada"</string>
<string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Desativada"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index e8e125c..ff07066 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -2011,8 +2011,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Defina um bloqueio de tela"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Definir bloqueio de tela"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para usar o espaço privado, defina um bloqueio de tela neste dispositivo"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Para excluir o espaço privado, defina um bloqueio de tela neste dispositivo"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string>
<string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 29b9d17..6559764 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -2012,8 +2012,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Настройте блокировку экрана"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Настроить блокировку экрана"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Чтобы использовать частное пространство, настройте блокировку экрана на этом устройстве."</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Чтобы удалить частное пространство, настройте блокировку экрана на этом устройстве."</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Приложение недоступно"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" сейчас недоступно."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недоступно: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index acd6d43..be41512 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"තිර අගුලක් සකසන්න"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"තිර අගුල සකසන්න"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ඔබේ රහසිගත අවකාශය භාවිතා කිරීමට, මෙම උපාංගයේ තිර අගුලක් සකසන්න"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"පෞද්ගලික අවකාශය මැකීමට, මෙම උපාංගයෙහි තිර අගුලක් සකසන්න"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"යෙදුම ලබා ගත නොහැකිය"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> මේ දැන් ලබා ගත නොහැකිය."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> නොතිබේ"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 07b44f9..c671f46 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -2012,8 +2012,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Nastavte zámku obrazovky"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Nastaviť zámku obrazovky"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ak chcete používať súkromný priestor, nastavte v tomto zariadení zámku obrazovky"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Ak chcete odstrániť súkromný priestor, nastavte v tomto zariadení zámku obrazovky"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikácia nie je dostupná"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> nie je teraz dostupná."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nie je k dispozícii"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index f3b0da4..ed8cf50 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -2012,8 +2012,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Nastavitev zaklepanja zaslona"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Nastavite zaklepanje zaslona"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Če želite uporabljati zasebni prostor, v tej napravi nastavite zaklepanje zaslona"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Če želite izbrisati zasebni prostor, v tej napravi nastavite zaklepanje zaslona"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija ni na voljo"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno ni na voljo."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"»<xliff:g id="ACTIVITY">%1$s</xliff:g>« ni na voljo"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index badb90d..e24e310 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Cakto një kyçje ekrani"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Cakto kyçjen e ekranit"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Për të përdorur hapësirën private, cakto një kyçje ekrani në këtë pajisje"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Për të përdorur hapësirën private, cakto një kyçje ekrani në këtë pajisje"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacioni nuk ofrohet"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk ofrohet për momentin."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nuk ofrohet"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index d38dd12..915486e 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -2011,8 +2011,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Подесите откључавање екрана"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Подеси откључавање екрана"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Да бисте користили приватни простор, подесите откључавање екрана на овом уређају"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Да бисте избрисали приватан простор, подесите откључавање екрана на овом уређају"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Апликација није доступна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> тренутно није доступна."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – није доступно"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 9b7f3a1..0c5b6ac 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1937,7 +1937,7 @@
<string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"Vardagskväll"</string>
<string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"I helgen"</string>
<string name="zen_mode_default_events_name" msgid="2280682960128512257">"Händelse"</string>
- <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"När jag sover"</string>
+ <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Sover"</string>
<string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Hanteras av <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="zen_mode_implicit_activated" msgid="2634285680776672994">"På"</string>
<string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Av"</string>
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ställ in ett skärmlås"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ställ in skärmlås"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ställ in ett skärmlås för enheten om du vill använda ditt privata område."</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Ange ett skärmlås för enheten om du vill radera privat område"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Appen är inte tillgänglig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> är inte tillgängligt just nu."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> är inte tillgänglig"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index e1123af..8d69834ea 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Weka mbinu ya kufunga skrini"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Weka mbinu ya kufunga skrini"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ili utumie sehemu ya faragha, weka mbinu ya kufunga skrini kwenye kifaa hiki"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Ili ufute sehemu ya faragha, weka mbinu ya kufunga skrini kwenye kifaa hiki"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Programu haipatikani"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> haipatikani hivi sasa."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> haipatikani"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index f167eb7..dfc6a79 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"திரைப் பூட்டை அமையுங்கள்"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"திரைப் பூட்டை அமை"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ரகசிய இடத்தைப் பயன்படுத்த, சாதனத்தில் திரைப் பூட்டை அமையுங்கள்"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"ரகசிய இடத்தை நீக்க, இந்தச் சாதனத்தில் திரைப் பூட்டை அமையுங்கள்"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"இந்த ஆப்ஸ் இப்போது கிடைப்பதில்லை"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் இப்போது கிடைப்பதில்லை."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> இல்லை"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index cc716ea..51bb90f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"ตั้งล็อกหน้าจอ"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ตั้งล็อกหน้าจอ"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"หากต้องการใช้พื้นที่ส่วนตัว ให้ตั้งการล็อกหน้าจอในอุปกรณ์นี้"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"หากต้องการลบพื้นที่ส่วนตัว ให้ตั้งการล็อกหน้าจอในอุปกรณ์นี้"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"แอปไม่พร้อมใช้งาน"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่พร้อมใช้งานในขณะนี้"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ไม่พร้อมใช้งาน"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 8939120..a4d2752 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Magtakda ng lock ng screen"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Itakda ang lock ng screen"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para gamitin ang iyong pribadong space, magtakda ng lock ng screen sa device na ito."</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Para mag-delete ng pribadong space, magtakda ng lock ng screen sa device na ito"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Hindi available ang app"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Hindi available sa ngayon ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Hindi available ang <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 85fea5c..f467f92 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ekran kilidi ayarlayın"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ekran kilidi ayarla"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Özel alanı kullanmak için cihazda ekran kilidi ayarlayın"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Gizli alanı silmek için bu cihazda ekran kilidi ayarlayın."</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Uygulama kullanılamıyor"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması şu anda kullanılamıyor."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> kullanılamıyor"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 614925f..a63f3fb 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -2012,8 +2012,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Налаштуйте блокування екрана"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Налаштувати блокування екрана"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Для доступу до приватного простору налаштуйте блокування екрана"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Щоб видалити приватний простір, налаштуйте блокування екрана на цьому пристрої"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Додаток недоступний"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зараз недоступний."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недоступно: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 7bd6175..f62074e 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ekran qulfini sozlash"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ekran qulfini sozlash"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Maxfiy makon ishlatish uchun bu qurilma ekran qulfini sozlang"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Maxfiy makon ishlatish uchun bu qurilma ekran qulfini sozlang"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Ilova ishlamayapti"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Ayni vaqtda <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi ishlamayapti."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> kanali ish faoliyatida emas"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index f084c37c..3b08a22 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Đặt phương thức khoá màn hình"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Đặt phương thức khoá màn hình"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Để dùng không gian riêng tư, hãy thiết lập một phương thức khoá màn hình trên thiết bị này"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Để xoá không gian riêng tư, hãy đặt một phương thức khoá màn hình trên thiết bị này"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Ứng dụng này không dùng được"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> hiện không dùng được."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Không hỗ trợ <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index a1c36ab..95753eb 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"设置一种屏锁方式"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"设置屏锁方式"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"若要使用私密空间,请在此设备上设置屏锁方式"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"若要删除私密空间,请在此设备上设置屏幕锁定"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"应用无法使用"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g>目前无法使用。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>不可用"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 6a5fea7..df04ec8 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"設定螢幕鎖定"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"設定螢幕鎖定"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"如要使用私人空間,請在此裝置上設定螢幕鎖定功能"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"如要刪除私人空間,請在此裝置上設定螢幕鎖定功能"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"無法使用應用程式"</string>
<string name="app_blocked_message" msgid="542972921087873023">"目前無法使用「<xliff:g id="APP_NAME">%1$s</xliff:g>」。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"無法使用「<xliff:g id="ACTIVITY">%1$s</xliff:g>」"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index bb64ab5..f0351ce 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"設定螢幕鎖定功能"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"設定螢幕鎖定功能"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"如要使用私人空間,請在這部裝置設定螢幕鎖定功能"</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"如要刪除私人空間,請在這部裝置上設定螢幕鎖定功能"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"應用程式無法使用"</string>
<string name="app_blocked_message" msgid="542972921087873023">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」目前無法使用。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"無法存取「<xliff:g id="ACTIVITY">%1$s</xliff:g>」"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 0524c09..f051a45 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -2010,8 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Setha ukukhiya isikrini"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Setha ukukhiya isikrini"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ukuze usebenzise isikhala esigodliwe, setha ukukhiya kwesikrini kule divayisi."</string>
- <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
- <skip />
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Ukuze usule Indawo Engasese, setha ukukhiya kwesikrini kule divayisi."</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Uhlelo lokusebenza alutholakali"</string>
<string name="app_blocked_message" msgid="542972921087873023">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayitholakali khona manje."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"okungatholakali <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 421b7d2..fe3d4f6 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -7136,4 +7136,8 @@
<!-- Whether to enable scaling and fading animation to scrollviews while scrolling.
P.S this is a change only intended for wear devices. -->
<bool name="config_enableViewGroupScalingFading">false</bool>
+ <!-- Action for opening identity check settings page [CHAR LIMIT=NONE] [DO NOT TRANSLATE] -->
+ <string name="identity_check_settings_action"></string>
+ <!-- Package for opening identity check settings page [CHAR LIMIT=NONE] [DO NOT TRANSLATE] -->
+ <string name="identity_check_settings_package_name">com\u002eandroid\u002esettings</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0396659..06b36b8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -5611,4 +5611,8 @@
<java-symbol type="string" name="fingerprint_loe_notification_msg" />
<java-symbol type="bool" name="config_enableViewGroupScalingFading"/>
+
+ <!-- Identity check strings -->
+ <java-symbol type="string" name="identity_check_settings_action" />
+ <java-symbol type="string" name="identity_check_settings_package_name" />
</resources>
diff --git a/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java b/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java
index 77e8a40..fe54aa8 100644
--- a/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java
+++ b/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java
@@ -30,31 +30,30 @@
public class BfsccTestAppCmdService extends Service {
private IBfsccTestAppCmdService.Stub mBinder = new IBfsccTestAppCmdService.Stub() {
- private final LinkedBlockingQueue<IBinder.IFrozenStateChangeCallback.State> mNotifications =
+ private final LinkedBlockingQueue<Integer> mNotifications =
new LinkedBlockingQueue<>();
@Override
public void listenTo(IBinder binder) throws RemoteException {
binder.addFrozenStateChangeCallback(
- (IBinder who, IBinder.IFrozenStateChangeCallback.State state)
- -> mNotifications.offer(state));
+ (IBinder who, int state) -> mNotifications.offer(state));
}
@Override
public boolean[] waitAndConsumeNotifications() {
List<Boolean> results = new ArrayList<>();
try {
- IBinder.IFrozenStateChangeCallback.State state =
- mNotifications.poll(5, TimeUnit.SECONDS);
+ Integer state = mNotifications.poll(5, TimeUnit.SECONDS);
if (state != null) {
- results.add(state == IBinder.IFrozenStateChangeCallback.State.FROZEN);
+ results.add(
+ state.intValue() == IBinder.FrozenStateChangeCallback.STATE_FROZEN);
}
} catch (InterruptedException e) {
return null;
}
while (mNotifications.size() > 0) {
- results.add(mNotifications.poll()
- == IBinder.IFrozenStateChangeCallback.State.FROZEN);
+ results.add(mNotifications.poll().intValue()
+ == IBinder.FrozenStateChangeCallback.STATE_FROZEN);
}
boolean[] convertedResults = new boolean[results.size()];
for (int i = 0; i < results.size(); i++) {
diff --git a/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java b/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java
index ee2e7e0..195a18a 100644
--- a/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java
+++ b/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java
@@ -52,7 +52,7 @@
import java.util.concurrent.atomic.AtomicReference;
/**
- * Tests functionality of {@link android.os.IBinder.IFrozenStateChangeCallback}.
+ * Tests functionality of {@link android.os.IBinder.FrozenStateChangeCallback}.
*/
@RunWith(AndroidJUnit4.class)
@IgnoreUnderRavenwood(blockedBy = ActivityManager.class)
@@ -157,7 +157,7 @@
@Test
public void onStateChangeNotCalledAfterCallbackRemoved() throws Exception {
final LinkedBlockingQueue<Boolean> results = new LinkedBlockingQueue<>();
- IBinder.IFrozenStateChangeCallback callback;
+ IBinder.FrozenStateChangeCallback callback;
if ((callback = createCallback(mBfsccTestAppCmdService.asBinder(), results)) == null) {
return;
}
@@ -171,7 +171,7 @@
public void multipleCallbacks() throws Exception {
final LinkedBlockingQueue<Boolean> results1 = new LinkedBlockingQueue<>();
final LinkedBlockingQueue<Boolean> results2 = new LinkedBlockingQueue<>();
- IBinder.IFrozenStateChangeCallback callback1;
+ IBinder.FrozenStateChangeCallback callback1;
if ((callback1 = createCallback(mBfsccTestAppCmdService.asBinder(), results1)) == null) {
return;
}
@@ -197,8 +197,8 @@
public void onStateChangeCalledWithTheRightBinder() throws Exception {
final IBinder binder = mBfsccTestAppCmdService.asBinder();
final LinkedBlockingQueue<IBinder> results = new LinkedBlockingQueue<>();
- IBinder.IFrozenStateChangeCallback callback =
- (IBinder who, IBinder.IFrozenStateChangeCallback.State state) -> results.offer(who);
+ IBinder.FrozenStateChangeCallback callback =
+ (IBinder who, int state) -> results.offer(who);
try {
binder.addFrozenStateChangeCallback(callback);
} catch (UnsupportedOperationException e) {
@@ -221,12 +221,12 @@
}
}
- private IBinder.IFrozenStateChangeCallback createCallback(IBinder binder, Queue<Boolean> queue)
+ private IBinder.FrozenStateChangeCallback createCallback(IBinder binder, Queue<Boolean> queue)
throws RemoteException {
try {
- final IBinder.IFrozenStateChangeCallback callback =
- (IBinder who, IBinder.IFrozenStateChangeCallback.State state) ->
- queue.offer(state == IBinder.IFrozenStateChangeCallback.State.FROZEN);
+ final IBinder.FrozenStateChangeCallback callback =
+ (IBinder who, int state) ->
+ queue.offer(state == IBinder.FrozenStateChangeCallback.STATE_FROZEN);
binder.addFrozenStateChangeCallback(callback);
return callback;
} catch (UnsupportedOperationException e) {
diff --git a/core/tests/coretests/src/android/tracing/OWNERS b/core/tests/coretests/src/android/tracing/OWNERS
deleted file mode 100644
index 86a7e88..0000000
--- a/core/tests/coretests/src/android/tracing/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include platform/development:/tools/winscope/OWNERS
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/tracing/TEST_MAPPING b/core/tests/coretests/src/android/tracing/TEST_MAPPING
deleted file mode 100644
index 4b7adf9..0000000
--- a/core/tests/coretests/src/android/tracing/TEST_MAPPING
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "postsubmit": [
- {
- "name": "FrameworksCoreTests_android_tracing",
- "file_patterns": [".*\\.java"]
- }
- ]
-}
diff --git a/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java b/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java
index 32345e6..a311d0d 100644
--- a/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java
+++ b/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java
@@ -16,10 +16,14 @@
package android.window.flags;
-import static android.window.flags.DesktopModeFlags.DESKTOP_WINDOWING_MODE;
+import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE;
+import static android.window.flags.DesktopModeFlags.ToggleOverride.OVERRIDE_OFF;
+import static android.window.flags.DesktopModeFlags.ToggleOverride.OVERRIDE_ON;
+import static android.window.flags.DesktopModeFlags.ToggleOverride.OVERRIDE_UNSET;
+import static android.window.flags.DesktopModeFlags.ToggleOverride.fromSetting;
import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE;
-import static com.android.window.flags.Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS;
+import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS;
import static com.android.window.flags.Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION;
import static com.google.common.truth.Truth.assertThat;
@@ -72,267 +76,287 @@
@Test
@DisableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- public void isEnabled_devOptionFlagDisabled_overrideOff_featureFlagOn_returnsTrue() {
+ public void isTrue_devOptionFlagDisabled_overrideOff_featureFlagOn_returnsTrue() {
setOverride(OVERRIDE_OFF_SETTING);
// In absence of dev options, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isTrue();
}
@Test
@DisableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
- public void isEnabled_devOptionFlagDisabled_overrideOn_featureFlagOff_returnsFalse() {
+ public void isTrue_devOptionFlagDisabled_overrideOn_featureFlagOff_returnsFalse() {
setOverride(OVERRIDE_ON_SETTING);
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isFalse();
}
@Test
@EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
- public void isEnabled_overrideUnset_featureFlagOn_returnsTrue() {
+ public void isTrue_overrideUnset_featureFlagOn_returnsTrue() {
setOverride(OVERRIDE_UNSET_SETTING);
// For overridableFlag, for unset overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isTrue();
}
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- public void isEnabled_overrideUnset_featureFlagOff_returnsFalse() {
+ public void isTrue_overrideUnset_featureFlagOff_returnsFalse() {
setOverride(OVERRIDE_UNSET_SETTING);
// For overridableFlag, for unset overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isFalse();
}
@Test
@EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
- public void isEnabled_noOverride_featureFlagOn_returnsTrue() {
+ public void isTrue_noOverride_featureFlagOn_returnsTrue() {
setOverride(null);
// For overridableFlag, in absence of overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isTrue();
}
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- public void isEnabled_noOverride_featureFlagOff_returnsFalse() {
+ public void isTrue_noOverride_featureFlagOff_returnsFalse() {
setOverride(null);
// For overridableFlag, in absence of overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isFalse();
}
@Test
@EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
- public void isEnabled_unrecognizableOverride_featureFlagOn_returnsTrue() {
+ public void isTrue_unrecognizableOverride_featureFlagOn_returnsTrue() {
setOverride(-2);
// For overridableFlag, for unrecognized overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isTrue();
}
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- public void isEnabled_unrecognizableOverride_featureFlagOff_returnsFalse() {
+ public void isTrue_unrecognizableOverride_featureFlagOff_returnsFalse() {
setOverride(-2);
// For overridableFlag, for unrecognizable overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isFalse();
}
@Test
@EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
- public void isEnabled_overrideOff_featureFlagOn_returnsFalse() {
+ public void isTrue_overrideOff_featureFlagOn_returnsFalse() {
setOverride(OVERRIDE_OFF_SETTING);
// For overridableFlag, follow override if they exist
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isFalse();
}
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- public void isEnabled_overrideOn_featureFlagOff_returnsTrue() {
+ public void isTrue_overrideOn_featureFlagOff_returnsTrue() {
setOverride(OVERRIDE_ON_SETTING);
// For overridableFlag, follow override if they exist
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isTrue();
}
@Test
@EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
- public void isEnabled_overrideOffThenOn_featureFlagOn_returnsFalseAndFalse() {
+ public void isTrue_overrideOffThenOn_featureFlagOn_returnsFalseAndFalse() {
setOverride(OVERRIDE_OFF_SETTING);
// For overridableFlag, follow override if they exist
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isFalse();
setOverride(OVERRIDE_ON_SETTING);
// Keep overrides constant through the process
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isFalse();
}
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- public void isEnabled_overrideOnThenOff_featureFlagOff_returnsTrueAndTrue() {
+ public void isTrue_overrideOnThenOff_featureFlagOff_returnsTrueAndTrue() {
setOverride(OVERRIDE_ON_SETTING);
// For overridableFlag, follow override if they exist
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isTrue();
setOverride(OVERRIDE_OFF_SETTING);
// Keep overrides constant through the process
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isTrue();
}
@Test
@EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
- FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS})
- public void isEnabled_dwFlagOn_overrideUnset_featureFlagOn_returnsTrue() {
+ FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS})
+ public void isTrue_dwFlagOn_overrideUnset_featureFlagOn_returnsTrue() {
setOverride(OVERRIDE_UNSET_SETTING);
// For unset overrides, follow flag
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
}
@Test
@EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
- @DisableFlags(FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
- public void isEnabled_dwFlagOn_overrideUnset_featureFlagOff_returnsFalse() {
+ @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS)
+ public void isTrue_dwFlagOn_overrideUnset_featureFlagOff_returnsFalse() {
setOverride(OVERRIDE_UNSET_SETTING);
// For unset overrides, follow flag
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
}
@Test
@EnableFlags({
FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION,
FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
- FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
+ FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS
})
- public void isEnabled_dwFlagOn_overrideOn_featureFlagOn_returnsTrue() {
+ public void isTrue_dwFlagOn_overrideOn_featureFlagOn_returnsTrue() {
setOverride(OVERRIDE_ON_SETTING);
// When toggle override matches its default state (dw flag), don't override flags
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
}
@Test
@EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
- @DisableFlags(FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
- public void isEnabled_dwFlagOn_overrideOn_featureFlagOff_returnsFalse() {
+ @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS)
+ public void isTrue_dwFlagOn_overrideOn_featureFlagOff_returnsFalse() {
setOverride(OVERRIDE_ON_SETTING);
// When toggle override matches its default state (dw flag), don't override flags
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
}
@Test
@EnableFlags({
FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION,
FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
- FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
+ FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS
})
- public void isEnabled_dwFlagOn_overrideOff_featureFlagOn_returnsTrue() {
+ public void isTrue_dwFlagOn_overrideOff_featureFlagOn_returnsTrue() {
setOverride(OVERRIDE_OFF_SETTING);
// Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
}
@Test
@EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
- @DisableFlags(FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
- public void isEnabled_dwFlagOn_overrideOff_featureFlagOff_returnsFalse() {
+ @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS)
+ public void isTrue_dwFlagOn_overrideOff_featureFlagOff_returnsFalse() {
setOverride(OVERRIDE_OFF_SETTING);
// Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
}
@Test
@EnableFlags({
FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION,
- FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
+ FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS
})
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- public void isEnabled_dwFlagOff_overrideUnset_featureFlagOn_returnsTrue() {
+ public void isTrue_dwFlagOff_overrideUnset_featureFlagOn_returnsTrue() {
setOverride(OVERRIDE_UNSET_SETTING);
// For unset overrides, follow flag
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
}
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags({
FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
- FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
+ FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS
})
- public void isEnabled_dwFlagOff_overrideUnset_featureFlagOff_returnsFalse() {
+ public void isTrue_dwFlagOff_overrideUnset_featureFlagOff_returnsFalse() {
setOverride(OVERRIDE_UNSET_SETTING);
// For unset overrides, follow flag
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
}
@Test
@EnableFlags({
FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION,
- FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
+ FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS
})
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- public void isEnabled_dwFlagOff_overrideOn_featureFlagOn_returnsTrue() {
+ public void isTrue_dwFlagOff_overrideOn_featureFlagOn_returnsTrue() {
setOverride(OVERRIDE_ON_SETTING);
// Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
}
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags({
FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
- FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
+ FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS
})
- public void isEnabled_dwFlagOff_overrideOn_featureFlagOff_returnFalse() {
+ public void isTrue_dwFlagOff_overrideOn_featureFlagOff_returnFalse() {
setOverride(OVERRIDE_ON_SETTING);
// Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
}
@Test
@EnableFlags({
FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION,
- FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
+ FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS
})
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- public void isEnabled_dwFlagOff_overrideOff_featureFlagOn_returnsTrue() {
+ public void isTrue_dwFlagOff_overrideOff_featureFlagOn_returnsTrue() {
setOverride(OVERRIDE_OFF_SETTING);
// When toggle override matches its default state (dw flag), don't override flags
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
}
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags({
FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
- FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
+ FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS
})
- public void isEnabled_dwFlagOff_overrideOff_featureFlagOff_returnsFalse() {
+ public void isTrue_dwFlagOff_overrideOff_featureFlagOff_returnsFalse() {
setOverride(OVERRIDE_OFF_SETTING);
// When toggle override matches its default state (dw flag), don't override flags
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
+ }
+
+ @Test
+ public void fromSetting_validInt_returnsToggleOverride() {
+ assertThat(fromSetting(0, OVERRIDE_UNSET)).isEqualTo(OVERRIDE_OFF);
+ assertThat(fromSetting(1, OVERRIDE_UNSET)).isEqualTo(OVERRIDE_ON);
+ assertThat(fromSetting(-1, OVERRIDE_ON)).isEqualTo(OVERRIDE_UNSET);
+ }
+
+ @Test
+ public void fromSetting_invalidInt_returnsFallback() {
+ assertThat(fromSetting(2, OVERRIDE_ON)).isEqualTo(OVERRIDE_ON);
+ assertThat(fromSetting(-2, OVERRIDE_UNSET)).isEqualTo(OVERRIDE_UNSET);
+ }
+
+ @Test
+ public void getSetting_returnsToggleOverrideInteger() {
+ assertThat(OVERRIDE_OFF.getSetting()).isEqualTo(0);
+ assertThat(OVERRIDE_ON.getSetting()).isEqualTo(1);
+ assertThat(OVERRIDE_UNSET.getSetting()).isEqualTo(-1);
}
private void setOverride(Integer setting) {
diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
index 5af272c..d6b2a78 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -117,6 +117,7 @@
// Simulate a trace session and see if begin / end are invoked.
assertThat(monitor.begin(mSurfaceControl, mActivity.getApplicationContext(),
+ mActivity.getMainThreadHandler(),
Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isTrue();
verify(tracker).begin();
assertThat(monitor.end(Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isTrue();
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
index 397cdcf..67de25e 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
@@ -125,12 +125,12 @@
}
@Override
- public void addFrozenStateChangeCallback(IFrozenStateChangeCallback callback)
+ public void addFrozenStateChangeCallback(FrozenStateChangeCallback callback)
throws RemoteException {
}
@Override
- public boolean removeFrozenStateChangeCallback(IFrozenStateChangeCallback callback) {
+ public boolean removeFrozenStateChangeCallback(FrozenStateChangeCallback callback) {
return false;
}
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 6d31578..e07471c 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -128,6 +128,22 @@
private static final WeakHashMap<Bitmap, Void> sAllBitmaps = new WeakHashMap<>();
/**
+ * @hide
+ */
+ private static NativeAllocationRegistry getRegistry(boolean malloc, long size) {
+ final long free = nativeGetNativeFinalizer();
+ if (com.android.libcore.Flags.nativeMetrics()) {
+ Class cls = Bitmap.class;
+ return malloc ? NativeAllocationRegistry.createMalloced(cls, free, size)
+ : NativeAllocationRegistry.createNonmalloced(cls, free, size);
+ } else {
+ ClassLoader loader = Bitmap.class.getClassLoader();
+ return malloc ? NativeAllocationRegistry.createMalloced(loader, free, size)
+ : NativeAllocationRegistry.createNonmalloced(loader, free, size);
+ }
+ }
+
+ /**
* Private constructor that must receive an already allocated native bitmap
* int (pointer).
*/
@@ -151,7 +167,6 @@
mWidth = width;
mHeight = height;
mRequestPremultiplied = requestPremultiplied;
-
mNinePatchChunk = ninePatchChunk;
mNinePatchInsets = ninePatchInsets;
if (density >= 0) {
@@ -159,17 +174,9 @@
}
mNativePtr = nativeBitmap;
-
final int allocationByteCount = getAllocationByteCount();
- NativeAllocationRegistry registry;
- if (fromMalloc) {
- registry = NativeAllocationRegistry.createMalloced(
- Bitmap.class.getClassLoader(), nativeGetNativeFinalizer(), allocationByteCount);
- } else {
- registry = NativeAllocationRegistry.createNonmalloced(
- Bitmap.class.getClassLoader(), nativeGetNativeFinalizer(), allocationByteCount);
- }
- registry.registerNativeAllocation(this, nativeBitmap);
+ getRegistry(fromMalloc, allocationByteCount).registerNativeAllocation(this, mNativePtr);
+
synchronized (Bitmap.class) {
sAllBitmaps.put(this, null);
}
diff --git a/graphics/java/android/graphics/GraphicsStatsService.java b/graphics/java/android/graphics/GraphicsStatsService.java
index dc785c5..7a012bc 100644
--- a/graphics/java/android/graphics/GraphicsStatsService.java
+++ b/graphics/java/android/graphics/GraphicsStatsService.java
@@ -311,7 +311,7 @@
Log.w(TAG, "Unable to create path: '" + parent.getAbsolutePath() + "'");
return;
}
- nSaveBuffer(path.getAbsolutePath(), buffer.mInfo.mPackageName,
+ nSaveBuffer(path.getAbsolutePath(), buffer.mInfo.mUid, buffer.mInfo.mPackageName,
buffer.mInfo.mVersionCode, buffer.mInfo.mStartTime, buffer.mInfo.mEndTime,
buffer.mData);
}
@@ -405,7 +405,7 @@
HistoricalBuffer buffer = buffers.get(i);
File path = pathForApp(buffer.mInfo);
skipFiles.add(path);
- nAddToDump(dump, path.getAbsolutePath(), buffer.mInfo.mPackageName,
+ nAddToDump(dump, path.getAbsolutePath(), buffer.mInfo.mUid, buffer.mInfo.mPackageName,
buffer.mInfo.mVersionCode, buffer.mInfo.mStartTime, buffer.mInfo.mEndTime,
buffer.mData);
}
@@ -469,21 +469,23 @@
private static native int nGetAshmemSize();
private static native long nCreateDump(int outFd, boolean isProto);
- private static native void nAddToDump(long dump, String path, String packageName,
+ private static native void nAddToDump(long dump, String path, int uid, String packageName,
long versionCode, long startTime, long endTime, byte[] data);
private static native void nAddToDump(long dump, String path);
private static native void nFinishDump(long dump);
private static native void nFinishDumpInMemory(long dump, long pulledData, boolean lastFullDay);
- private static native void nSaveBuffer(String path, String packageName, long versionCode,
- long startTime, long endTime, byte[] data);
+ private static native void nSaveBuffer(String path, int uid, String packageName,
+ long versionCode, long startTime, long endTime, byte[] data);
private final class BufferInfo {
+ final int mUid;
final String mPackageName;
final long mVersionCode;
long mStartTime;
long mEndTime;
- BufferInfo(String packageName, long versionCode, long startTime) {
+ BufferInfo(int uid, String packageName, long versionCode, long startTime) {
+ this.mUid = uid;
this.mPackageName = packageName;
this.mVersionCode = versionCode;
this.mStartTime = startTime;
@@ -502,7 +504,7 @@
ActiveBuffer(IGraphicsStatsCallback token, int uid, int pid, String packageName,
long versionCode)
throws RemoteException, IOException {
- mInfo = new BufferInfo(packageName, versionCode, System.currentTimeMillis());
+ mInfo = new BufferInfo(uid, packageName, versionCode, System.currentTimeMillis());
mUid = uid;
mPid = pid;
mCallback = token;
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index 4dbff34..e50d8dc 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Skermskoot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Maak in blaaier oop"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nuwe venster"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Maak toe"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Maak kieslys toe"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Maak kieslys oop"</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index d70a317..f29bbe7 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"ቅጽበታዊ ገፅ ዕይታ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"በአሳሽ ውስጥ ክፈት"</string>
<string name="new_window_text" msgid="6318648868380652280">"አዲስ መስኮት"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"ዝጋ"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"ምናሌ ዝጋ"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"ምናሌን ክፈት"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index cb316e9..d76a2a5 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"لقطة شاشة"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"فتح في المتصفِّح"</string>
<string name="new_window_text" msgid="6318648868380652280">"نافذة جديدة"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"إدارة النوافذ"</string>
<string name="close_text" msgid="4986518933445178928">"إغلاق"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"إغلاق القائمة"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"فتح القائمة"</string>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index 9f7fa7c..1fe79ac 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"স্ক্ৰীনশ্বট"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ব্ৰাউজাৰত খোলক"</string>
<string name="new_window_text" msgid="6318648868380652280">"নতুন ৱিণ্ড’"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"বন্ধ কৰক"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"মেনু বন্ধ কৰক"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"মেনু খোলক"</string>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index 90962f0..2992655 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Skrinşot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Brauzerdə açın"</string>
<string name="new_window_text" msgid="6318648868380652280">"Yeni pəncərə"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <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="expand_menu_text" msgid="3847736164494181168">"Menyunu açın"</string>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index 9c6ed6b..12f1418 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Snimak ekrana"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Otvorite u pregledaču"</string>
<string name="new_window_text" msgid="6318648868380652280">"Novi prozor"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Upravljajte prozorima"</string>
<string name="close_text" msgid="4986518933445178928">"Zatvorite"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite meni"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Otvorite meni"</string>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index e8b24bd..8aa43f7 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Здымак экрана"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Адкрыць у браўзеры"</string>
<string name="new_window_text" msgid="6318648868380652280">"Новае акно"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Закрыць"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Закрыць меню"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Адкрыць меню"</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index 1f188f6..b84778b 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Екранна снимка"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Отваряне в браузър"</string>
<string name="new_window_text" msgid="6318648868380652280">"Нов прозорец"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Управление на прозорците"</string>
<string name="close_text" msgid="4986518933445178928">"Затваряне"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Затваряне на менюто"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Отваряне на менюто"</string>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index b572038..5e47e2a 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"স্ক্রিনশট"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ব্রাউজারে খুলুন"</string>
<string name="new_window_text" msgid="6318648868380652280">"নতুন উইন্ডো"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"বন্ধ করুন"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"\'মেনু\' বন্ধ করুন"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"মেনু খুলুন"</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 630b31b..bd7cddd5 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Snimak ekrana"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Otvaranje u pregledniku"</string>
<string name="new_window_text" msgid="6318648868380652280">"Novi prozor"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Upravljanje prozorima"</string>
<string name="close_text" msgid="4986518933445178928">"Zatvaranje"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Zatvaranje menija"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Otvaranje menija"</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 98ec381..af54037 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Captura de pantalla"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Obre al navegador"</string>
<string name="new_window_text" msgid="6318648868380652280">"Finestra nova"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Tanca"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Tanca el menú"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Obre el menú"</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index 08d5bb5..dd4802e 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Snímek obrazovky"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Otevřít v prohlížeči"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nové okno"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Spravovat okna"</string>
<string name="close_text" msgid="4986518933445178928">"Zavřít"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Zavřít nabídku"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Otevřít nabídku"</string>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index ae1bb9a..fca92a1 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Åbn i browser"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nyt vindue"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Luk"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Luk menu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Åbn menu"</string>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index abbfa66..512bd7a 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Im Browser öffnen"</string>
<string name="new_window_text" msgid="6318648868380652280">"Neues Fenster"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Schließen"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Menü schließen"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Menü öffnen"</string>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index 0f762d3..f66d874 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Στιγμιότυπο οθόνης"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Άνοιγμα σε πρόγραμμα περιήγησης"</string>
<string name="new_window_text" msgid="6318648868380652280">"Νέο παράθυρο"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Κλείσιμο"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Κλείσιμο μενού"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Άνοιγμα μενού"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index 2314e6b..0b11cb5 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Open in browser"</string>
<string name="new_window_text" msgid="6318648868380652280">"New window"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Manage windows"</string>
<string name="close_text" msgid="4986518933445178928">"Close"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Open menu"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index f5b0a27..a09e1e9 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Open in browser"</string>
<string name="new_window_text" msgid="6318648868380652280">"New Window"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Manage Windows"</string>
<string name="close_text" msgid="4986518933445178928">"Close"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Close Menu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Open Menu"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index 2314e6b..0b11cb5 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Open in browser"</string>
<string name="new_window_text" msgid="6318648868380652280">"New window"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Manage windows"</string>
<string name="close_text" msgid="4986518933445178928">"Close"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Open menu"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index 2314e6b..0b11cb5 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Open in browser"</string>
<string name="new_window_text" msgid="6318648868380652280">"New window"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Manage windows"</string>
<string name="close_text" msgid="4986518933445178928">"Close"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Open menu"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
index 6292be5..7662a14 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Open in browser"</string>
<string name="new_window_text" msgid="6318648868380652280">"New Window"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Manage Windows"</string>
<string name="close_text" msgid="4986518933445178928">"Close"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Close Menu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Open Menu"</string>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index 0dd0a99..7a324e3 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Captura de pantalla"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Abrir en el navegador"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nueva ventana"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Cerrar"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Abrir el menú"</string>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index 6df154d..27272aa 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Captura de pantalla"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Abrir en el navegador"</string>
<string name="new_window_text" msgid="6318648868380652280">"Ventana nueva"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Cerrar"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Abrir menú"</string>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index cfaa0d3..d859f01 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Ekraanipilt"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Avamine brauseris"</string>
<string name="new_window_text" msgid="6318648868380652280">"Uus aken"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Sule"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Sule menüü"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Ava menüü"</string>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index 509c97e..999960b 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Pantaila-argazkia"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Ireki arakatzailean"</string>
<string name="new_window_text" msgid="6318648868380652280">"Leiho berria"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Itxi"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Itxi menua"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Ireki menua"</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index 223b671..e31a6ca 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"نماگرفت"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"باز کردن در مرورگر"</string>
<string name="new_window_text" msgid="6318648868380652280">"پنجره جدید"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"مدیریت کردن پنجرهها"</string>
<string name="close_text" msgid="4986518933445178928">"بستن"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"بستن منو"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"باز کردن منو"</string>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index 9083c4d..71c3e36 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Kuvakaappaus"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Avaa selaimessa"</string>
<string name="new_window_text" msgid="6318648868380652280">"Uusi ikkuna"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Sulje"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Sulje valikko"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Avaa valikko"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 2f284ad..790a296 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Capture d\'écran"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Ouvrir dans le navigateur"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nouvelle fenêtre"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Fermer"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Ouvrir le menu"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index 92f579d..3472edd 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Capture d\'écran"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Ouvrir dans un navigateur"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nouvelle fenêtre"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Fermer"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Ouvrir le menu"</string>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index 5126aa2..31cb71d 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Captura de pantalla"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Abrir no navegador"</string>
<string name="new_window_text" msgid="6318648868380652280">"Ventá nova"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Pechar"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Pechar o menú"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Abrir menú"</string>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index 3418637..e1f5806 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"સ્ક્રીનશૉટ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"બ્રાઉઝરમાં ખોલો"</string>
<string name="new_window_text" msgid="6318648868380652280">"નવી વિન્ડો"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"વિન્ડો મેનેજ કરો"</string>
<string name="close_text" msgid="4986518933445178928">"બંધ કરો"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"મેનૂ બંધ કરો"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"મેનૂ ખોલો"</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index 8eaa86f..cea4b23 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"स्क्रीनशॉट"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ब्राउज़र में खोलें"</string>
<string name="new_window_text" msgid="6318648868380652280">"नई विंडो"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"विंडो मैनेज करें"</string>
<string name="close_text" msgid="4986518933445178928">"बंद करें"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"मेन्यू बंद करें"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"मेन्यू खोलें"</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 5427a9b..23cddbc 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Snimka zaslona"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Otvori u pregledniku"</string>
<string name="new_window_text" msgid="6318648868380652280">"Novi prozor"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Upravljanje prozorima"</string>
<string name="close_text" msgid="4986518933445178928">"Zatvorite"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite izbornik"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Otvaranje izbornika"</string>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index 5b337ea..e3c3ced 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Képernyőkép"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Megnyitás böngészőben"</string>
<string name="new_window_text" msgid="6318648868380652280">"Új ablak"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <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="expand_menu_text" msgid="3847736164494181168">"Menü megnyitása"</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index ef38307..56b609b 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Սքրինշոթ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Բացել դիտարկիչում"</string>
<string name="new_window_text" msgid="6318648868380652280">"Նոր պատուհան"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Փակել"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Փակել ընտրացանկը"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Բացել ընտրացանկը"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index fcb3e72..a83d51e 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Buka di browser"</string>
<string name="new_window_text" msgid="6318648868380652280">"Jendela Baru"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Tutup"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Buka Menu"</string>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 9755083..e7590cb 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Skjámynd"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Opna í vafra"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nýr gluggi"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Loka"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Loka valmynd"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Opna valmynd"</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index 5f9c492..bd74fbe 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Apri nel browser"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nuova finestra"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Chiudi"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Chiudi il menu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Apri menu"</string>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index ddbb89a..d8533bb 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"צילום מסך"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"פתיחה בדפדפן"</string>
<string name="new_window_text" msgid="6318648868380652280">"חלון חדש"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"סגירה"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"סגירת התפריט"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"פתיחת התפריט"</string>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 8284837..26540c7 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"スクリーンショット"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ブラウザで開く"</string>
<string name="new_window_text" msgid="6318648868380652280">"新しいウィンドウ"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"ウィンドウを管理する"</string>
<string name="close_text" msgid="4986518933445178928">"閉じる"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"メニューを閉じる"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"メニューを開く"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 82828d8..d2fbcb1 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"ეკრანის ანაბეჭდი"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ბრაუზერში გახსნა"</string>
<string name="new_window_text" msgid="6318648868380652280">"ახალი ფანჯარა"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"ფანჯრების მართვა"</string>
<string name="close_text" msgid="4986518933445178928">"დახურვა"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"მენიუს დახურვა"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"მენიუს გახსნა"</string>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index af4e4f3..43c2f83 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Скриншот"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Браузерден ашу"</string>
<string name="new_window_text" msgid="6318648868380652280">"Жаңа терезе"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Жабу"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Мәзірді жабу"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Мәзірді ашу"</string>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index c3a3800..c0bf1bf 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"រូបថតអេក្រង់"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"បើកក្នុងកម្មវិធីរុករកតាមអ៊ីនធឺណិត"</string>
<string name="new_window_text" msgid="6318648868380652280">"វិនដូថ្មី"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"បិទ"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"បិទម៉ឺនុយ"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"បើកម៉ឺនុយ"</string>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index aa8cec5..92b8ad4 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ಬ್ರೌಸರ್ನಲ್ಲಿ ತೆರೆಯಿರಿ"</string>
<string name="new_window_text" msgid="6318648868380652280">"ಹೊಸ ವಿಂಡೋ"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"ವಿಂಡೋಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
<string name="close_text" msgid="4986518933445178928">"ಮುಚ್ಚಿ"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"ಮೆನು ಮುಚ್ಚಿ"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"ಮೆನು ತೆರೆಯಿರಿ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index fc2a1b9..b52c8a1 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"스크린샷"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"브라우저에서 열기"</string>
<string name="new_window_text" msgid="6318648868380652280">"새 창"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"닫기"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"메뉴 닫기"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"메뉴 열기"</string>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index c294725..f994d1e 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Скриншот"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Серепчиден ачуу"</string>
<string name="new_window_text" msgid="6318648868380652280">"Жаңы терезе"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Жабуу"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Менюну жабуу"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Менюну ачуу"</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index 7d2f999..459f3a2 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"ຮູບໜ້າຈໍ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ເປີດໃນໂປຣແກຣມທ່ອງເວັບ"</string>
<string name="new_window_text" msgid="6318648868380652280">"ໜ້າຈໍໃໝ່"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"ຈັດການໜ້າຈໍ"</string>
<string name="close_text" msgid="4986518933445178928">"ປິດ"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"ປິດເມນູ"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"ເປີດເມນູ"</string>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index be446a6..2bfd9d3 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Ekrano kopija"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Atidaryti naršyklėje"</string>
<string name="new_window_text" msgid="6318648868380652280">"Naujas langas"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Tvarkyti langus"</string>
<string name="close_text" msgid="4986518933445178928">"Uždaryti"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Uždaryti meniu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Atidaryti meniu"</string>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index ed0c05e..b601274 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Ekrānuzņēmums"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Atvērt pārlūkā"</string>
<string name="new_window_text" msgid="6318648868380652280">"Jauns logs"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Aizvērt"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Aizvērt izvēlni"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Atvērt izvēlni"</string>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index 9b24b7f..96e7f25 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Слика од екранот"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Отвори во прелистувач"</string>
<string name="new_window_text" msgid="6318648868380652280">"Нов прозорец"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Управувајте со прозорци"</string>
<string name="close_text" msgid="4986518933445178928">"Затворете"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Затворете го менито"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Отвори го менито"</string>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index ac67f8d..a77c203 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"സ്ക്രീൻഷോട്ട്"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ബ്രൗസറിൽ തുറക്കുക"</string>
<string name="new_window_text" msgid="6318648868380652280">"പുതിയ വിന്ഡോ"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"അടയ്ക്കുക"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"മെനു അടയ്ക്കുക"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"മെനു തുറക്കുക"</string>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index 6d5deb3..5c7f548 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Дэлгэцийн агшин"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Хөтчид нээх"</string>
<string name="new_window_text" msgid="6318648868380652280">"Шинэ цонх"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Хаах"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Цэсийг хаах"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Цэс нээх"</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index 49747f2..a78b37b 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"स्क्रीनशॉट"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ब्राउझरमध्ये उघडा"</string>
<string name="new_window_text" msgid="6318648868380652280">"नवीन विंडो"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"बंद करा"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"मेनू बंद करा"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"मेनू उघडा"</string>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index dec3893..fa2c1c5 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Tangkapan skrin"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Buka dalam penyemak imbas"</string>
<string name="new_window_text" msgid="6318648868380652280">"Tetingkap Baharu"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Tutup"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Buka Menu"</string>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index 908ef81..48449c0 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ဘရောင်ဇာတွင် ဖွင့်ရန်"</string>
<string name="new_window_text" msgid="6318648868380652280">"ဝင်းဒိုးအသစ်"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"ပိတ်ရန်"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"မီနူး ပိတ်ရန်"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"မီနူး ဖွင့်ရန်"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 01ca4ed..5697f0d 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Skjermbilde"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Åpne i nettleseren"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nytt vindu"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Lukk"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Lukk menyen"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Åpne menyen"</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index 05ce071..365a3b3 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"स्क्रिनसट"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ब्राउजरमा खोल्नुहोस्"</string>
<string name="new_window_text" msgid="6318648868380652280">"नयाँ विन्डो"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"बन्द गर्नुहोस्"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"मेनु बन्द गर्नुहोस्"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"मेनु खोल्नुहोस्"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 9ec4444..9cf1551 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Openen in browser"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nieuw venster"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Sluiten"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Menu sluiten"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Menu openen"</string>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index 7ee7342..9f7342c 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"ସ୍କ୍ରିନସଟ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ବ୍ରାଉଜରରେ ଖୋଲନ୍ତୁ"</string>
<string name="new_window_text" msgid="6318648868380652280">"ନୂଆ ୱିଣ୍ଡୋ"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"ମେନୁ ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"ମେନୁ ଖୋଲନ୍ତୁ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index cc31e3c..48fa552 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"ਬ੍ਰਾਊਜ਼ਰ ਵਿੱਚ ਖੋਲ੍ਹੋ"</string>
<string name="new_window_text" msgid="6318648868380652280">"ਨਵੀਂ ਵਿੰਡੋ"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"ਬੰਦ ਕਰੋ"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"ਮੀਨੂ ਬੰਦ ਕਰੋ"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"ਮੀਨੂ ਖੋਲ੍ਹੋ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index 5dd14c9..211ae98 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Zrzut ekranu"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Otwórz w przeglądarce"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nowe okno"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Zamknij"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Zamknij menu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Otwórz menu"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index d9c3d44..dfae5d8 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Captura de tela"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Abrir no navegador"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nova janela"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Fechar"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Abrir o menu"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index 1ace699..1399b26 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Captura de ecrã"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Abrir no navegador"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nova janela"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Faça a gestão das janelas"</string>
<string name="close_text" msgid="4986518933445178928">"Fechar"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Abrir menu"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index d9c3d44..dfae5d8 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Captura de tela"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Abrir no navegador"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nova janela"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Fechar"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Abrir o menu"</string>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index ffaea97..2f458e9 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Captură de ecran"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Deschide în browser"</string>
<string name="new_window_text" msgid="6318648868380652280">"Fereastră nouă"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Gestionează ferestrele"</string>
<string name="close_text" msgid="4986518933445178928">"Închide"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Închide meniul"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Deschide meniul"</string>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index 6231e3e..a7fdd41 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Скриншот"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Открыть в браузере"</string>
<string name="new_window_text" msgid="6318648868380652280">"Новое окно"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Управление окнами"</string>
<string name="close_text" msgid="4986518933445178928">"Закрыть"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Закрыть меню"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Открыть меню"</string>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index 824bd8d..bbfafb6 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"තිර රුව"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"බ්රව්සරයේ විවෘත කරන්න"</string>
<string name="new_window_text" msgid="6318648868380652280">"නව කවුළුව"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"වසන්න"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"මෙනුව වසන්න"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"මෙනුව විවෘත කරන්න"</string>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index 4a1508d..da7a834 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Snímka obrazovky"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Otvoriť v prehliadači"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nové okno"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Zavrieť"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Zavrieť ponuku"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Otvoriť ponuku"</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index dd2f9f0..0434e54 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Posnetek zaslona"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Odpri v brskalniku"</string>
<string name="new_window_text" msgid="6318648868380652280">"Novo okno"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Upravljanje oken"</string>
<string name="close_text" msgid="4986518933445178928">"Zapri"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Zapri meni"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Odpri meni"</string>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index 322525b..65a270d 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Pamja e ekranit"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Hape në shfletues"</string>
<string name="new_window_text" msgid="6318648868380652280">"Dritare e re"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Mbyll"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Mbyll menynë"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Hap menynë"</string>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index 87ae78e..caa9c7d 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Снимак екрана"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Отворите у прегледачу"</string>
<string name="new_window_text" msgid="6318648868380652280">"Нови прозор"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Управљајте прозорима"</string>
<string name="close_text" msgid="4986518933445178928">"Затворите"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Затворите мени"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Отворите мени"</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 6942e95..681ef8b 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Skärmbild"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Öppna i webbläsaren"</string>
<string name="new_window_text" msgid="6318648868380652280">"Nytt fönster"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Hantera fönster"</string>
<string name="close_text" msgid="4986518933445178928">"Stäng"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Stäng menyn"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Öppna menyn"</string>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 30d6870..bb314a3 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Picha ya skrini"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Fungua katika kivinjari"</string>
<string name="new_window_text" msgid="6318648868380652280">"Dirisha Jipya"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Funga"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Funga Menyu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Fungua Menyu"</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 9e51416..686e705 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"ஸ்கிரீன்ஷாட்"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"உலாவியில் திறக்கும்"</string>
<string name="new_window_text" msgid="6318648868380652280">"புதிய சாளரம்"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"மூடும்"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"மெனுவை மூடும்"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"மெனுவைத் திற"</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index be770ca..7b554d9 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"స్క్రీన్షాట్"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"బ్రౌజర్లో తెరవండి"</string>
<string name="new_window_text" msgid="6318648868380652280">"కొత్త విండో"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"విండోలను మేనేజ్ చేయండి"</string>
<string name="close_text" msgid="4986518933445178928">"మూసివేయండి"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"మెనూను మూసివేయండి"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"మెనూను తెరవండి"</string>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index e7975ac..59deabb 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"ภาพหน้าจอ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"เปิดในเบราว์เซอร์"</string>
<string name="new_window_text" msgid="6318648868380652280">"หน้าต่างใหม่"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"จัดการหน้าต่าง"</string>
<string name="close_text" msgid="4986518933445178928">"ปิด"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"ปิดเมนู"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"เปิดเมนู"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 72d0926..79e968d 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Buksan sa browser"</string>
<string name="new_window_text" msgid="6318648868380652280">"Bagong Window"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Pamahalaan ang Mga Window"</string>
<string name="close_text" msgid="4986518933445178928">"Isara"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Isara ang Menu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Buksan ang Menu"</string>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index 2b02f47..e5bca20 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Ekran görüntüsü"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Tarayıcıda aç"</string>
<string name="new_window_text" msgid="6318648868380652280">"Yeni Pencere"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Kapat"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Menüyü kapat"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Menüyü Aç"</string>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index 47126ac..0e877b0 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Знімок екрана"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Відкрити у вебпереглядачі"</string>
<string name="new_window_text" msgid="6318648868380652280">"Нове вікно"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Закрити"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Закрити меню"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Відкрити меню"</string>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 859288f..06807957 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"اسکرین شاٹ"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"براؤزر میں کھولیں"</string>
<string name="new_window_text" msgid="6318648868380652280">"نئی ونڈو"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Windows کا نظم کریں"</string>
<string name="close_text" msgid="4986518933445178928">"بند کریں"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"مینیو بند کریں"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"مینو کھولیں"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 625fc8e..4e0eb53 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -123,6 +123,7 @@
<string name="screenshot_text" msgid="1477704010087786671">"Skrinshot"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Brauzerda ochish"</string>
<string name="new_window_text" msgid="6318648868380652280">"Yangi oyna"</string>
+ <string name="manage_windows_text" msgid="5567366688493093920">"Oynalarni boshqarish"</string>
<string name="close_text" msgid="4986518933445178928">"Yopish"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Menyuni yopish"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Menyuni ochish"</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index 2e643dd..c5d76ea 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Ảnh chụp màn hình"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Mở trong trình duyệt"</string>
<string name="new_window_text" msgid="6318648868380652280">"Cửa sổ mới"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Đóng"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Đóng trình đơn"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Mở Trình đơn"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index f023f53..1202168 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"屏幕截图"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"在浏览器中打开"</string>
<string name="new_window_text" msgid="6318648868380652280">"新窗口"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"关闭"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"关闭菜单"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"打开菜单"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index 5c2ef04..a23b147 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"螢幕截圖"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"在瀏覽器中開啟"</string>
<string name="new_window_text" msgid="6318648868380652280">"新視窗"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"關閉"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"打開選單"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index a362d5b..e70a8ad 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"螢幕截圖"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"在瀏覽器中開啟"</string>
<string name="new_window_text" msgid="6318648868380652280">"新視窗"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"關閉"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"開啟選單"</string>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index 3a3f431..13a2a0f 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -123,6 +123,8 @@
<string name="screenshot_text" msgid="1477704010087786671">"Isithombe-skrini"</string>
<string name="open_in_browser_text" msgid="9181692926376072904">"Vula kubhrawuza"</string>
<string name="new_window_text" msgid="6318648868380652280">"Iwindi Elisha"</string>
+ <!-- no translation found for manage_windows_text (5567366688493093920) -->
+ <skip />
<string name="close_text" msgid="4986518933445178928">"Vala"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Vala Imenyu"</string>
<string name="expand_menu_text" msgid="3847736164494181168">"Vula Imenyu"</string>
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index fe8b818..a14461a 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -17,7 +17,7 @@
<resources>
<!-- Determines whether the shell features all run on another thread. This is to be overrided
by the resources of the app using the Shell library. -->
- <bool name="config_enableShellMainThread">false</bool>
+ <bool name="config_enableShellMainThread">true</bool>
<!-- Determines whether to register the shell task organizer on init.
TODO(b/238217847): This config is temporary until we refactor the base WMComponent. -->
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt
deleted file mode 100644
index b5d63bd..0000000
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt
+++ /dev/null
@@ -1,143 +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.wm.shell.shared.desktopmode
-
-import android.content.Context
-import android.provider.Settings
-import android.util.Log
-import com.android.window.flags.Flags
-
-/*
- * An enum to check desktop mode flags state.
- *
- * This enum provides a centralized way to control the behavior of flags related to desktop
- * windowing features which are aiming for developer preview before their release. It allows
- * developer option to override the default behavior of these flags.
- *
- * NOTE: Flags should only be added to this enum when they have received Product and UX
- * alignment that the feature is ready for developer preview, otherwise just do a flag check.
- */
-enum class DesktopModeFlags(
- // Function called to obtain aconfig flag value.
- private val flagFunction: () -> Boolean,
- // Whether the flag state should be affected by developer option.
- private val shouldOverrideByDevOption: Boolean
-) {
- // All desktop mode related flags will be added here
- DESKTOP_WINDOWING_MODE(Flags::enableDesktopWindowingMode, true),
- CASCADING_WINDOWS(Flags::enableCascadingWindows, true),
- WALLPAPER_ACTIVITY(Flags::enableDesktopWindowingWallpaperActivity, true),
- MODALS_POLICY(Flags::enableDesktopWindowingModalsPolicy, true),
- THEMED_APP_HEADERS(Flags::enableThemedAppHeaders, true),
- QUICK_SWITCH(Flags::enableDesktopWindowingQuickSwitch, true),
- APP_HEADER_WITH_TASK_DENSITY(Flags::enableAppHeaderWithTaskDensity, true),
- TASK_STACK_OBSERVER_IN_SHELL(Flags::enableTaskStackObserverInShell, true),
- SIZE_CONSTRAINTS(Flags::enableDesktopWindowingSizeConstraints, true),
- DISABLE_SNAP_RESIZE(Flags::disableNonResizableAppSnapResizing, true),
- DYNAMIC_INITIAL_BOUNDS(Flags::enableWindowingDynamicInitialBounds, false),
- SCALED_RESIZING(Flags::enableWindowingScaledResizing, false),
- ENABLE_DESKTOP_WINDOWING_TASK_LIMIT(Flags::enableDesktopWindowingTaskLimit, true),
- BACK_NAVIGATION(Flags::enableDesktopWindowingBackNavigation, true),
- EDGE_DRAG_RESIZE(Flags::enableWindowingEdgeDragResize, true),
- TASKBAR_RUNNING_APPS(Flags::enableDesktopWindowingTaskbarRunningApps, true);
-
- /**
- * Determines state of flag based on the actual flag and desktop mode developer option
- * overrides.
- */
- fun isEnabled(context: Context): Boolean =
- if (!Flags.showDesktopWindowingDevOption() ||
- !shouldOverrideByDevOption ||
- context.contentResolver == null) {
- flagFunction()
- } else {
- val shouldToggleBeEnabledByDefault =
- DesktopModeStatus.shouldDevOptionBeEnabledByDefault()
- when (getToggleOverride(context)) {
- ToggleOverride.OVERRIDE_UNSET -> flagFunction()
- // When toggle override matches its default state, don't override flags. This helps
- // users reset their feature overrides.
- ToggleOverride.OVERRIDE_OFF ->
- if (shouldToggleBeEnabledByDefault) false else flagFunction()
- ToggleOverride.OVERRIDE_ON ->
- if (shouldToggleBeEnabledByDefault) flagFunction() else true
- }
- }
-
- private fun getToggleOverride(context: Context): ToggleOverride {
- val override =
- cachedToggleOverride
- ?: run {
- val override = getToggleOverrideFromSystem(context)
- // Cache toggle override the first time we encounter context. Override does not
- // change with context, as context is just used to fetch Settings.Global
- cachedToggleOverride = override
- Log.d(TAG, "Toggle override initialized to: $override")
- override
- }
-
- return override
- }
-
- private fun getToggleOverrideFromSystem(context: Context): ToggleOverride =
- convertToToggleOverrideWithFallback(
- Settings.Global.getInt(
- context.contentResolver,
- Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES,
- ToggleOverride.OVERRIDE_UNSET.setting),
- ToggleOverride.OVERRIDE_UNSET)
-
- /**
- * Override state of desktop mode developer option toggle.
- *
- * @property setting The integer value that is associated with the developer option toggle
- * override
- */
- enum class ToggleOverride(val setting: Int) {
- /** No override is set. */
- OVERRIDE_UNSET(-1),
- /** Override to off. */
- OVERRIDE_OFF(0),
- /** Override to on. */
- OVERRIDE_ON(1)
- }
-
- companion object {
- private const val TAG = "DesktopModeFlags"
-
- /**
- * Local cache for toggle override, which is initialized once on its first access. It needs
- * to be refreshed only on reboots as overridden state is expected to take effect on
- * reboots.
- */
- private var cachedToggleOverride: ToggleOverride? = null
-
- private val settingToToggleOverrideMap = ToggleOverride.entries.associateBy { it.setting }
-
- @JvmStatic
- fun convertToToggleOverrideWithFallback(
- overrideInt: Int,
- fallbackOverride: ToggleOverride
- ): ToggleOverride {
- return settingToToggleOverrideMap[overrideInt]
- ?: run {
- Log.w(TAG, "Unknown toggleOverride int $overrideInt")
- fallbackOverride
- }
- }
- }
-}
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 dd86a1a..647a555a 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
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.content.Context;
import android.os.SystemProperties;
+import android.window.flags.DesktopModeFlags;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -90,9 +91,6 @@
/** The maximum override density allowed for tasks inside the desktop. */
private static final int DESKTOP_DENSITY_MAX = 1000;
- /** The number of [WindowDecorViewHost] instances to warm up on system start. */
- private static final int WINDOW_DECOR_PRE_WARM_SIZE = 2;
-
/**
* Sysprop declaring whether to enters desktop mode by default when the windowing mode of the
* display's root TaskDisplayArea is set to WINDOWING_MODE_FREEFORM.
@@ -115,14 +113,6 @@
private static final String MAX_TASK_LIMIT_SYS_PROP = "persist.wm.debug.desktop_max_task_limit";
/**
- * Sysprop declaring the number of [WindowDecorViewHost] instances to warm up on system start.
- *
- * <p>If it is not defined, then [WINDOW_DECOR_PRE_WARM_SIZE] is used.
- */
- private static final String WINDOW_DECOR_PRE_WARM_SIZE_SYS_PROP =
- "persist.wm.debug.desktop_window_decor_pre_warm_size";
-
- /**
* Return {@code true} if veiled resizing is active. If false, fluid resizing is used.
*/
public static boolean isVeiledResizeEnabled() {
@@ -162,12 +152,6 @@
context.getResources().getInteger(R.integer.config_maxDesktopWindowingActiveTasks));
}
- /** The number of [WindowDecorViewHost] instances to warm up on system start. */
- public static int getWindowDecorPreWarmSize() {
- return SystemProperties.getInt(WINDOW_DECOR_PRE_WARM_SIZE_SYS_PROP,
- WINDOW_DECOR_PRE_WARM_SIZE);
- }
-
/**
* Return {@code true} if the current device supports desktop mode.
*/
@@ -194,7 +178,7 @@
public static boolean canEnterDesktopMode(@NonNull Context context) {
if (!isDeviceEligibleForDesktopMode(context)) return false;
- return DesktopModeFlags.DESKTOP_WINDOWING_MODE.isEnabled(context);
+ return DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE.isTrue();
}
/**
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 f478b44..3e5adf3 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
@@ -117,6 +117,7 @@
*/
private static final long MAX_ANIMATION_DURATION = 2000;
private final LatencyTracker mLatencyTracker;
+ @ShellMainThread private final Handler mHandler;
/** True when a back gesture is ongoing */
private boolean mBackGestureStarted = false;
@@ -218,7 +219,8 @@
@NonNull BackAnimationBackground backAnimationBackground,
ShellBackAnimationRegistry shellBackAnimationRegistry,
ShellCommandHandler shellCommandHandler,
- Transitions transitions) {
+ Transitions transitions,
+ @ShellMainThread Handler handler) {
this(
shellInit,
shellController,
@@ -230,7 +232,8 @@
backAnimationBackground,
shellBackAnimationRegistry,
shellCommandHandler,
- transitions);
+ transitions,
+ handler);
}
@VisibleForTesting
@@ -245,7 +248,8 @@
@NonNull BackAnimationBackground backAnimationBackground,
ShellBackAnimationRegistry shellBackAnimationRegistry,
ShellCommandHandler shellCommandHandler,
- Transitions transitions) {
+ Transitions transitions,
+ @NonNull @ShellMainThread Handler handler) {
mShellController = shellController;
mShellExecutor = shellExecutor;
mActivityTaskManager = activityTaskManager;
@@ -263,6 +267,7 @@
mTransitions = transitions;
mBackTransitionHandler = new BackTransitionHandler();
mTransitions.addHandler(mBackTransitionHandler);
+ mHandler = handler;
updateTouchableArea();
}
@@ -399,7 +404,7 @@
}
}
- private static class IBackAnimationImpl extends IBackAnimation.Stub
+ private class IBackAnimationImpl extends IBackAnimation.Stub
implements ExternalInterfaceBinder {
private BackAnimationController mController;
@@ -417,7 +422,8 @@
callback,
runner,
controller.mContext,
- CUJ_PREDICTIVE_BACK_HOME)));
+ CUJ_PREDICTIVE_BACK_HOME,
+ mHandler)));
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java
index e24df0b..9ca9b73 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.view.IRemoteAnimationFinishedCallback;
@@ -31,6 +32,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.Cuj.CujType;
import com.android.internal.jank.InteractionJankMonitor;
+import com.android.wm.shell.shared.annotations.ShellMainThread;
/**
* Used to register the animation callback and runner, it will trigger result if gesture was finish
@@ -45,6 +47,8 @@
private final IRemoteAnimationRunner mRunner;
private final @CujType int mCujType;
private final Context mContext;
+ @ShellMainThread
+ private final Handler mHandler;
// Whether we are waiting to receive onAnimationStart
private boolean mWaitingAnimation;
@@ -56,18 +60,35 @@
@NonNull IOnBackInvokedCallback callback,
@NonNull IRemoteAnimationRunner runner,
@NonNull Context context,
- @CujType int cujType) {
+ @CujType int cujType,
+ @ShellMainThread Handler handler) {
mCallback = callback;
mRunner = runner;
mCujType = cujType;
mContext = context;
+ mHandler = handler;
}
public BackAnimationRunner(
@NonNull IOnBackInvokedCallback callback,
@NonNull IRemoteAnimationRunner runner,
- @NonNull Context context) {
- this(callback, runner, context, NO_CUJ);
+ @NonNull Context context,
+ @ShellMainThread Handler handler
+ ) {
+ this(callback, runner, context, NO_CUJ, handler);
+ }
+
+ /**
+ * @deprecated Use {@link BackAnimationRunner} constructor providing an handler for the ui
+ * thread of the animation.
+ */
+ @Deprecated
+ public BackAnimationRunner(
+ @NonNull IOnBackInvokedCallback callback,
+ @NonNull IRemoteAnimationRunner runner,
+ @NonNull Context context
+ ) {
+ this(callback, runner, context, NO_CUJ, context.getMainThreadHandler());
}
/** Returns the registered animation runner */
@@ -100,7 +121,7 @@
mWaitingAnimation = false;
if (shouldMonitorCUJ(apps)) {
interactionJankMonitor.begin(
- apps[0].leash, mContext, mCujType);
+ apps[0].leash, mContext, mHandler, mCujType);
}
try {
getRunner().onAnimationStart(TRANSIT_OLD_UNSET, apps, wallpapers,
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 32e809a..3733930 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
@@ -26,6 +26,7 @@
import android.graphics.PointF
import android.graphics.Rect
import android.graphics.RectF
+import android.os.Handler
import android.os.RemoteException
import android.util.TimeUtils
import android.view.Choreographer
@@ -53,6 +54,7 @@
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.protolog.ShellProtoLogGroup
import com.android.wm.shell.shared.animation.Interpolators
+import com.android.wm.shell.shared.annotations.ShellMainThread
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
@@ -61,7 +63,8 @@
private val context: Context,
private val background: BackAnimationBackground,
private val rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
- protected val transaction: SurfaceControl.Transaction
+ protected val transaction: SurfaceControl.Transaction,
+ @ShellMainThread handler: Handler,
) : ShellBackAnimation() {
protected val startClosingRect = RectF()
@@ -80,7 +83,13 @@
private var statusbarHeight = SystemBarUtils.getStatusBarHeight(context)
private val backAnimationRunner =
- BackAnimationRunner(Callback(), Runner(), context, Cuj.CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY)
+ BackAnimationRunner(
+ Callback(),
+ Runner(),
+ context,
+ Cuj.CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY,
+ handler,
+ )
private val initialTouchPos = PointF()
private val transformMatrix = Matrix()
private val tmpFloat9 = FloatArray(9)
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 3fcceca..7a56979 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
@@ -34,6 +34,7 @@
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.os.Handler;
import android.os.RemoteException;
import android.view.Choreographer;
import android.view.IRemoteAnimationFinishedCallback;
@@ -52,6 +53,7 @@
import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.shared.animation.Interpolators;
+import com.android.wm.shell.shared.annotations.ShellMainThread;
import javax.inject.Inject;
@@ -113,9 +115,10 @@
private float mVerticalMargin;
@Inject
- public CrossTaskBackAnimation(Context context, BackAnimationBackground background) {
+ public CrossTaskBackAnimation(Context context, BackAnimationBackground background,
+ @ShellMainThread Handler handler) {
mBackAnimationRunner = new BackAnimationRunner(
- new Callback(), new Runner(), context, CUJ_PREDICTIVE_BACK_CROSS_TASK);
+ new Callback(), new Runner(), context, CUJ_PREDICTIVE_BACK_CROSS_TASK, handler);
mBackground = background;
mContext = context;
loadResources();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt
index b02f97b..2f7666b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.graphics.Rect
import android.graphics.RectF
+import android.os.Handler
import android.util.MathUtils
import android.view.SurfaceControl
import android.view.animation.Animation
@@ -30,6 +31,7 @@
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.protolog.ShellProtoLogGroup
+import com.android.wm.shell.shared.annotations.ShellMainThread
import javax.inject.Inject
import kotlin.math.max
import kotlin.math.min
@@ -40,13 +42,15 @@
background: BackAnimationBackground,
rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
transaction: SurfaceControl.Transaction,
- private val customAnimationLoader: CustomAnimationLoader
+ private val customAnimationLoader: CustomAnimationLoader,
+ @ShellMainThread handler: Handler,
) :
CrossActivityBackAnimation(
context,
background,
rootTaskDisplayAreaOrganizer,
- transaction
+ transaction,
+ handler
) {
private var enterAnimation: Animation? = null
@@ -59,7 +63,8 @@
constructor(
context: Context,
background: BackAnimationBackground,
- rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
+ rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
+ @ShellMainThread handler: Handler,
) : this(
context,
background,
@@ -67,7 +72,8 @@
SurfaceControl.Transaction(),
CustomAnimationLoader(
TransitionAnimation(context, false /* debug */, "CustomCrossActivityBackAnimation")
- )
+ ),
+ handler,
)
override fun preparePreCommitClosingRectMovement(swipeEdge: Int) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt
index 66d8a5f..eecd769 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt
@@ -16,11 +16,13 @@
package com.android.wm.shell.back
import android.content.Context
+import android.os.Handler
import android.view.SurfaceControl
import android.window.BackEvent
import com.android.wm.shell.R
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.shared.animation.Interpolators
+import com.android.wm.shell.shared.annotations.ShellMainThread
import javax.inject.Inject
import kotlin.math.max
@@ -30,13 +32,15 @@
constructor(
context: Context,
background: BackAnimationBackground,
- rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
+ rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
+ @ShellMainThread handler: Handler,
) :
CrossActivityBackAnimation(
context,
background,
rootTaskDisplayAreaOrganizer,
- SurfaceControl.Transaction()
+ SurfaceControl.Transaction(),
+ handler
) {
private val postCommitInterpolator = Interpolators.EMPHASIZED
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 c545d73..af4a0c5 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
@@ -1241,8 +1241,9 @@
mBubbleData.dismissBubbleWithKey(
bubbleKey, Bubbles.DISMISS_USER_GESTURE_FROM_LAUNCHER, timestamp);
}
- if (selectedBubbleKey != null && !selectedBubbleKey.equals(bubbleKey)) {
- // We did not remove the selected bubble. Expand it again
+ if (mBubbleData.hasBubbles()) {
+ // We still have bubbles, if we dragged an individual bubble to dismiss we were expanded
+ // so re-expand to whatever is selected.
showExpandedViewForBubbleBar();
}
}
@@ -2007,7 +2008,7 @@
@Override
public void selectionChanged(BubbleViewProvider selectedBubble) {
// Only need to update the layer view if we're currently expanded for selection changes.
- if (mLayerView != null && isStackExpanded()) {
+ if (mLayerView != null && mLayerView.isExpanded()) {
mLayerView.showExpandedView(selectedBubble);
}
}
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 1c9c195..1367b7e 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
@@ -186,6 +186,10 @@
if (expandedView == null) {
return;
}
+ if (mExpandedBubble != null && mIsExpanded && b.getKey().equals(mExpandedBubble.getKey())) {
+ // Already showing this bubble, skip animating
+ return;
+ }
if (mExpandedBubble != null && !b.getKey().equals(mExpandedBubble.getKey())) {
removeView(mExpandedView);
mExpandedView = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index b8aa1b1..4b55fd0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -48,6 +48,7 @@
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.Handler;
import android.view.Display;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
@@ -75,6 +76,7 @@
import com.android.wm.shell.common.split.DividerSnapAlgorithm.SnapTarget;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.animation.Interpolators;
+import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
import com.android.wm.shell.shared.split.SplitScreenConstants.SnapPosition;
import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
@@ -116,6 +118,8 @@
new PathInterpolator(0.2f, 0f, 0f, 1f);
private static final Interpolator GROW_INTERPOLATOR =
new PathInterpolator(0.45f, 0f, 0.5f, 1f);
+ @ShellMainThread
+ private final Handler mHandler;
private int mDividerWindowWidth;
private int mDividerInsets;
@@ -166,7 +170,8 @@
SplitLayoutHandler splitLayoutHandler,
SplitWindowManager.ParentContainerCallbacks parentContainerCallbacks,
DisplayController displayController, DisplayImeController displayImeController,
- ShellTaskOrganizer taskOrganizer, int parallaxType) {
+ ShellTaskOrganizer taskOrganizer, int parallaxType, @ShellMainThread Handler handler) {
+ mHandler = handler;
mContext = context.createConfigurationContext(configuration);
mOrientation = configuration.orientation;
mRotation = configuration.windowConfiguration.getRotation();
@@ -598,7 +603,8 @@
}
void onStartDragging() {
- mInteractionJankMonitor.begin(getDividerLeash(), mContext, CUJ_SPLIT_SCREEN_RESIZE);
+ mInteractionJankMonitor.begin(getDividerLeash(), mContext, mHandler,
+ CUJ_SPLIT_SCREEN_RESIZE);
}
void onDraggingCancelled() {
@@ -756,7 +762,7 @@
@Override
public void onAnimationStart(Animator animation) {
mInteractionJankMonitor.begin(getDividerLeash(),
- mContext, CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER);
+ mContext, mHandler, CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
index 17869e9..4d15605c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
@@ -27,6 +27,7 @@
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
+import android.window.flags.DesktopModeFlags;
import com.android.internal.annotations.VisibleForTesting;
import com.android.window.flags.Flags;
@@ -37,7 +38,6 @@
import com.android.wm.shell.compatui.CompatUIController.CompatUIHintsState;
import com.android.wm.shell.compatui.api.CompatUIEvent;
import com.android.wm.shell.compatui.impl.CompatUIEvents.SizeCompatRestartButtonAppeared;
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import java.util.function.Consumer;
@@ -83,7 +83,7 @@
mCallback = callback;
mHasSizeCompat = taskInfo.appCompatTaskInfo.isTopActivityInSizeCompat();
if (DesktopModeStatus.canEnterDesktopMode(context)
- && DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(context)) {
+ && DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()) {
// Don't show the SCM button for freeform tasks
mHasSizeCompat &= !taskInfo.isFreeform();
}
@@ -139,7 +139,7 @@
final boolean prevHasSizeCompat = mHasSizeCompat;
mHasSizeCompat = taskInfo.appCompatTaskInfo.isTopActivityInSizeCompat();
if (DesktopModeStatus.canEnterDesktopMode(mContext)
- && DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)) {
+ && DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()) {
// Don't show the SCM button for freeform tasks
mHasSizeCompat &= !taskInfo.isFreeform();
}
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 4adea23..bec2ea5 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
@@ -444,7 +444,9 @@
BackAnimationBackground backAnimationBackground,
Optional<ShellBackAnimationRegistry> shellBackAnimationRegistry,
ShellCommandHandler shellCommandHandler,
- Transitions transitions) {
+ Transitions transitions,
+ @ShellMainThread Handler handler
+ ) {
if (BackAnimationController.IS_ENABLED) {
return shellBackAnimationRegistry.map(
(animations) ->
@@ -457,7 +459,8 @@
backAnimationBackground,
animations,
shellCommandHandler,
- transitions));
+ transitions,
+ handler));
}
return Optional.empty();
}
@@ -1016,11 +1019,10 @@
@WMSingleton
@Provides
static TaskStackTransitionObserver provideTaskStackTransitionObserver(
- Context context,
Lazy<Transitions> transitions,
ShellInit shellInit
) {
- return new TaskStackTransitionObserver(context, transitions, shellInit);
+ return new TaskStackTransitionObserver(transitions, shellInit);
}
//
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 05a70d8..80a9b67 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
@@ -16,7 +16,7 @@
package com.android.wm.shell.dagger;
-import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT;
+import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -75,6 +75,7 @@
import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator;
import com.android.wm.shell.desktopmode.SpringDragToDesktopTransitionHandler;
import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler;
+import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository;
import com.android.wm.shell.desktopmode.education.AppHandleEducationController;
import com.android.wm.shell.desktopmode.education.AppHandleEducationFilter;
import com.android.wm.shell.desktopmode.education.data.AppHandleEducationDatastoreRepository;
@@ -116,8 +117,6 @@
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import com.android.wm.shell.windowdecor.viewhost.DefaultWindowDecorViewHostSupplier;
-import com.android.wm.shell.windowdecor.viewhost.PooledWindowDecorViewHostSupplier;
-import com.android.wm.shell.windowdecor.viewhost.ReusableWindowDecorViewHost;
import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
import dagger.Binds;
@@ -143,7 +142,7 @@
includes = {
WMShellBaseModule.class,
PipModule.class,
- ShellBackAnimationModule.class,
+ ShellBackAnimationModule.class
})
public abstract class WMShellModule {
@@ -249,6 +248,7 @@
AssistContentRequester assistContentRequester,
MultiInstanceHelper multiInstanceHelper,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
+ WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
Optional<DesktopActivityOrientationChangeHandler> desktopActivityOrientationHandler,
WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
if (DesktopModeStatus.canEnterDesktopMode(context)) {
@@ -274,6 +274,7 @@
assistContentRequester,
multiInstanceHelper,
desktopTasksLimiter,
+ windowDecorCaptionHandleRepository,
desktopActivityOrientationHandler,
windowDecorViewHostSupplier);
}
@@ -355,7 +356,8 @@
@ShellMainThread ShellExecutor mainExecutor,
@ShellAnimationThread ShellExecutor animExecutor,
@DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,
- InteractionJankMonitor interactionJankMonitor) {
+ InteractionJankMonitor interactionJankMonitor,
+ @ShellMainThread Handler handler) {
return new FreeformTaskTransitionHandler(
shellInit,
transitions,
@@ -365,7 +367,8 @@
mainExecutor,
animExecutor,
desktopModeTaskRepository,
- interactionJankMonitor);
+ interactionJankMonitor,
+ handler);
}
@WMSingleton
@@ -382,19 +385,8 @@
@WMSingleton
@Provides
static WindowDecorViewHostSupplier provideWindowDecorViewHostSupplier(
- @NonNull Context context,
- @ShellMainThread @NonNull CoroutineScope mainScope,
- @NonNull ShellInit shellInit) {
- if (DesktopModeStatus.canEnterDesktopMode(context)
- && Flags.enableDesktopWindowingScvhCache()) {
- final int maxPoolSize = DesktopModeStatus.getMaxTaskLimit(context);
- final int preWarmSize = DesktopModeStatus.getWindowDecorPreWarmSize();
- return new PooledWindowDecorViewHostSupplier(
- context, mainScope, shellInit,
- ReusableWindowDecorViewHost.DefaultFactory.INSTANCE, maxPoolSize, preWarmSize);
- } else {
- return new DefaultWindowDecorViewHostSupplier(mainScope);
- }
+ @ShellMainThread @NonNull CoroutineScope mainScope) {
+ return new DefaultWindowDecorViewHostSupplier(mainScope);
}
//
@@ -617,6 +609,7 @@
RecentsTransitionHandler recentsTransitionHandler,
MultiInstanceHelper multiInstanceHelper,
@ShellMainThread ShellExecutor mainExecutor,
+ @ShellMainThread Handler mainHandler,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
Optional<RecentTasksController> recentTasksController,
InteractionJankMonitor interactionJankMonitor) {
@@ -629,7 +622,7 @@
dragToDesktopTransitionHandler, desktopModeTaskRepository,
desktopModeLoggerTransitionObserver, launchAdjacentController,
recentsTransitionHandler, multiInstanceHelper, mainExecutor, desktopTasksLimiter,
- recentTasksController.orElse(null), interactionJankMonitor);
+ recentTasksController.orElse(null), interactionJankMonitor, mainHandler);
}
@WMSingleton
@@ -639,10 +632,11 @@
Transitions transitions,
@DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,
ShellTaskOrganizer shellTaskOrganizer,
- InteractionJankMonitor interactionJankMonitor) {
+ InteractionJankMonitor interactionJankMonitor,
+ @ShellMainThread Handler handler) {
int maxTaskLimit = DesktopModeStatus.getMaxTaskLimit(context);
if (!DesktopModeStatus.canEnterDesktopMode(context)
- || !ENABLE_DESKTOP_WINDOWING_TASK_LIMIT.isEnabled(context)
+ || !ENABLE_DESKTOP_WINDOWING_TASK_LIMIT.isTrue()
|| maxTaskLimit <= 0) {
return Optional.empty();
}
@@ -653,7 +647,8 @@
shellTaskOrganizer,
maxTaskLimit,
interactionJankMonitor,
- context)
+ context,
+ handler)
);
}
@@ -700,9 +695,10 @@
static ExitDesktopTaskTransitionHandler provideExitDesktopTaskTransitionHandler(
Transitions transitions,
Context context,
- InteractionJankMonitor interactionJankMonitor) {
+ InteractionJankMonitor interactionJankMonitor,
+ @ShellMainThread Handler handler) {
return new ExitDesktopTaskTransitionHandler(
- transitions, context, interactionJankMonitor);
+ transitions, context, interactionJankMonitor, handler);
}
@WMSingleton
@@ -787,6 +783,12 @@
@WMSingleton
@Provides
+ static WindowDecorCaptionHandleRepository provideAppHandleRepository() {
+ return new WindowDecorCaptionHandleRepository();
+ }
+
+ @WMSingleton
+ @Provides
static AppHandleEducationController provideAppHandleEducationController(
AppHandleEducationFilter appHandleEducationFilter,
ShellTaskOrganizer shellTaskOrganizer,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
index 037fbb2..3a4764d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
@@ -101,7 +101,8 @@
DisplayInsetsController displayInsetsController,
TabletopModeController pipTabletopController,
Optional<OneHandedController> oneHandedController,
- @ShellMainThread ShellExecutor mainExecutor) {
+ @ShellMainThread ShellExecutor mainExecutor,
+ @ShellMainThread Handler handler) {
return Optional.ofNullable(PipController.create(
context, shellInit, shellCommandHandler, shellController,
displayController, pipAnimationController, pipAppOpsListener,
@@ -111,7 +112,7 @@
pipTransitionState, pipTouchHandler, pipTransitionController,
windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
displayInsetsController, pipTabletopController, oneHandedController,
- mainExecutor));
+ mainExecutor, handler));
}
// Handler is used by Icon.loadDrawableAsync
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 c74f4a7..f3ae3ed 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
@@ -35,6 +35,7 @@
import android.graphics.Rect
import android.graphics.Region
import android.os.Binder
+import android.os.Handler
import android.os.IBinder
import android.os.SystemProperties
import android.util.Size
@@ -83,8 +84,10 @@
import com.android.wm.shell.shared.ShellSharedConstants
import com.android.wm.shell.shared.annotations.ExternalThread
import com.android.wm.shell.shared.annotations.ShellMainThread
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY
+import android.window.flags.DesktopModeFlags
+import android.window.flags.DesktopModeFlags.DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE
+import android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY
+import android.window.flags.DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.DESKTOP_DENSITY_OVERRIDE
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.useDesktopOverrideDensity
@@ -136,7 +139,8 @@
@ShellMainThread private val mainExecutor: ShellExecutor,
private val desktopTasksLimiter: Optional<DesktopTasksLimiter>,
private val recentTasksController: RecentTasksController?,
- private val interactionJankMonitor: InteractionJankMonitor
+ private val interactionJankMonitor: InteractionJankMonitor,
+ @ShellMainThread private val handler: Handler,
) :
RemoteCallable<DesktopTasksController>,
Transitions.TransitionHandler,
@@ -303,13 +307,18 @@
private fun getSplitFocusedTask(task1: RunningTaskInfo, task2: RunningTaskInfo) =
if (task1.taskId == task2.parentTaskId) task2 else task1
- private fun isFreeformDisplay(displayId: Int): Boolean {
+ private fun forceEnterDesktop(displayId: Int): Boolean {
+ if (!DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context)) {
+ return false
+ }
+
val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)
requireNotNull(tdaInfo) {
"This method can only be called with the ID of a display having non-null DisplayArea."
}
val tdaWindowingMode = tdaInfo.configuration.windowConfiguration.windowingMode
- return tdaWindowingMode == WINDOWING_MODE_FREEFORM
+ val isFreeformDisplay = tdaWindowingMode == WINDOWING_MODE_FREEFORM
+ return isFreeformDisplay
}
/** Moves task to desktop mode if task is running, else launches it in desktop mode. */
@@ -357,7 +366,7 @@
wct: WindowContainerTransaction = WindowContainerTransaction(),
transitionSource: DesktopModeTransitionSource,
) {
- if (DesktopModeFlags.MODALS_POLICY.isEnabled(context)
+ if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODALS_POLICY.isTrue()
&& isTopActivityExemptFromDesktopWindowing(context, task)) {
logW("Cannot enter desktop for taskId %d, ineligible top activity found", task.taskId)
return
@@ -387,7 +396,7 @@
taskSurface: SurfaceControl,
) {
logV("startDragToDesktop taskId=%d", taskInfo.taskId)
- interactionJankMonitor.begin(taskSurface, context,
+ interactionJankMonitor.begin(taskSurface, context, handler,
CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD)
dragToDesktopTransitionHandler.startDragToDesktopTransition(
taskInfo.taskId,
@@ -635,7 +644,7 @@
if (taskBoundsBeforeMaximize != null) {
destinationBounds.set(taskBoundsBeforeMaximize)
} else {
- if (DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(context)) {
+ if (ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()) {
destinationBounds.set(calculateInitialBounds(displayLayout, taskInfo))
} else {
destinationBounds.set(getDefaultDesktopTaskBounds(displayLayout))
@@ -789,9 +798,9 @@
dragStartBounds: Rect
) {
releaseVisualIndicator()
- if (!taskInfo.isResizeable && DesktopModeFlags.DISABLE_SNAP_RESIZE.isEnabled(context)) {
+ if (!taskInfo.isResizeable && DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE.isTrue()) {
interactionJankMonitor.begin(
- taskSurface, context, CUJ_DESKTOP_MODE_SNAP_RESIZE, "drag_non_resizable"
+ taskSurface, context, handler, CUJ_DESKTOP_MODE_SNAP_RESIZE, "drag_non_resizable"
)
// reposition non-resizable app back to its original position before being dragged
@@ -804,7 +813,7 @@
)
} else {
interactionJankMonitor.begin(
- taskSurface, context, CUJ_DESKTOP_MODE_SNAP_RESIZE, "drag_resizable"
+ taskSurface, context, handler, CUJ_DESKTOP_MODE_SNAP_RESIZE, "drag_resizable"
)
snapToHalfScreen(taskInfo, taskSurface, currentDragBounds, position)
}
@@ -878,7 +887,8 @@
moveHomeTask(wct, toTop = true)
// Currently, we only handle the desktop on the default display really.
- if (displayId == DEFAULT_DISPLAY && WALLPAPER_ACTIVITY.isEnabled(context)) {
+ if (displayId == DEFAULT_DISPLAY
+ && ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
// Add translucent wallpaper activity to show the wallpaper underneath
addWallpaperActivity(wct)
}
@@ -1077,11 +1087,11 @@
&& taskRepository.isActiveTask(triggerTask.taskId))
private fun isIncompatibleTask(task: TaskInfo) =
- DesktopModeFlags.MODALS_POLICY.isEnabled(context)
+ DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODALS_POLICY.isTrue()
&& isTopActivityExemptFromDesktopWindowing(context, task)
private fun shouldHandleTaskClosing(request: TransitionRequestInfo): Boolean {
- return WALLPAPER_ACTIVITY.isEnabled(context) &&
+ return ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue() &&
TransitionUtil.isClosingType(request.type) &&
request.triggerTask != null
}
@@ -1189,10 +1199,11 @@
val wct = WindowContainerTransaction()
if (!isDesktopModeShowing(task.displayId)) {
logD("Bring desktop tasks to front on transition=taskId=%d", task.taskId)
- // We are outside of desktop mode and already existing desktop task is being launched.
- // We should make this task go to fullscreen instead of freeform. Note that this means
- // any re-launch of a freeform window outside of desktop will be in fullscreen.
- if (taskRepository.isActiveTask(task.taskId)) {
+ if (taskRepository.isActiveTask(task.taskId) && !forceEnterDesktop(task.displayId)) {
+ // We are outside of desktop mode and already existing desktop task is being
+ // launched. We should make this task go to fullscreen instead of freeform. Note
+ // that this means any re-launch of a freeform window outside of desktop will be in
+ // fullscreen as long as default-desktop flag is disabled.
addMoveToFullscreenChanges(wct, task)
return wct
}
@@ -1202,7 +1213,7 @@
}
// If task is already visible, it must have been handled already and added to desktop mode.
// Cascade task only if it's not visible yet.
- if (DesktopModeFlags.CASCADING_WINDOWS.isEnabled(context)
+ if (DesktopModeFlags.ENABLE_CASCADING_WINDOWS.isTrue()
&& !taskRepository.isVisibleTask(task.taskId)) {
val displayLayout = displayController.getDisplayLayout(task.displayId)
if (displayLayout != null) {
@@ -1229,9 +1240,7 @@
transition: IBinder
): WindowContainerTransaction? {
logV("handleFullscreenTaskLaunch")
- val forceEnterDesktop = DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context) &&
- isFreeformDisplay(task.displayId)
- if (isDesktopModeShowing(task.displayId) || forceEnterDesktop) {
+ if (isDesktopModeShowing(task.displayId) || forceEnterDesktop(task.displayId)) {
logD("Switch fullscreen task to freeform on transition: taskId=%d", task.taskId)
return WindowContainerTransaction().also { wct ->
addMoveToDesktopChanges(wct, task)
@@ -1276,7 +1285,7 @@
}
taskRepository.addClosingTask(task.displayId, task.taskId)
// If a CLOSE or TO_BACK is triggered on a desktop task, remove the task.
- if (DesktopModeFlags.BACK_NAVIGATION.isEnabled(context) &&
+ if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue() &&
taskRepository.isVisibleTask(task.taskId)
) {
wct.removeTask(task.token)
@@ -1305,13 +1314,13 @@
} else {
WINDOWING_MODE_FREEFORM
}
- val initialBounds = if (DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(context)) {
+ val initialBounds = if (ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()) {
calculateInitialBounds(displayLayout, taskInfo)
} else {
getDefaultDesktopTaskBounds(displayLayout)
}
- if (DesktopModeFlags.CASCADING_WINDOWS.isEnabled(context)) {
+ if (DesktopModeFlags.ENABLE_CASCADING_WINDOWS.isTrue()) {
cascadeWindow(taskInfo, initialBounds, displayLayout)
}
@@ -1604,7 +1613,7 @@
when (indicatorType) {
IndicatorType.TO_DESKTOP_INDICATOR -> {
// Start a new jank interaction for the drag release to desktop window animation.
- interactionJankMonitor.begin(taskSurface, context,
+ interactionJankMonitor.begin(taskSurface, context, handler,
CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE, "to_desktop")
finalizeDragToDesktop(taskInfo)
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
index 597637d..d84349b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
@@ -18,6 +18,7 @@
import android.app.ActivityManager.RunningTaskInfo
import android.content.Context
+import android.os.Handler
import android.os.IBinder
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_TO_BACK
@@ -29,6 +30,7 @@
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.protolog.ShellProtoLogGroup
+import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions.TransitionObserver
@@ -36,7 +38,7 @@
* Limits the number of tasks shown in Desktop Mode.
*
* This class should only be used if
- * [com.android.wm.shell.shared.desktopmode.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT]
+ * [android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT]
* is enabled and [maxTasksLimit] is strictly greater than 0.
*/
class DesktopTasksLimiter (
@@ -45,7 +47,8 @@
private val shellTaskOrganizer: ShellTaskOrganizer,
private val maxTasksLimit: Int,
private val interactionJankMonitor: InteractionJankMonitor,
- private val context: Context
+ private val context: Context,
+ @ShellMainThread private val handler: Handler,
) {
private val minimizeTransitionObserver = MinimizeTransitionObserver()
@VisibleForTesting
@@ -125,7 +128,7 @@
if (mActiveTaskDetails != null && mActiveTaskDetails.transitionInfo != null) {
// Begin minimize window CUJ instrumentation.
interactionJankMonitor.begin(
- mActiveTaskDetails.transitionInfo?.rootLeash, context,
+ mActiveTaskDetails.transitionInfo?.rootLeash, context, handler,
CUJ_DESKTOP_MODE_MINIMIZE_WINDOW
)
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
index 74e53fa..0841628 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
@@ -25,7 +25,7 @@
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY
+import android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.Transitions
@@ -79,7 +79,7 @@
}
private fun updateWallpaperToken(info: TransitionInfo) {
- if (!WALLPAPER_ACTIVITY.isEnabled(context)) {
+ if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
return
}
info.changes.forEach { change ->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
index dfc5ab3..2bc01b2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
@@ -304,14 +304,14 @@
val leafTaskFilter = TransitionUtil.LeafTaskFilter()
info.changes.withIndex().forEach { (i, change) ->
if (TransitionUtil.isWallpaper(change)) {
- val layer = layers.wallpaperLayers - i
+ val layer = layers.topWallpaperLayer - i
startTransaction.apply {
setLayer(change.leash, layer)
show(change.leash)
}
} else if (isHomeChange(change)) {
state.homeChange = change
- val layer = layers.homeLayers - i
+ val layer = layers.topHomeLayer - i
startTransaction.apply {
setLayer(change.leash, layer)
show(change.leash)
@@ -325,7 +325,7 @@
if (state.cancelState == CancelState.NO_CANCEL) {
// Normal case, split root goes to the bottom behind everything
// else.
- layers.appLayers - i
+ layers.topAppLayer - i
} else {
// Cancel-early case, pretend nothing happened so split root stays
// top.
@@ -357,7 +357,7 @@
state.otherRootChanges.add(change)
val bounds = change.endAbsBounds
startTransaction.apply {
- setLayer(change.leash, layers.appLayers - i)
+ setLayer(change.leash, layers.topAppLayer - i)
setWindowCrop(change.leash, bounds.width(), bounds.height())
show(change.leash)
}
@@ -398,6 +398,7 @@
}
}
}
+ state.surfaceLayers = layers
state.startTransitionFinishCb = finishCallback
state.startTransitionFinishTransaction = finishTransaction
startTransaction.apply()
@@ -522,6 +523,10 @@
startTransaction.show(change.leash)
finishTransaction.show(change.leash)
state.draggedTaskChange = change
+ // Restoring the dragged leash layer as it gets reset in the merge transition
+ state.surfaceLayers?.let {
+ startTransaction.setLayer(change.leash, it.dragLayer)
+ }
}
change.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM -> {
// Other freeform tasks that are being restored go behind the dragged task.
@@ -647,8 +652,15 @@
}
}
- private fun isHomeChange(change: Change): Boolean {
- return change.taskInfo?.activityType == ACTIVITY_TYPE_HOME
+ /** Checks if the change is a home task change */
+ @VisibleForTesting
+ fun isHomeChange(change: Change): Boolean {
+ return change.taskInfo?.let {
+ it.activityType == ACTIVITY_TYPE_HOME &&
+ // Skip translucent wizard task with type home
+ // TODO(b/368334295): Remove when the multiple home changes issue is resolved
+ !(it.isTopActivityTransparent && it.numActivities == 1)
+ } ?: false
}
private fun startCancelAnimation() {
@@ -765,12 +777,18 @@
/**
* Represents the layering (Z order) that will be given to any window based on its type during
- * the "start" transition of the drag-to-desktop transition
+ * the "start" transition of the drag-to-desktop transition.
+ *
+ * @param topAppLayer Used to calculate the app layer z-order = `topAppLayer - changeIndex`.
+ * @param topHomeLayer Used to calculate the home layer z-order = `topHomeLayer - changeIndex`.
+ * @param topWallpaperLayer Used to calculate the wallpaper layer z-order = `topWallpaperLayer -
+ * changeIndex`
+ * @param dragLayer Defines the drag layer z-order
*/
- protected data class DragToDesktopLayers(
- val appLayers: Int,
- val homeLayers: Int,
- val wallpaperLayers: Int,
+ data class DragToDesktopLayers(
+ val topAppLayer: Int,
+ val topHomeLayer: Int,
+ val topWallpaperLayer: Int,
val dragLayer: Int,
)
@@ -790,6 +808,7 @@
abstract var homeChange: Change?
abstract var draggedTaskChange: Change?
abstract var freeformTaskChanges: List<Change>
+ abstract var surfaceLayers: DragToDesktopLayers?
abstract var cancelState: CancelState
abstract var startAborted: Boolean
@@ -803,6 +822,7 @@
override var homeChange: Change? = null,
override var draggedTaskChange: Change? = null,
override var freeformTaskChanges: List<Change> = emptyList(),
+ override var surfaceLayers: DragToDesktopLayers? = null,
override var cancelState: CancelState = CancelState.NO_CANCEL,
override var startAborted: Boolean = false,
var otherRootChanges: MutableList<Change> = mutableListOf()
@@ -818,6 +838,7 @@
override var homeChange: Change? = null,
override var draggedTaskChange: Change? = null,
override var freeformTaskChanges: List<Change> = emptyList(),
+ override var surfaceLayers: DragToDesktopLayers? = null,
override var cancelState: CancelState = CancelState.NO_CANCEL,
override var startAborted: Boolean = false,
var splitRootChange: Change? = null,
@@ -872,9 +893,9 @@
*/
override fun calculateStartDragToDesktopLayers(info: TransitionInfo): DragToDesktopLayers =
DragToDesktopLayers(
- appLayers = info.changes.size,
- homeLayers = info.changes.size * 2,
- wallpaperLayers = info.changes.size * 3,
+ topAppLayer = info.changes.size,
+ topHomeLayer = info.changes.size * 2,
+ topWallpaperLayer = info.changes.size * 3,
dragLayer = info.changes.size * 3
)
}
@@ -914,9 +935,9 @@
*/
override fun calculateStartDragToDesktopLayers(info: TransitionInfo): DragToDesktopLayers =
DragToDesktopLayers(
- appLayers = -1,
- homeLayers = info.changes.size - 1,
- wallpaperLayers = info.changes.size * 2 - 1,
+ topAppLayer = -1,
+ topHomeLayer = info.changes.size - 1,
+ topWallpaperLayer = info.changes.size * 2 - 1,
dragLayer = info.changes.size * 2
)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
index e87be52..dedd44f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
@@ -29,6 +29,7 @@
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.Handler;
import android.os.IBinder;
import android.util.DisplayMetrics;
import android.view.SurfaceControl;
@@ -44,6 +45,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.Cuj;
import com.android.internal.jank.InteractionJankMonitor;
+import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.transition.Transitions;
@@ -63,6 +65,8 @@
private final Context mContext;
private final Transitions mTransitions;
private final InteractionJankMonitor mInteractionJankMonitor;
+ @ShellMainThread
+ private final Handler mHandler;
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback;
private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
@@ -71,20 +75,24 @@
public ExitDesktopTaskTransitionHandler(
Transitions transitions,
Context context,
- InteractionJankMonitor interactionJankMonitor
- ) {
- this(transitions, SurfaceControl.Transaction::new, context, interactionJankMonitor);
+ InteractionJankMonitor interactionJankMonitor,
+ @ShellMainThread Handler handler
+ ) {
+ this(transitions, SurfaceControl.Transaction::new, context, interactionJankMonitor,
+ handler);
}
private ExitDesktopTaskTransitionHandler(
Transitions transitions,
Supplier<SurfaceControl.Transaction> supplier,
Context context,
- InteractionJankMonitor interactionJankMonitor) {
+ InteractionJankMonitor interactionJankMonitor,
+ @ShellMainThread Handler handler) {
mTransitions = transitions;
mTransactionSupplier = supplier;
mContext = context;
mInteractionJankMonitor = interactionJankMonitor;
+ mHandler = handler;
}
/**
@@ -154,7 +162,7 @@
final SurfaceControl sc = change.getLeash();
final Rect endBounds = change.getEndAbsBounds();
mInteractionJankMonitor
- .begin(sc, mContext, Cuj.CUJ_DESKTOP_MODE_EXIT_MODE);
+ .begin(sc, mContext, mHandler, Cuj.CUJ_DESKTOP_MODE_EXIT_MODE);
// Hide the first (fullscreen) frame because the animation will start from the freeform
// size.
startT.hide(sc)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/WindowDecorCaptionHandleRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/WindowDecorCaptionHandleRepository.kt
new file mode 100644
index 0000000..7ae5370
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/WindowDecorCaptionHandleRepository.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.graphics.Rect
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+/** Repository to observe caption state. */
+class WindowDecorCaptionHandleRepository {
+ private val _captionStateFlow = MutableStateFlow<CaptionState>(CaptionState.NoCaption)
+ /** Observer for app handle state changes. */
+ val captionStateFlow: StateFlow<CaptionState> = _captionStateFlow
+
+ /** Notifies [captionStateFlow] if there is a change to caption state. */
+ fun notifyCaptionChanged(captionState: CaptionState) {
+ _captionStateFlow.value = captionState
+ }
+}
+
+/**
+ * Represents the current status of the caption.
+ *
+ * It can be one of three options:
+ * * [AppHandle]: Indicating that there is at least one visible app handle on the screen.
+ * * [AppHeader]: Indicating that there is at least one visible app chip on the screen.
+ * * [NoCaption]: Signifying that no caption handle is currently visible on the device.
+ */
+sealed class CaptionState {
+ data class AppHandle(
+ val runningTaskInfo: RunningTaskInfo,
+ val isHandleMenuExpanded: Boolean,
+ val globalAppHandleBounds: Rect
+ ) : CaptionState()
+
+ data class AppHeader(
+ val runningTaskInfo: RunningTaskInfo,
+ val isHeaderMenuExpanded: Boolean,
+ val globalAppChipBounds: Rect
+ ) : CaptionState()
+
+ data object NoCaption : CaptionState()
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
index 832e2d2..517e209 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
@@ -28,6 +28,7 @@
import android.app.WindowConfiguration;
import android.content.Context;
import android.graphics.Rect;
+import android.os.Handler;
import android.os.IBinder;
import android.util.ArrayMap;
import android.view.SurfaceControl;
@@ -43,6 +44,7 @@
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
+import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
@@ -65,6 +67,8 @@
private final InteractionJankMonitor mInteractionJankMonitor;
private final ShellExecutor mMainExecutor;
private final ShellExecutor mAnimExecutor;
+ @ShellMainThread
+ private final Handler mHandler;
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
@@ -79,7 +83,8 @@
ShellExecutor mainExecutor,
ShellExecutor animExecutor,
DesktopModeTaskRepository desktopModeTaskRepository,
- InteractionJankMonitor interactionJankMonitor) {
+ InteractionJankMonitor interactionJankMonitor,
+ @ShellMainThread Handler handler) {
mTransitions = transitions;
mContext = context;
mWindowDecorViewModel = windowDecorViewModel;
@@ -88,6 +93,7 @@
mInteractionJankMonitor = interactionJankMonitor;
mMainExecutor = mainExecutor;
mAnimExecutor = animExecutor;
+ mHandler = handler;
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
shellInit.addInitCallback(this::onInit, this);
}
@@ -267,7 +273,7 @@
change.getTaskInfo().displayId) == 1) {
// Starting the jank trace if closing the last window in desktop mode.
mInteractionJankMonitor.begin(
- sc, mContext, CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE);
+ sc, mContext, mHandler, CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE);
}
animator.addListener(
new AnimatorListenerAdapter() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 1827923..15472eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -55,6 +55,7 @@
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.shared.annotations.ExternalThread;
+import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.sysui.ConfigurationChangeListener;
import com.android.wm.shell.sysui.KeyguardChangeListener;
import com.android.wm.shell.sysui.ShellCommandHandler;
@@ -203,7 +204,7 @@
DisplayController displayController, DisplayLayout displayLayout,
TaskStackListenerImpl taskStackListener,
InteractionJankMonitor jankMonitor, UiEventLogger uiEventLogger,
- ShellExecutor mainExecutor, Handler mainHandler) {
+ ShellExecutor mainExecutor, @ShellMainThread Handler mainHandler) {
OneHandedSettingsUtil settingsUtil = new OneHandedSettingsUtil();
OneHandedAccessibilityUtil accessibilityUtil = new OneHandedAccessibilityUtil(context);
OneHandedTimeoutHandler timeoutHandler = new OneHandedTimeoutHandler(mainExecutor);
@@ -217,7 +218,7 @@
mainExecutor);
OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer(
context, displayLayout, settingsUtil, animationController, tutorialHandler,
- jankMonitor, mainExecutor);
+ jankMonitor, mainExecutor, mainHandler);
OneHandedUiEventLogger oneHandedUiEventsLogger = new OneHandedUiEventLogger(uiEventLogger);
return new OneHandedController(context, shellInit, shellCommandHandler, shellController,
displayController, organizer, touchHandler, tutorialHandler, settingsUtil,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index d157ca8..95e633d0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.graphics.Rect;
+import android.os.Handler;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -42,6 +43,7 @@
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.shared.annotations.ShellMainThread;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -70,6 +72,8 @@
private final OneHandedSettingsUtil mOneHandedSettingsUtil;
private final InteractionJankMonitor mJankMonitor;
private final Context mContext;
+ @ShellMainThread
+ private final Handler mHandler;
private boolean mIsReady;
private float mLastVisualOffset = 0;
@@ -136,9 +140,11 @@
OneHandedAnimationController animationController,
OneHandedTutorialHandler tutorialHandler,
InteractionJankMonitor jankMonitor,
- ShellExecutor mainExecutor) {
+ ShellExecutor mainExecutor,
+ @ShellMainThread Handler handler) {
super(mainExecutor);
mContext = context;
+ mHandler = handler;
setDisplayLayout(displayLayout);
mOneHandedSettingsUtil = oneHandedSettingsUtil;
mAnimationController = animationController;
@@ -333,7 +339,7 @@
getDisplayAreaTokenMap().entrySet().iterator().next();
final InteractionJankMonitor.Configuration.Builder builder =
InteractionJankMonitor.Configuration.Builder.withSurface(
- cujType, mContext, firstEntry.getValue());
+ cujType, mContext, firstEntry.getValue(), mHandler);
if (!TextUtils.isEmpty(tag)) {
builder.setTag(tag);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index deb7691..af68442 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -44,6 +44,7 @@
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.util.Pair;
@@ -93,6 +94,7 @@
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipTransitionState;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.sysui.ConfigurationChangeListener;
import com.android.wm.shell.sysui.KeyguardChangeListener;
import com.android.wm.shell.sysui.ShellCommandHandler;
@@ -146,6 +148,8 @@
private Optional<OneHandedController> mOneHandedController;
private final ShellCommandHandler mShellCommandHandler;
private final ShellController mShellController;
+ @ShellMainThread
+ private final Handler mHandler;
protected final PipImpl mImpl;
private final Rect mTmpInsetBounds = new Rect();
@@ -405,7 +409,8 @@
DisplayInsetsController displayInsetsController,
TabletopModeController pipTabletopController,
Optional<OneHandedController> oneHandedController,
- ShellExecutor mainExecutor) {
+ ShellExecutor mainExecutor,
+ Handler handler) {
if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: Device doesn't support Pip feature", TAG);
@@ -418,7 +423,8 @@
pipDisplayLayoutState, pipMotionHelper, pipMediaController, phonePipMenuController,
pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController,
windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
- displayInsetsController, pipTabletopController, oneHandedController, mainExecutor)
+ displayInsetsController, pipTabletopController, oneHandedController, mainExecutor,
+ handler)
.mImpl;
}
@@ -446,11 +452,13 @@
DisplayInsetsController displayInsetsController,
TabletopModeController tabletopModeController,
Optional<OneHandedController> oneHandedController,
- ShellExecutor mainExecutor
+ ShellExecutor mainExecutor,
+ @ShellMainThread Handler handler
) {
mContext = context;
mShellCommandHandler = shellCommandHandler;
mShellController = shellController;
+ mHandler = handler;
mImpl = new PipImpl();
mWindowManagerShellWrapper = windowManagerShellWrapper;
mDisplayController = displayController;
@@ -1047,7 +1055,8 @@
// Begin InteractionJankMonitor with PIP transition CUJs
final InteractionJankMonitor.Configuration.Builder builder =
InteractionJankMonitor.Configuration.Builder.withSurface(
- CUJ_PIP_TRANSITION, mContext, mPipTaskOrganizer.getSurfaceControl())
+ CUJ_PIP_TRANSITION, mContext, mPipTaskOrganizer.getSurfaceControl(),
+ mHandler)
.setTag(getTransitionTag(direction))
.setTimeout(2000);
InteractionJankMonitor.getInstance().begin(builder);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index 82fbfad..5710af6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -204,8 +204,7 @@
@NonNull
@Override
public Rect getFloatingBoundsOnScreen() {
- return !mPipBoundsState.getMotionBoundsState().getAnimatingToBounds().isEmpty()
- ? mPipBoundsState.getMotionBoundsState().getAnimatingToBounds() : getBounds();
+ return getBounds();
}
@NonNull
@@ -616,7 +615,7 @@
cancelPhysicsAnimation();
}
- setAnimatingToBounds(new Rect(
+ mPipBoundsState.getMotionBoundsState().setAnimatingToBounds(new Rect(
(int) toX,
(int) toY,
(int) toX + getBounds().width(),
@@ -660,6 +659,9 @@
// All motion operations have actually finished.
mPipBoundsState.setBounds(
mPipBoundsState.getMotionBoundsState().getBoundsInMotion());
+ // Notifies the floating coordinator that we moved, so we return these bounds from
+ // {@link FloatingContentCoordinator.FloatingContent#getFloatingBoundsOnScreen()}.
+ mFloatingContentCoordinator.onContentMoved(this);
mPipBoundsState.getMotionBoundsState().onAllAnimationsEnded();
if (!mDismissalPending) {
// do not schedule resize if PiP is dismissing, which may cause app re-open to
@@ -674,16 +676,6 @@
}
/**
- * Notifies the floating coordinator that we're moving, and sets the animating to bounds so
- * we return these bounds from
- * {@link FloatingContentCoordinator.FloatingContent#getFloatingBoundsOnScreen()}.
- */
- private void setAnimatingToBounds(Rect bounds) {
- mPipBoundsState.getMotionBoundsState().setAnimatingToBounds(bounds);
- mFloatingContentCoordinator.onContentMoved(this);
- }
-
- /**
* Directly resizes the PiP to the given {@param bounds}.
*/
private void resizePipUnchecked(Rect toBounds) {
@@ -712,7 +704,7 @@
// This is so all the proper callbacks are performed.
mPipTaskOrganizer.scheduleAnimateResizePip(toBounds, duration,
TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND, null /* updateBoundsCallback */);
- setAnimatingToBounds(toBounds);
+ mPipBoundsState.getMotionBoundsState().setAnimatingToBounds(toBounds);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index a6e25a9..03ff1aa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -38,6 +38,7 @@
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.window.WindowContainerToken;
+import android.window.flags.DesktopModeFlags;
import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
@@ -53,11 +54,9 @@
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
-import com.android.wm.shell.recents.IRecentsAnimationRunner;
import com.android.wm.shell.shared.GroupedRecentTaskInfo;
import com.android.wm.shell.shared.annotations.ExternalThread;
import com.android.wm.shell.shared.annotations.ShellMainThread;
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.shared.split.SplitBounds;
import com.android.wm.shell.sysui.ShellCommandHandler;
@@ -356,7 +355,7 @@
private void notifyTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
if (mListener == null
- || !DesktopModeFlags.TASK_STACK_OBSERVER_IN_SHELL.isEnabled(mContext)
+ || !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue()
|| taskInfo.realActivity == null) {
return;
}
@@ -370,7 +369,7 @@
private boolean shouldEnableRunningTasksForDesktopMode() {
return mPcFeatureEnabled
|| (DesktopModeStatus.canEnterDesktopMode(mContext)
- && DesktopModeFlags.TASKBAR_RUNNING_APPS.isEnabled(mContext));
+ && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS.isTrue());
}
@VisibleForTesting
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
index 3a0bdb9..e5bfccf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
@@ -18,14 +18,13 @@
import android.app.ActivityManager.RunningTaskInfo
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
-import android.content.Context
import android.os.IBinder
import android.util.ArrayMap
import android.view.SurfaceControl
import android.view.WindowManager
import android.window.TransitionInfo
import com.android.wm.shell.shared.TransitionUtil
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags
+import android.window.flags.DesktopModeFlags
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.Transitions
import dagger.Lazy
@@ -38,7 +37,6 @@
* TODO(346588978) Move split/pip signals here as well so that launcher don't need to handle it
*/
class TaskStackTransitionObserver(
- private val context: Context,
private val transitions: Lazy<Transitions>,
shellInit: ShellInit
) : Transitions.TransitionObserver {
@@ -64,7 +62,7 @@
startTransaction: SurfaceControl.Transaction,
finishTransaction: SurfaceControl.Transaction
) {
- if (DesktopModeFlags.TASK_STACK_OBSERVER_IN_SHELL.isEnabled(context)) {
+ if (DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue) {
val taskInfoList = mutableListOf<RunningTaskInfo>()
val transitionTypeList = mutableListOf<Int>()
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 4ba84ee..e8eb10c 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
@@ -1654,7 +1654,7 @@
mSplitLayout = new SplitLayout(TAG + "SplitDivider", mContext,
mRootTaskInfo.configuration, this, mParentContainerCallbacks,
mDisplayController, mDisplayImeController, mTaskOrganizer,
- PARALLAX_ALIGN_CENTER /* parallaxType */);
+ PARALLAX_ALIGN_CENTER /* parallaxType */, mMainHandler);
mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSplitLayout);
}
@@ -2456,6 +2456,7 @@
final StageChangeRecord record = new StageChangeRecord();
final int transitType = info.getType();
TransitionInfo.Change pipChange = null;
+ int closingSplitTaskId = -1;
for (int iC = 0; iC < info.getChanges().size(); ++iC) {
final TransitionInfo.Change change = info.getChanges().get(iC);
if (change.getMode() == TRANSIT_CHANGE
@@ -2516,21 +2517,31 @@
+ " with " + taskInfo.taskId + " before startAnimation().");
}
}
+ if (isClosingType(change.getMode()) &&
+ getStageOfTask(change.getTaskInfo().taskId) != STAGE_TYPE_UNDEFINED) {
+ // If either one of the 2 stages is closing we're assuming we'll break split
+ closingSplitTaskId = change.getTaskInfo().taskId;
+ }
}
if (pipChange != null) {
TransitionInfo.Change pipReplacingChange = getPipReplacingChange(info, pipChange,
mMainStage.mRootTaskInfo.taskId, mSideStage.mRootTaskInfo.taskId,
getSplitItemStage(pipChange.getLastParent()));
- if (pipReplacingChange != null) {
+ boolean keepSplitWithPip = pipReplacingChange != null && closingSplitTaskId == -1;
+ if (keepSplitWithPip) {
// Set an enter transition for when startAnimation gets called again
mSplitTransitions.setEnterTransition(transition, /*remoteTransition*/ null,
TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, /*resizeAnim*/ false);
+ } else {
+ int finalClosingTaskId = closingSplitTaskId;
+ mRecentTasks.ifPresent(recentTasks ->
+ recentTasks.removeSplitPair(finalClosingTaskId));
+ logExit(EXIT_REASON_FULLSCREEN_REQUEST);
}
mMixedHandler.animatePendingEnterPipFromSplit(transition, info,
- startTransaction, finishTransaction, finishCallback,
- pipReplacingChange != null);
+ startTransaction, finishTransaction, finishCallback, keepSplitWithPip);
notifySplitAnimationFinished();
return true;
}
@@ -2821,8 +2832,12 @@
}
callbackWct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token, false);
mWindowDecorViewModel.ifPresent(viewModel -> {
- viewModel.onTaskInfoChanged(finalMainChild.getTaskInfo());
- viewModel.onTaskInfoChanged(finalSideChild.getTaskInfo());
+ if (finalMainChild != null) {
+ viewModel.onTaskInfoChanged(finalMainChild.getTaskInfo());
+ }
+ if (finalSideChild != null) {
+ viewModel.onTaskInfoChanged(finalSideChild.getTaskInfo());
+ }
});
mPausingTasks.clear();
});
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 0151395..431461a 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
@@ -44,6 +44,7 @@
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.View;
+import android.view.ViewConfiguration;
import android.window.DisplayAreaInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -310,7 +311,6 @@
new CaptionTouchEventListener(taskInfo, taskPositioner);
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
windowDecoration.setDragPositioningCallback(taskPositioner);
- windowDecoration.setDragDetector(touchEventListener.mDragDetector);
windowDecoration.setTaskDragResizer(taskPositioner);
windowDecoration.relayout(taskInfo, startT, finishT,
false /* applyStartTransactionOnDraw */, false /* setTaskCropAndPosition */);
@@ -334,7 +334,8 @@
mTaskId = taskInfo.taskId;
mTaskToken = taskInfo.token;
mDragPositioningCallback = dragPositioningCallback;
- mDragDetector = new DragDetector(this);
+ mDragDetector = new DragDetector(this, 0 /* holdToDragMinDurationMs */,
+ ViewConfiguration.get(mContext).getScaledTouchSlop());
mDisplayId = taskInfo.displayId;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 0caa8e9..d0eba23 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -16,6 +16,8 @@
package com.android.wm.shell.windowdecor;
+import static android.window.flags.DesktopModeFlags.ENABLE_WINDOWING_SCALED_RESIZING;
+
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getFineResizeCornerSize;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getLargeResizeCornerSize;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getResizeEdgeHandleSize;
@@ -55,7 +57,6 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
@@ -74,7 +75,6 @@
private View.OnTouchListener mOnCaptionTouchListener;
private DragPositioningCallback mDragPositioningCallback;
private DragResizeInputListener mDragResizeListener;
- private DragDetector mDragDetector;
private RelayoutParams mRelayoutParams = new RelayoutParams();
private final RelayoutResult<WindowDecorLinearLayout> mResult =
@@ -176,12 +176,6 @@
return stableBounds.bottom - requiredEmptySpace;
}
-
- void setDragDetector(DragDetector dragDetector) {
- mDragDetector = dragDetector;
- mDragDetector.setTouchSlop(ViewConfiguration.get(mContext).getScaledTouchSlop());
- }
-
@Override
void relayout(RunningTaskInfo taskInfo) {
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
@@ -241,7 +235,7 @@
boolean applyStartTransactionOnDraw, boolean setTaskCropAndPosition) {
final boolean isFreeform =
taskInfo.getWindowingMode() == WindowConfiguration.WINDOWING_MODE_FREEFORM;
- final boolean isDragResizeable = DesktopModeFlags.SCALED_RESIZING.isEnabled(mContext)
+ final boolean isDragResizeable = ENABLE_WINDOWING_SCALED_RESIZING.isTrue()
? isFreeform : isFreeform && taskInfo.isResizeable;
final WindowDecorLinearLayout oldRootView = mResult.mRootView;
@@ -288,11 +282,10 @@
final int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext())
.getScaledTouchSlop();
- mDragDetector.setTouchSlop(touchSlop);
final Resources res = mResult.mRootView.getResources();
mDragResizeListener.setGeometry(new DragResizeWindowGeometry(0 /* taskCornerRadius */,
- new Size(mResult.mWidth, mResult.mHeight), getResizeEdgeHandleSize(mContext, res),
+ new Size(mResult.mWidth, mResult.mHeight), getResizeEdgeHandleSize(res),
getResizeHandleEdgeInset(res), getFineResizeCornerSize(res),
getLargeResizeCornerSize(res)), touchSlop);
}
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 b14283f..c59d929 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
@@ -79,10 +79,12 @@
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.View;
+import android.view.ViewConfiguration;
import android.widget.Toast;
import android.window.TaskSnapshot;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
+import android.window.flags.DesktopModeFlags;
import androidx.annotation.Nullable;
@@ -109,9 +111,10 @@
import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition;
import com.android.wm.shell.desktopmode.DesktopTasksLimiter;
import com.android.wm.shell.desktopmode.DesktopWallpaperActivity;
+import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
+import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
@@ -154,7 +157,7 @@
private final ShellTaskOrganizer mTaskOrganizer;
private final ShellController mShellController;
private final Context mContext;
- private final Handler mMainHandler;
+ private final @ShellMainThread Handler mMainHandler;
private final @ShellBackgroundThread ShellExecutor mBgExecutor;
private final Choreographer mMainChoreographer;
private final DisplayController mDisplayController;
@@ -163,7 +166,9 @@
private final InputManager mInputManager;
private final InteractionJankMonitor mInteractionJankMonitor;
private final MultiInstanceHelper mMultiInstanceHelper;
+ private final WindowDecorCaptionHandleRepository mWindowDecorCaptionHandleRepository;
private final Optional<DesktopTasksLimiter> mDesktopTasksLimiter;
+ private final AppHeaderViewHolder.Factory mAppHeaderViewHolderFactory;
private final WindowDecorViewHostSupplier mWindowDecorViewHostSupplier;
private boolean mTransitionDragActive;
@@ -214,7 +219,7 @@
public DesktopModeWindowDecorViewModel(
Context context,
ShellExecutor shellExecutor,
- Handler mainHandler,
+ @ShellMainThread Handler mainHandler,
Choreographer mainChoreographer,
@ShellBackgroundThread ShellExecutor bgExecutor,
ShellInit shellInit,
@@ -233,6 +238,7 @@
AssistContentRequester assistContentRequester,
MultiInstanceHelper multiInstanceHelper,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
+ WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
this(
@@ -258,10 +264,12 @@
new DesktopModeWindowDecoration.Factory(),
new InputMonitorFactory(),
SurfaceControl.Transaction::new,
+ new AppHeaderViewHolder.Factory(),
rootTaskDisplayAreaOrganizer,
new SparseArray<>(),
interactionJankMonitor,
desktopTasksLimiter,
+ windowDecorCaptionHandleRepository,
activityOrientationChangeHandler,
new TaskPositionerFactory());
}
@@ -270,7 +278,7 @@
DesktopModeWindowDecorViewModel(
Context context,
ShellExecutor shellExecutor,
- Handler mainHandler,
+ @ShellMainThread Handler mainHandler,
Choreographer mainChoreographer,
@ShellBackgroundThread ShellExecutor bgExecutor,
ShellInit shellInit,
@@ -290,10 +298,12 @@
DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory,
InputMonitorFactory inputMonitorFactory,
Supplier<SurfaceControl.Transaction> transactionFactory,
+ AppHeaderViewHolder.Factory appHeaderViewHolderFactory,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
SparseArray<DesktopModeWindowDecoration> windowDecorByTaskId,
InteractionJankMonitor interactionJankMonitor,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
+ WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
TaskPositionerFactory taskPositionerFactory) {
mContext = context;
@@ -316,6 +326,7 @@
mDesktopModeWindowDecorFactory = desktopModeWindowDecorFactory;
mInputMonitorFactory = inputMonitorFactory;
mTransactionFactory = transactionFactory;
+ mAppHeaderViewHolderFactory = appHeaderViewHolderFactory;
mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
mGenericLinksParser = genericLinksParser;
mInputManager = mContext.getSystemService(InputManager.class);
@@ -324,6 +335,7 @@
com.android.internal.R.string.config_systemUi);
mInteractionJankMonitor = interactionJankMonitor;
mDesktopTasksLimiter = desktopTasksLimiter;
+ mWindowDecorCaptionHandleRepository = windowDecorCaptionHandleRepository;
mActivityOrientationChangeHandler = activityOrientationChangeHandler;
mAssistContentRequester = assistContentRequester;
mOnDisplayChangingListener = (displayId, fromRotation, toRotation, displayAreaInfo, t) -> {
@@ -495,7 +507,8 @@
return;
}
mInteractionJankMonitor.begin(
- decoration.mTaskSurface, mContext, Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, source);
+ decoration.mTaskSurface, mContext, mMainHandler,
+ Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, source);
mDesktopTasksController.toggleDesktopTaskSize(decoration.mTaskInfo);
decoration.closeHandleMenu();
decoration.closeMaximizeMenu();
@@ -508,11 +521,11 @@
}
if (!decoration.mTaskInfo.isResizeable
- && DesktopModeFlags.DISABLE_SNAP_RESIZE.isEnabled(mContext)) {
+ && DesktopModeFlags.DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE.isTrue()) {
Toast.makeText(mContext,
R.string.desktop_mode_non_resizable_snap_text, Toast.LENGTH_SHORT).show();
} else {
- mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext,
+ mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, mMainHandler,
Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE, "maximize_menu_resizable");
mDesktopTasksController.snapToHalfScreen(
decoration.mTaskInfo,
@@ -548,7 +561,7 @@
return;
}
final WindowContainerTransaction wct = new WindowContainerTransaction();
- mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext,
+ mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, mMainHandler,
CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU);
// App sometimes draws before the insets from WindowDecoration#relayout have
// been added, so they must be added here
@@ -651,11 +664,14 @@
private class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener
implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener,
View.OnGenericMotionListener, DragDetector.MotionEventHandler {
+ private static final long APP_HANDLE_HOLD_TO_DRAG_DURATION_MS = 100;
+ private static final long APP_HEADER_HOLD_TO_DRAG_DURATION_MS = 0;
private final int mTaskId;
private final WindowContainerToken mTaskToken;
private final DragPositioningCallback mDragPositioningCallback;
- private final DragDetector mDragDetector;
+ private final DragDetector mHandleDragDetector;
+ private final DragDetector mHeaderDragDetector;
private final GestureDetector mGestureDetector;
private final int mDisplayId;
private final Rect mOnDragStartInitialBounds = new Rect();
@@ -677,7 +693,13 @@
mTaskId = taskInfo.taskId;
mTaskToken = taskInfo.token;
mDragPositioningCallback = dragPositioningCallback;
- mDragDetector = new DragDetector(this);
+ final int touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ final long appHandleHoldToDragDuration = Flags.enableHoldToDragAppHandle()
+ ? APP_HANDLE_HOLD_TO_DRAG_DURATION_MS : 0;
+ mHandleDragDetector = new DragDetector(this, appHandleHoldToDragDuration,
+ touchSlop);
+ mHeaderDragDetector = new DragDetector(this, APP_HEADER_HOLD_TO_DRAG_DURATION_MS,
+ touchSlop);
mGestureDetector = new GestureDetector(mContext, this);
mDisplayId = taskInfo.displayId;
}
@@ -736,7 +758,7 @@
&& id != R.id.maximize_window && id != R.id.minimize_window) {
return false;
}
-
+ final boolean isAppHandle = !getTaskInfo().isFreeform();
final int actionMasked = e.getActionMasked();
final boolean isDown = actionMasked == MotionEvent.ACTION_DOWN;
final boolean isUpOrCancel = actionMasked == MotionEvent.ACTION_CANCEL
@@ -785,7 +807,11 @@
// Gesture is finished, reset state.
mShouldPilferCaptionEvents = false;
}
- return mDragDetector.onMotionEvent(v, e);
+ if (isAppHandle) {
+ return mHandleDragDetector.onMotionEvent(v, e);
+ } else {
+ return mHeaderDragDetector.onMotionEvent(v, e);
+ }
}
@Override
@@ -853,6 +879,12 @@
}
}
+ @NonNull
+ private RunningTaskInfo getTaskInfo() {
+ final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
+ return decoration.mTaskInfo;
+ }
+
private boolean handleNonFreeformMotionEvent(DesktopModeWindowDecoration decoration,
View v, MotionEvent e) {
final int id = v.getId();
@@ -860,6 +892,15 @@
handleCaptionThroughStatusBar(e, decoration);
final boolean wasDragging = mIsDragging;
updateDragStatus(e.getActionMasked());
+ final boolean upOrCancel = e.getActionMasked() == ACTION_UP
+ || e.getActionMasked() == ACTION_CANCEL;
+ if (wasDragging && upOrCancel) {
+ // When finishing a drag the event will be consumed, which means the pressed
+ // state of the App Handle must be manually reset to scale its drawable back to
+ // its original shape. This is necessary for drag gestures of the Handle that
+ // result in a cancellation (dragging back to the top).
+ v.setPressed(false);
+ }
// Only prevent onClick from receiving this event if it's a drag.
return wasDragging;
}
@@ -1180,8 +1221,10 @@
: SPLIT_POSITION_TOP_OR_LEFT;
final RunningTaskInfo oppositeTaskInfo =
mSplitScreenController.getTaskInfo(oppositePosition);
- mWindowDecorByTaskId.get(oppositeTaskInfo.taskId)
- .disposeStatusBarInputLayer();
+ if (oppositeTaskInfo != null) {
+ mWindowDecorByTaskId.get(oppositeTaskInfo.taskId)
+ .disposeStatusBarInputLayer();
+ }
}
}
mMoveToDesktopAnimator = null;
@@ -1330,7 +1373,7 @@
&& mSplitScreenController.isTaskRootOrStageRoot(taskInfo.taskId)) {
return false;
}
- if (DesktopModeFlags.MODALS_POLICY.isEnabled(mContext)
+ if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODALS_POLICY.isTrue()
&& isTopActivityExemptFromDesktopWindowing(mContext, taskInfo)) {
return false;
}
@@ -1364,10 +1407,12 @@
mBgExecutor,
mMainChoreographer,
mSyncQueue,
+ mAppHeaderViewHolderFactory,
mRootTaskDisplayAreaOrganizer,
mGenericLinksParser,
mAssistContentRequester,
mMultiInstanceHelper,
+ mWindowDecorCaptionHandleRepository,
mWindowDecorViewHostSupplier);
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
@@ -1378,7 +1423,8 @@
mDragStartListener,
mTransitions,
mInteractionJankMonitor,
- mTransactionFactory);
+ mTransactionFactory,
+ mMainHandler);
windowDecoration.setTaskDragResizer(taskPositioner);
final DesktopModeTouchEventListener touchEventListener =
@@ -1421,7 +1467,6 @@
touchEventListener, touchEventListener, touchEventListener, touchEventListener);
windowDecoration.setExclusionRegionListener(mExclusionRegionListener);
windowDecoration.setDragPositioningCallback(taskPositioner);
- windowDecoration.setDragDetector(touchEventListener.mDragDetector);
windowDecoration.relayout(taskInfo, startT, finishT,
false /* applyStartTransactionOnDraw */, false /* shouldSetTaskPositionAndCrop */);
if (!Flags.enableHandleInputFix()) {
@@ -1602,7 +1647,8 @@
DragPositioningCallbackUtility.DragStartListener dragStartListener,
Transitions transitions,
InteractionJankMonitor interactionJankMonitor,
- Supplier<SurfaceControl.Transaction> transactionFactory) {
+ Supplier<SurfaceControl.Transaction> transactionFactory,
+ Handler handler) {
final TaskPositioner taskPositioner = DesktopModeStatus.isVeiledResizeEnabled()
? new VeiledResizeTaskPositioner(
taskOrganizer,
@@ -1610,7 +1656,8 @@
displayController,
dragStartListener,
transitions,
- interactionJankMonitor)
+ interactionJankMonitor,
+ handler)
: new FluidResizeTaskPositioner(
taskOrganizer,
transitions,
@@ -1619,7 +1666,7 @@
dragStartListener,
transactionFactory);
- if (DesktopModeFlags.SCALED_RESIZING.isEnabled(windowDecoration.mContext)) {
+ if (DesktopModeFlags.ENABLE_WINDOWING_SCALED_RESIZING.isTrue()) {
return new FixedAspectRatioTaskPositionerDecorator(windowDecoration,
taskPositioner);
}
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 b1fc55f..1537a1e 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
@@ -24,8 +24,11 @@
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
+import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
+import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
import static com.android.launcher3.icons.BaseIconFactory.MODE_DEFAULT;
+import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopMode;
import static com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getFineResizeCornerSize;
@@ -66,6 +69,7 @@
import android.widget.ImageButton;
import android.window.TaskSnapshot;
import android.window.WindowContainerTransaction;
+import android.window.flags.DesktopModeFlags;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.ScreenDecorationsUtils;
@@ -83,8 +87,9 @@
import com.android.wm.shell.common.MultiInstanceHelper;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.desktopmode.CaptionState;
+import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.shared.desktopmode.ManageWindowsViewContainer;
@@ -139,7 +144,6 @@
private Function0<Unit> mOnManageWindowsClickListener;
private DragPositioningCallback mDragPositioningCallback;
private DragResizeInputListener mDragResizeListener;
- private DragDetector mDragDetector;
private RelayoutParams mRelayoutParams = new RelayoutParams();
private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult =
new WindowDecoration.RelayoutResult<>();
@@ -163,6 +167,7 @@
private ExclusionRegionListener mExclusionRegionListener;
+ private final AppHeaderViewHolder.Factory mAppHeaderViewHolderFactory;
private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
private final MaximizeMenuFactory mMaximizeMenuFactory;
private final HandleMenuFactory mHandleMenuFactory;
@@ -179,6 +184,7 @@
private final Runnable mCloseMaximizeWindowRunnable = this::closeMaximizeMenu;
private final Runnable mCapturedLinkExpiredRunnable = this::onCapturedLinkExpired;
private final MultiInstanceHelper mMultiInstanceHelper;
+ private final WindowDecorCaptionHandleRepository mWindowDecorCaptionHandleRepository;
DesktopModeWindowDecoration(
Context context,
@@ -192,20 +198,24 @@
@ShellBackgroundThread ShellExecutor bgExecutor,
Choreographer choreographer,
SyncTransactionQueue syncQueue,
+ AppHeaderViewHolder.Factory appHeaderViewHolderFactory,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
AppToWebGenericLinksParser genericLinksParser,
AssistContentRequester assistContentRequester,
MultiInstanceHelper multiInstanceHelper,
+ WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
this (context, userContext, displayController, splitScreenController, taskOrganizer,
taskInfo, taskSurface, handler, bgExecutor, choreographer, syncQueue,
- rootTaskDisplayAreaOrganizer, genericLinksParser, assistContentRequester,
+ appHeaderViewHolderFactory, rootTaskDisplayAreaOrganizer, genericLinksParser,
+ assistContentRequester,
SurfaceControl.Builder::new, SurfaceControl.Transaction::new,
WindowContainerTransaction::new, SurfaceControl::new, new WindowManagerWrapper(
context.getSystemService(WindowManager.class)),
new SurfaceControlViewHostFactory() {}, windowDecorViewHostSupplier,
DefaultMaximizeMenuFactory.INSTANCE,
- DefaultHandleMenuFactory.INSTANCE, multiInstanceHelper);
+ DefaultHandleMenuFactory.INSTANCE, multiInstanceHelper,
+ windowDecorCaptionHandleRepository);
}
DesktopModeWindowDecoration(
@@ -220,6 +230,7 @@
@ShellBackgroundThread ShellExecutor bgExecutor,
Choreographer choreographer,
SyncTransactionQueue syncQueue,
+ AppHeaderViewHolder.Factory appHeaderViewHolderFactory,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
AppToWebGenericLinksParser genericLinksParser,
AssistContentRequester assistContentRequester,
@@ -232,7 +243,8 @@
WindowDecorViewHostSupplier windowDecorViewHostSupplier,
MaximizeMenuFactory maximizeMenuFactory,
HandleMenuFactory handleMenuFactory,
- MultiInstanceHelper multiInstanceHelper) {
+ MultiInstanceHelper multiInstanceHelper,
+ WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository) {
super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface,
surfaceControlBuilderSupplier, surfaceControlTransactionSupplier,
windowContainerTransactionSupplier, surfaceControlSupplier,
@@ -242,6 +254,7 @@
mBgExecutor = bgExecutor;
mChoreographer = choreographer;
mSyncQueue = syncQueue;
+ mAppHeaderViewHolderFactory = appHeaderViewHolderFactory;
mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
mGenericLinksParser = genericLinksParser;
mAssistContentRequester = assistContentRequester;
@@ -249,6 +262,7 @@
mHandleMenuFactory = handleMenuFactory;
mMultiInstanceHelper = multiInstanceHelper;
mWindowManagerWrapper = windowManagerWrapper;
+ mWindowDecorCaptionHandleRepository = windowDecorCaptionHandleRepository;
}
/**
@@ -320,11 +334,6 @@
mDragPositioningCallback = dragPositioningCallback;
}
- void setDragDetector(DragDetector dragDetector) {
- mDragDetector = dragDetector;
- mDragDetector.setTouchSlop(ViewConfiguration.get(mContext).getScaledTouchSlop());
- }
-
void setOpenInBrowserClickListener(Consumer<Uri> listener) {
mOpenInBrowserClickListener = listener;
}
@@ -381,6 +390,9 @@
if (mResult.mRootView == null) {
// This means something blocks the window decor from showing, e.g. the task is hidden.
// Nothing is set up in this case including the decoration surface.
+ if (canEnterDesktopMode(mContext) && Flags.enableDesktopWindowingAppHandleEducation()) {
+ notifyNoCaptionHandle();
+ }
disposeStatusBarInputLayer();
Trace.endSection(); // DesktopModeWindowDecoration#relayout
return;
@@ -396,6 +408,9 @@
position.set(determineHandlePosition());
}
Trace.beginSection("DesktopModeWindowDecoration#relayout-bindData");
+ if (canEnterDesktopMode(mContext) && Flags.enableDesktopWindowingAppHandleEducation()) {
+ notifyCaptionStateChanged();
+ }
mWindowDecorViewHolder.bindData(mTaskInfo,
position,
mResult.mCaptionWidth,
@@ -405,6 +420,7 @@
if (!mTaskInfo.isFocused) {
closeHandleMenu();
+ closeManageWindowsMenu();
closeMaximizeMenu();
}
updateDragResizeListener(oldDecorationSurface);
@@ -455,7 +471,7 @@
}
private void updateDragResizeListener(SurfaceControl oldDecorationSurface) {
- if (!isDragResizable(mTaskInfo, mContext)) {
+ if (!isDragResizable(mTaskInfo)) {
if (!mTaskInfo.positionInParent.equals(mPositionInParent)) {
// We still want to track caption bar's exclusion region on a non-resizeable task.
updateExclusionRegion();
@@ -482,7 +498,6 @@
final int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext())
.getScaledTouchSlop();
- mDragDetector.setTouchSlop(touchSlop);
// If either task geometry or position have changed, update this task's
// exclusion region listener
@@ -490,23 +505,79 @@
if (mDragResizeListener.setGeometry(
new DragResizeWindowGeometry(mRelayoutParams.mCornerRadius,
new Size(mResult.mWidth, mResult.mHeight),
- getResizeEdgeHandleSize(mContext, res), getResizeHandleEdgeInset(res),
+ getResizeEdgeHandleSize(res), getResizeHandleEdgeInset(res),
getFineResizeCornerSize(res), getLargeResizeCornerSize(res)), touchSlop)
|| !mTaskInfo.positionInParent.equals(mPositionInParent)) {
updateExclusionRegion();
}
}
- private static boolean isDragResizable(ActivityManager.RunningTaskInfo taskInfo,
- Context context) {
- if (DesktopModeFlags.SCALED_RESIZING.isEnabled(context)) {
+ private static boolean isDragResizable(ActivityManager.RunningTaskInfo taskInfo) {
+ if (DesktopModeFlags.ENABLE_WINDOWING_SCALED_RESIZING.isTrue()) {
return taskInfo.isFreeform();
}
return taskInfo.isFreeform() && taskInfo.isResizeable;
}
+ private void notifyCaptionStateChanged() {
+ // TODO: b/366159408 - Ensure bounds sent with notification account for RTL mode.
+ if (!canEnterDesktopMode(mContext) || !Flags.enableDesktopWindowingAppHandleEducation()) {
+ return;
+ }
+ if (!isCaptionVisible()) {
+ notifyNoCaptionHandle();
+ } else if (isAppHandle(mWindowDecorViewHolder)) {
+ // App handle is visible since `mWindowDecorViewHolder` is of type
+ // [AppHandleViewHolder].
+ final CaptionState captionState = new CaptionState.AppHandle(mTaskInfo,
+ isHandleMenuActive(), getCurrentAppHandleBounds());
+ mWindowDecorCaptionHandleRepository.notifyCaptionChanged(captionState);
+ } else {
+ // App header is visible since `mWindowDecorViewHolder` is of type
+ // [AppHeaderViewHolder].
+ ((AppHeaderViewHolder) mWindowDecorViewHolder).runOnAppChipGlobalLayout(
+ () -> {
+ notifyAppChipStateChanged();
+ return Unit.INSTANCE;
+ });
+ }
+ }
+
+ private void notifyNoCaptionHandle() {
+ if (!canEnterDesktopMode(mContext) || !Flags.enableDesktopWindowingAppHandleEducation()) {
+ return;
+ }
+ mWindowDecorCaptionHandleRepository.notifyCaptionChanged(
+ CaptionState.NoCaption.INSTANCE);
+ }
+
+ private Rect getCurrentAppHandleBounds() {
+ return new Rect(
+ mResult.mCaptionX,
+ /* top= */0,
+ mResult.mCaptionX + mResult.mCaptionWidth,
+ mResult.mCaptionHeight);
+ }
+
+ private void notifyAppChipStateChanged() {
+ final Rect appChipPositionInWindow =
+ ((AppHeaderViewHolder) mWindowDecorViewHolder).getAppChipLocationInWindow();
+ final Rect taskBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
+ final Rect appChipGlobalPosition = new Rect(
+ taskBounds.left + appChipPositionInWindow.left,
+ taskBounds.top + appChipPositionInWindow.top,
+ taskBounds.left + appChipPositionInWindow.right,
+ taskBounds.top + appChipPositionInWindow.bottom);
+ final CaptionState captionState = new CaptionState.AppHeader(
+ mTaskInfo,
+ isHandleMenuActive(),
+ appChipGlobalPosition);
+
+ mWindowDecorCaptionHandleRepository.notifyCaptionChanged(captionState);
+ }
+
private void updateMaximizeMenu(SurfaceControl.Transaction startT) {
- if (!isDragResizable(mTaskInfo, mContext) || !isMaximizeMenuActive()) {
+ if (!isDragResizable(mTaskInfo) || !isMaximizeMenuActive()) {
return;
}
if (!mTaskInfo.isVisible()) {
@@ -554,7 +625,7 @@
} else if (mRelayoutParams.mLayoutResId
== R.layout.desktop_mode_app_header) {
loadAppInfoIfNeeded();
- return new AppHeaderViewHolder(
+ return mAppHeaderViewHolderFactory.create(
mResult.mRootView,
mOnCaptionTouchListener,
mOnCaptionButtonClickListener,
@@ -604,13 +675,13 @@
// their custom content.
relayoutParams.mInputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_SPY;
} else {
- if (Flags.enableCaptionCompatInsetForceConsumption()) {
+ if (ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isTrue()) {
// Force-consume the caption bar insets when the app tries to hide the caption.
// This improves app compatibility of immersive apps.
relayoutParams.mInsetSourceFlags |= FLAG_FORCE_CONSUMING;
}
}
- if (Flags.enableCaptionCompatInsetForceConsumptionAlways()) {
+ if (ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS.isTrue()) {
// Always force-consume the caption bar insets for maximum app compatibility,
// including non-immersive apps that just don't handle caption insets properly.
relayoutParams.mInsetSourceFlags |= FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR;
@@ -656,7 +727,7 @@
// TODO(b/301119301): consider moving the config data needed for diffs to relayout params
// instead of using a whole Configuration as a parameter.
final Configuration windowDecorConfig = new Configuration();
- if (DesktopModeFlags.APP_HEADER_WITH_TASK_DENSITY.isEnabled(context) && isAppHeader) {
+ if (DesktopModeFlags.ENABLE_APP_HEADER_WITH_TASK_DENSITY.isTrue() && isAppHeader) {
// Should match the density of the task. The task may have had its density overridden
// to be different that SysUI's.
windowDecorConfig.setTo(taskInfo.configuration);
@@ -982,7 +1053,8 @@
loadAppInfoIfNeeded();
updateGenericLink();
final boolean supportsMultiInstance = mMultiInstanceHelper
- .supportsMultiInstanceSplit(mTaskInfo.baseActivity);
+ .supportsMultiInstanceSplit(mTaskInfo.baseActivity)
+ && Flags.enableDesktopWindowingMultiInstanceFeatures();
final boolean shouldShowManageWindowsButton = supportsMultiInstance
&& mMinimumInstancesFound;
mHandleMenu = mHandleMenuFactory.create(
@@ -992,7 +1064,7 @@
mAppIconBitmap,
mAppName,
mSplitScreenController,
- DesktopModeStatus.canEnterDesktopMode(mContext),
+ canEnterDesktopMode(mContext),
supportsMultiInstance,
shouldShowManageWindowsButton,
getBrowserLink(),
@@ -1025,6 +1097,9 @@
return Unit.INSTANCE;
}
);
+ if (canEnterDesktopMode(mContext) && Flags.enableDesktopWindowingAppHandleEducation()) {
+ notifyCaptionStateChanged();
+ }
mMinimumInstancesFound = false;
}
@@ -1065,7 +1140,10 @@
}
void closeManageWindowsMenu() {
- mManageWindowsMenu.close();
+ if (mManageWindowsMenu != null) {
+ mManageWindowsMenu.close();
+ }
+ mManageWindowsMenu = null;
}
private void updateGenericLink() {
@@ -1087,11 +1165,15 @@
mWindowDecorViewHolder.onHandleMenuClosed();
mHandleMenu.close();
mHandleMenu = null;
+ if (canEnterDesktopMode(mContext) && Flags.enableDesktopWindowingAppHandleEducation()) {
+ notifyCaptionStateChanged();
+ }
}
@Override
void releaseViews(WindowContainerTransaction wct) {
closeHandleMenu();
+ closeManageWindowsMenu();
closeMaximizeMenu();
super.releaseViews(wct);
}
@@ -1255,9 +1337,14 @@
public void close() {
closeDragResizeListener();
closeHandleMenu();
+ closeManageWindowsMenu();
mExclusionRegionListener.onExclusionRegionDismissed(mTaskInfo.taskId);
disposeResizeVeil();
disposeStatusBarInputLayer();
+ if (canEnterDesktopMode(mContext) && Flags.enableDesktopWindowingAppHandleEducation()) {
+ notifyNoCaptionHandle();
+ }
+
super.close();
}
@@ -1284,7 +1371,7 @@
*/
private Region getGlobalExclusionRegion() {
Region exclusionRegion;
- if (mDragResizeListener != null && mTaskInfo.isResizeable) {
+ if (mDragResizeListener != null && isDragResizable(mTaskInfo)) {
exclusionRegion = mDragResizeListener.getCornersRegion();
} else {
exclusionRegion = new Region();
@@ -1365,10 +1452,12 @@
@ShellBackgroundThread ShellExecutor bgExecutor,
Choreographer choreographer,
SyncTransactionQueue syncQueue,
+ AppHeaderViewHolder.Factory appHeaderViewHolderFactory,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
AppToWebGenericLinksParser genericLinksParser,
AssistContentRequester assistContentRequester,
MultiInstanceHelper multiInstanceHelper,
+ WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
return new DesktopModeWindowDecoration(
context,
@@ -1382,10 +1471,12 @@
bgExecutor,
choreographer,
syncQueue,
+ appHeaderViewHolderFactory,
rootTaskDisplayAreaOrganizer,
genericLinksParser,
assistContentRequester,
multiInstanceHelper,
+ windowDecorCaptionHandleRepository,
windowDecorViewHostSupplier);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
index 3fd3656..01bb7f7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
@@ -26,6 +26,7 @@
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
+import android.annotation.NonNull;
import android.graphics.PointF;
import android.view.MotionEvent;
import android.view.View;
@@ -48,12 +49,18 @@
private int mTouchSlop;
private boolean mIsDragEvent;
private int mDragPointerId = -1;
+ private final long mHoldToDragMinDurationMs;
+ private boolean mDidStrayBeforeFullHold;
+ private boolean mDidHoldForMinDuration;
private boolean mResultOfDownAction;
- DragDetector(MotionEventHandler eventHandler) {
+ DragDetector(@NonNull MotionEventHandler eventHandler, long holdToDragMinDurationMs,
+ int touchSlop) {
resetState();
mEventHandler = eventHandler;
+ mHoldToDragMinDurationMs = holdToDragMinDurationMs;
+ mTouchSlop = touchSlop;
}
/**
@@ -101,9 +108,26 @@
if (!mIsDragEvent) {
float dx = ev.getRawX(dragPointerIndex) - mInputDownPoint.x;
float dy = ev.getRawY(dragPointerIndex) - mInputDownPoint.y;
+ final float dt = ev.getEventTime() - ev.getDownTime();
+ final boolean pastTouchSlop = Math.hypot(dx, dy) > mTouchSlop;
+ final boolean withinHoldRegion = !pastTouchSlop;
+
+ if (mHoldToDragMinDurationMs <= 0) {
+ mDidHoldForMinDuration = true;
+ } else {
+ if (!withinHoldRegion && dt < mHoldToDragMinDurationMs) {
+ // Mark as having strayed so that in case the (x,y) ends up in the
+ // original position we know it's not actually valid.
+ mDidStrayBeforeFullHold = true;
+ }
+ if (!mDidStrayBeforeFullHold && dt >= mHoldToDragMinDurationMs) {
+ mDidHoldForMinDuration = true;
+ }
+ }
+
// Touches generate noisy moves, so only once the move is past the touch
// slop threshold should it be considered a drag.
- mIsDragEvent = Math.hypot(dx, dy) > mTouchSlop;
+ mIsDragEvent = mDidHoldForMinDuration && pastTouchSlop;
}
// The event handler should only be notified about 'move' events if a drag has been
// detected.
@@ -162,6 +186,8 @@
mInputDownPoint.set(0, 0);
mDragPointerId = -1;
mResultOfDownAction = false;
+ mDidStrayBeforeFullHold = false;
+ mDidHoldForMinDuration = false;
}
interface MotionEventHandler {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
index cad3462..38f9cfa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
@@ -27,12 +27,12 @@
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.view.SurfaceControl;
+import android.window.flags.DesktopModeFlags;
import androidx.annotation.NonNull;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
/**
@@ -145,7 +145,7 @@
// If the application is unresizeable and any bounds have been set back to their old
// location or to a stable bound edge, reset all the bounds to maintain the applications
// aspect ratio.
- if (DesktopModeFlags.SCALED_RESIZING.isEnabled(windowDecoration.mDecorWindowContext)
+ if (DesktopModeFlags.ENABLE_WINDOWING_SCALED_RESIZING.isTrue()
&& !isAspectRatioMaintained && !windowDecoration.mTaskInfo.isResizeable) {
repositionTaskBounds.top = oldTop;
repositionTaskBounds.bottom = oldBottom;
@@ -275,7 +275,7 @@
private static boolean isSizeConstraintForDesktopModeEnabled(Context context) {
return DesktopModeStatus.canEnterDesktopMode(context)
- && DesktopModeFlags.SIZE_CONSTRAINTS.isEnabled(context);
+ && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS.isTrue();
}
interface DragStartListener {
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 a27c506..4ff394e 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
@@ -183,7 +183,7 @@
mTouchRegion.setEmpty();
// Apply the geometry to the touch region.
- geometry.union(mContext, mTouchRegion);
+ geometry.union(mTouchRegion);
mInputEventReceiver.setGeometry(geometry);
mInputEventReceiver.setTouchRegion(mTouchRegion);
@@ -318,7 +318,8 @@
}
};
- mDragDetector = new DragDetector(this);
+ mDragDetector = new DragDetector(this, 0 /* holdToDragMinDurationMs */,
+ ViewConfiguration.get(mContext).getScaledTouchSlop());
mDisplayLayoutSizeSupplier = displayLayoutSizeSupplier;
mTouchRegionConsumer = touchRegionConsumer;
}
@@ -357,7 +358,7 @@
*/
@NonNull Region getCornersRegion() {
Region region = new Region();
- mDragResizeWindowGeometry.union(mContext, region);
+ mDragResizeWindowGeometry.union(region);
return region;
}
@@ -408,8 +409,8 @@
float y = e.getY(0);
float rawX = e.getRawX(0);
float rawY = e.getRawY(0);
- final int ctrlType = mDragResizeWindowGeometry.calculateCtrlType(mContext,
- isEventFromTouchscreen(e), isEdgeResizePermitted(mContext, e), x,
+ final int ctrlType = mDragResizeWindowGeometry.calculateCtrlType(
+ isEventFromTouchscreen(e), isEdgeResizePermitted(e), x,
y);
ProtoLog.d(WM_SHELL_DESKTOP_MODE,
"%s: Handling action down, update ctrlType to %d", TAG, ctrlType);
@@ -500,8 +501,8 @@
// Since we are handling cursor, we know that this is not a touchscreen event, and
// that edge resizing should always be allowed.
@DragPositioningCallback.CtrlType int ctrlType =
- mDragResizeWindowGeometry.calculateCtrlType(mContext, /* isTouchscreen= */
- false, /* isEdgeResizePermitted= */ true, x, y);
+ mDragResizeWindowGeometry.calculateCtrlType(/* isTouchscreen= */ false,
+ /* isEdgeResizePermitted= */ true, x, y);
int cursorType = PointerIcon.TYPE_DEFAULT;
switch (ctrlType) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
index 6dedf6d..d726f50 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
@@ -18,8 +18,8 @@
import static android.view.InputDevice.SOURCE_MOUSE;
import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
+import static android.window.flags.DesktopModeFlags.ENABLE_WINDOWING_EDGE_DRAG_RESIZE;
-import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.EDGE_DRAG_RESIZE;
import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM;
import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_LEFT;
import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT;
@@ -76,8 +76,8 @@
/**
* Returns the resource value to use for the resize handle on the edge of the window.
*/
- static int getResizeEdgeHandleSize(@NonNull Context context, @NonNull Resources res) {
- return EDGE_DRAG_RESIZE.isEnabled(context)
+ static int getResizeEdgeHandleSize(@NonNull Resources res) {
+ return ENABLE_WINDOWING_EDGE_DRAG_RESIZE.isTrue()
? res.getDimensionPixelSize(R.dimen.freeform_edge_handle_outset)
: res.getDimensionPixelSize(R.dimen.freeform_resize_handle);
}
@@ -118,11 +118,11 @@
* Returns the union of all regions that can be touched for drag resizing; the corners window
* and window edges.
*/
- void union(@NonNull Context context, @NonNull Region region) {
+ void union(@NonNull Region region) {
// Apply the edge resize regions.
mTaskEdges.union(region);
- if (EDGE_DRAG_RESIZE.isEnabled(context)) {
+ if (ENABLE_WINDOWING_EDGE_DRAG_RESIZE.isTrue()) {
// Apply the corners as well for the larger corners, to ensure we capture all possible
// touches.
mLargeTaskCorners.union(region);
@@ -140,7 +140,7 @@
final float x = e.getX(0) + offset.x;
final float y = e.getY(0) + offset.y;
- if (EDGE_DRAG_RESIZE.isEnabled(context)) {
+ if (ENABLE_WINDOWING_EDGE_DRAG_RESIZE.isTrue()) {
// First check if touch falls within a corner.
// Large corner bounds are used for course input like touch, otherwise fine bounds.
boolean result = isEventFromTouchscreen(e)
@@ -148,7 +148,7 @@
: isInCornerBounds(mFineTaskCorners, x, y);
// Check if touch falls within the edge resize handle. Limit edge resizing to stylus and
// mouse input.
- if (!result && isEdgeResizePermitted(context, e)) {
+ if (!result && isEdgeResizePermitted(e)) {
result = isInEdgeResizeBounds(x, y);
}
return result;
@@ -164,8 +164,8 @@
return (e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN;
}
- static boolean isEdgeResizePermitted(@NonNull Context context, @NonNull MotionEvent e) {
- if (EDGE_DRAG_RESIZE.isEnabled(context)) {
+ static boolean isEdgeResizePermitted(@NonNull MotionEvent e) {
+ if (ENABLE_WINDOWING_EDGE_DRAG_RESIZE.isTrue()) {
return e.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS
|| e.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE
// Touchpad input
@@ -193,9 +193,8 @@
* resize region.
*/
@DragPositioningCallback.CtrlType
- int calculateCtrlType(@NonNull Context context, boolean isTouchscreen,
- boolean isEdgeResizePermitted, float x, float y) {
- if (EDGE_DRAG_RESIZE.isEnabled(context)) {
+ int calculateCtrlType(boolean isTouchscreen, boolean isEdgeResizePermitted, float x, float y) {
+ if (ENABLE_WINDOWING_EDGE_DRAG_RESIZE.isTrue()) {
// First check if touch falls within a corner.
// Large corner bounds are used for course input like touch, otherwise fine bounds.
int ctrlType = isTouchscreen
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 faffe4a..5b3f263 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
@@ -592,12 +592,16 @@
floatingBtn.visibility = View.GONE
fullscreenBtn.isSelected = taskInfo.isFullscreen
+ fullscreenBtn.isEnabled = !taskInfo.isFullscreen
fullscreenBtn.imageTintList = style.windowingButtonColor
splitscreenBtn.isSelected = taskInfo.isMultiWindow
+ splitscreenBtn.isEnabled = !taskInfo.isMultiWindow
splitscreenBtn.imageTintList = style.windowingButtonColor
floatingBtn.isSelected = taskInfo.isPinned
+ floatingBtn.isEnabled = !taskInfo.isPinned
floatingBtn.imageTintList = style.windowingButtonColor
desktopBtn.isSelected = taskInfo.isFreeform
+ desktopBtn.isEnabled = !taskInfo.isFreeform
desktopBtn.imageTintList = style.windowingButtonColor
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
index 4faed01..2d97dc0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
@@ -32,7 +32,7 @@
import androidx.core.animation.doOnStart
import androidx.core.content.ContextCompat
import com.android.wm.shell.R
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags
+import android.window.flags.DesktopModeFlags
private const val OPEN_MAXIMIZE_MENU_DELAY_ON_HOVER_MS = 350
private const val MAX_DRAWABLE_ALPHA = 255
@@ -108,7 +108,7 @@
baseForegroundColor: Int? = null,
rippleDrawable: RippleDrawable? = null
) {
- if (DesktopModeFlags.THEMED_APP_HEADERS.isEnabled(context)) {
+ if (DesktopModeFlags.ENABLE_THEMED_APP_HEADERS.isTrue()) {
requireNotNull(iconForegroundColor) { "Icon foreground color must be non-null" }
requireNotNull(baseForegroundColor) { "Base foreground color must be non-null" }
requireNotNull(rippleDrawable) { "Ripple drawable must be non-null" }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
index 5998155..6eb5cca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
@@ -24,7 +24,10 @@
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
+import android.view.Choreographer;
import android.view.Surface;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
@@ -37,6 +40,7 @@
import com.android.internal.jank.InteractionJankMonitor;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.transition.Transitions;
import java.util.function.Supplier;
@@ -63,14 +67,17 @@
private int mCtrlType;
private boolean mIsResizingOrAnimatingResize;
@Surface.Rotation private int mRotation;
+ @ShellMainThread
+ private final Handler mHandler;
public VeiledResizeTaskPositioner(ShellTaskOrganizer taskOrganizer,
DesktopModeWindowDecoration windowDecoration,
DisplayController displayController,
DragPositioningCallbackUtility.DragStartListener dragStartListener,
- Transitions transitions, InteractionJankMonitor interactionJankMonitor) {
+ Transitions transitions, InteractionJankMonitor interactionJankMonitor,
+ @ShellMainThread Handler handler) {
this(taskOrganizer, windowDecoration, displayController, dragStartListener,
- SurfaceControl.Transaction::new, transitions, interactionJankMonitor);
+ SurfaceControl.Transaction::new, transitions, interactionJankMonitor, handler);
}
public VeiledResizeTaskPositioner(ShellTaskOrganizer taskOrganizer,
@@ -78,7 +85,7 @@
DisplayController displayController,
DragPositioningCallbackUtility.DragStartListener dragStartListener,
Supplier<SurfaceControl.Transaction> supplier, Transitions transitions,
- InteractionJankMonitor interactionJankMonitor) {
+ InteractionJankMonitor interactionJankMonitor, @ShellMainThread Handler handler) {
mDesktopWindowDecoration = windowDecoration;
mTaskOrganizer = taskOrganizer;
mDisplayController = displayController;
@@ -86,6 +93,7 @@
mTransactionSupplier = supplier;
mTransitions = transitions;
mInteractionJankMonitor = interactionJankMonitor;
+ mHandler = handler;
}
@Override
@@ -97,7 +105,7 @@
if (isResizing()) {
// Capture CUJ for re-sizing window in DW mode.
mInteractionJankMonitor.begin(mDesktopWindowDecoration.mTaskSurface,
- mDesktopWindowDecoration.mContext, CUJ_DESKTOP_MODE_RESIZE_WINDOW);
+ mDesktopWindowDecoration.mContext, mHandler, CUJ_DESKTOP_MODE_RESIZE_WINDOW);
if (!mDesktopWindowDecoration.mTaskInfo.isFocused) {
WindowContainerTransaction wct = new WindowContainerTransaction();
wct.reorder(mDesktopWindowDecoration.mTaskInfo.token, true);
@@ -118,6 +126,11 @@
@Override
public Rect onDragPositioningMove(float x, float y) {
+ if (Looper.myLooper() != mHandler.getLooper()) {
+ // This method must run on the shell main thread to use the correct Choreographer
+ // instance below.
+ throw new IllegalStateException("This method must run on the shell main thread.");
+ }
PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y, mRepositionStartPoint);
if (isResizing() && DragPositioningCallbackUtility.changeBounds(mCtrlType,
mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds, delta,
@@ -131,10 +144,11 @@
} else if (mCtrlType == CTRL_TYPE_UNDEFINED) {
// Begin window drag CUJ instrumentation only when drag position moves.
mInteractionJankMonitor.begin(mDesktopWindowDecoration.mTaskSurface,
- mDesktopWindowDecoration.mContext, CUJ_DESKTOP_MODE_DRAG_WINDOW);
+ mDesktopWindowDecoration.mContext, mHandler, CUJ_DESKTOP_MODE_DRAG_WINDOW);
final SurfaceControl.Transaction t = mTransactionSupplier.get();
DragPositioningCallbackUtility.setPositionOnDrag(mDesktopWindowDecoration,
mRepositionTaskBounds, mTaskBoundsAtDragStart, mRepositionStartPoint, t, x, y);
+ t.setFrameTimeline(Choreographer.getInstance().getVsyncId());
t.apply();
}
return new Rect(mRepositionTaskBounds);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
index 033d695..af6a819 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
@@ -22,12 +22,14 @@
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.Point
+import android.graphics.Rect
import android.graphics.drawable.LayerDrawable
import android.graphics.drawable.RippleDrawable
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RoundRectShape
import android.view.View
import android.view.View.OnLongClickListener
+import android.view.ViewTreeObserver.OnGlobalLayoutListener
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
@@ -45,7 +47,7 @@
import com.android.internal.R.attr.materialColorSurfaceDim
import com.android.window.flags.Flags.enableMinimizeButton
import com.android.wm.shell.R
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags
+import android.window.flags.DesktopModeFlags
import com.android.wm.shell.windowdecor.MaximizeButtonView
import com.android.wm.shell.windowdecor.common.DecorThemeUtil
import com.android.wm.shell.windowdecor.common.OPACITY_100
@@ -62,7 +64,7 @@
* finer controls such as a close window button and an "app info" section to pull up additional
* controls.
*/
-internal class AppHeaderViewHolder(
+class AppHeaderViewHolder(
rootView: View,
onCaptionTouchListener: View.OnTouchListener,
onCaptionButtonClickListener: View.OnClickListener,
@@ -155,7 +157,7 @@
height: Int,
isCaptionVisible: Boolean
) {
- if (DesktopModeFlags.THEMED_APP_HEADERS.isEnabled(context)) {
+ if (DesktopModeFlags.ENABLE_THEMED_APP_HEADERS.isTrue()) {
bindDataWithThemedHeaders(taskInfo)
} else {
bindDataLegacy(taskInfo)
@@ -279,6 +281,34 @@
maximizeButtonView.startHoverAnimation()
}
+ fun runOnAppChipGlobalLayout(runnable: () -> Unit) {
+ if (openMenuButton.isAttachedToWindow) {
+ // App chip is already inflated.
+ runnable()
+ return
+ }
+ // Wait for app chip to be inflated before notifying repository.
+ openMenuButton.viewTreeObserver.addOnGlobalLayoutListener(object :
+ OnGlobalLayoutListener {
+ override fun onGlobalLayout() {
+ runnable()
+ openMenuButton.viewTreeObserver.removeOnGlobalLayoutListener(this)
+ }
+ })
+ }
+
+ fun getAppChipLocationInWindow(): Rect {
+ val appChipBoundsInWindow = IntArray(2)
+ openMenuButton.getLocationInWindow(appChipBoundsInWindow)
+
+ return Rect(
+ /* left = */ appChipBoundsInWindow[0],
+ /* top = */ appChipBoundsInWindow[1],
+ /* right = */ appChipBoundsInWindow[0] + openMenuButton.width,
+ /* bottom = */ appChipBoundsInWindow[1] + openMenuButton.height
+ )
+ }
+
private fun getHeaderStyle(header: Header): HeaderStyle {
return HeaderStyle(
background = getHeaderBackground(header),
@@ -529,4 +559,26 @@
private const val LIGHT_THEME_UNFOCUSED_OPACITY = 166 // 65%
private const val FOCUSED_OPACITY = 255
}
+
+ class Factory {
+ fun create(
+ rootView: View,
+ onCaptionTouchListener: View.OnTouchListener,
+ onCaptionButtonClickListener: View.OnClickListener,
+ onLongClickListener: OnLongClickListener,
+ onCaptionGenericMotionListener: View.OnGenericMotionListener,
+ appName: CharSequence,
+ appIconBitmap: Bitmap,
+ onMaximizeHoverAnimationFinishedListener: () -> Unit,
+ ): AppHeaderViewHolder = AppHeaderViewHolder(
+ rootView,
+ onCaptionTouchListener,
+ onCaptionButtonClickListener,
+ onLongClickListener,
+ onCaptionGenericMotionListener,
+ appName,
+ appIconBitmap,
+ onMaximizeHoverAnimationFinishedListener,
+ )
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/WindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/WindowDecorationViewHolder.kt
index 2341b09..5ea55b3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/WindowDecorationViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/WindowDecorationViewHolder.kt
@@ -24,7 +24,7 @@
* Encapsulates the root [View] of a window decoration and its children to facilitate looking up
* children (via findViewById) and updating to the latest data from [RunningTaskInfo].
*/
-internal abstract class WindowDecorationViewHolder(rootView: View) {
+abstract class WindowDecorationViewHolder(rootView: View) {
val context: Context = rootView.context
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHost.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHost.kt
index 5156e47..139e679 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHost.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHost.kt
@@ -19,33 +19,51 @@
import android.content.res.Configuration
import android.view.Display
import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
import android.view.View
import android.view.WindowManager
+import android.view.WindowlessWindowManager
import androidx.tracing.Trace
import com.android.internal.annotations.VisibleForTesting
import com.android.wm.shell.shared.annotations.ShellMainThread
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
+typealias SurfaceControlViewHostFactory =
+ (Context, Display, WindowlessWindowManager, String) -> SurfaceControlViewHost
/**
- * A default implementation of [WindowDecorViewHost] backed by a [SurfaceControlViewHostAdapter].
+ * A default implementation of [WindowDecorViewHost] backed by a [SurfaceControlViewHost].
*
- * It supports asynchronously updating the view hierarchy using [updateViewAsync], in which
+ * It does not support swapping the root view added to the VRI of the [SurfaceControlViewHost], and
+ * any attempts to do will throw, which means that once a [View] is added using [updateView] or
+ * [updateViewAsync], only its properties and binding may be changed, its children views may be
+ * added, removed or changed and its [WindowManager.LayoutParams] may be changed.
+ * It also supports asynchronously updating the view hierarchy using [updateViewAsync], in which
* case the update work will be posted on the [ShellMainThread] with no delay.
*/
class DefaultWindowDecorViewHost(
- context: Context,
+ private val context: Context,
@ShellMainThread private val mainScope: CoroutineScope,
- display: Display,
- @VisibleForTesting val viewHostAdapter: SurfaceControlViewHostAdapter =
- SurfaceControlViewHostAdapter(context, display)
+ private val display: Display,
+ private val surfaceControlViewHostFactory: SurfaceControlViewHostFactory = { c, d, wwm, s ->
+ SurfaceControlViewHost(c, d, wwm, s)
+ }
) : WindowDecorViewHost {
+ private val rootSurface: SurfaceControl = SurfaceControl.Builder()
+ .setName("DefaultWindowDecorViewHost surface")
+ .setContainerLayer()
+ .setCallsite("DefaultWindowDecorViewHost#init")
+ .build()
+
+ private var wwm: WindowlessWindowManager? = null
+ @VisibleForTesting
+ var viewHost: SurfaceControlViewHost? = null
private var currentUpdateJob: Job? = null
override val surfaceControl: SurfaceControl
- get() = viewHostAdapter.rootSurface
+ get() = rootSurface
override fun updateView(
view: View,
@@ -74,7 +92,8 @@
override fun release(t: SurfaceControl.Transaction) {
clearCurrentUpdateJob()
- viewHostAdapter.release(t)
+ viewHost?.release()
+ t.remove(rootSurface)
}
private fun updateViewHost(
@@ -83,15 +102,45 @@
configuration: Configuration,
onDrawTransaction: SurfaceControl.Transaction?
) {
- viewHostAdapter.prepareViewHost(configuration)
- onDrawTransaction?.let {
- viewHostAdapter.applyTransactionOnDraw(it)
+ Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost")
+ if (wwm == null) {
+ wwm = WindowlessWindowManager(configuration, rootSurface, null)
}
- viewHostAdapter.updateView(view, attrs)
+ requireWindowlessWindowManager().setConfiguration(configuration)
+ if (viewHost == null) {
+ viewHost = surfaceControlViewHostFactory.invoke(
+ context,
+ display,
+ requireWindowlessWindowManager(),
+ "DefaultWindowDecorViewHost#updateViewHost"
+ )
+ }
+ onDrawTransaction?.let {
+ requireViewHost().rootSurfaceControl.applyTransactionOnDraw(it)
+ }
+ if (requireViewHost().view == null) {
+ Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost-setView")
+ requireViewHost().setView(view, attrs)
+ Trace.endSection()
+ } else {
+ check(requireViewHost().view == view) { "Changing view is not allowed" }
+ Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost-relayout")
+ requireViewHost().relayout(attrs)
+ Trace.endSection()
+ }
+ Trace.endSection()
}
private fun clearCurrentUpdateJob() {
currentUpdateJob?.cancel()
currentUpdateJob = null
}
+
+ private fun requireWindowlessWindowManager(): WindowlessWindowManager {
+ return wwm ?: error("Expected non-null windowless window manager")
+ }
+
+ private fun requireViewHost(): SurfaceControlViewHost {
+ return viewHost ?: error("Expected non-null view host")
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/PooledWindowDecorViewHostSupplier.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/PooledWindowDecorViewHostSupplier.kt
deleted file mode 100644
index b04188f..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/PooledWindowDecorViewHostSupplier.kt
+++ /dev/null
@@ -1,105 +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.wm.shell.windowdecor.viewhost
-
-import android.content.Context
-import android.os.Trace
-import android.util.Pools
-import android.view.Display
-import android.view.SurfaceControl
-import com.android.wm.shell.shared.annotations.ShellMainThread
-import com.android.wm.shell.sysui.ShellInit
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
-
-/**
- * A [WindowDecorViewHostSupplier] backed by a pool to allow recycling view hosts which may be
- * expensive to recreate for each new/updated window decoration.
- *
- * Callers can obtain [ReusableWindowDecorViewHost] using [acquire], which will return a pooled
- * object if available, or create a new instance and return it if needed. When done using a
- * [ReusableWindowDecorViewHost], it must be released using [release] to allow it to be sent back
- * into the pool and reused later on.
- *
- * This class also supports pre-warming [ReusableWindowDecorViewHost] instances, which will be put
- * into the pool immediately after creation.
- */
-class PooledWindowDecorViewHostSupplier(
- private val context: Context,
- @ShellMainThread private val mainScope: CoroutineScope,
- shellInit: ShellInit,
- private val viewHostFactory: ReusableWindowDecorViewHost.Factory =
- ReusableWindowDecorViewHost.DefaultFactory,
- maxPoolSize: Int,
- private val preWarmSize: Int,
-) : WindowDecorViewHostSupplier<ReusableWindowDecorViewHost> {
-
- private val pool: Pools.Pool<ReusableWindowDecorViewHost> = Pools.SynchronizedPool(maxPoolSize)
- private var nextDecorViewHostId = 0
-
- init {
- require(preWarmSize <= maxPoolSize) { "Pre-warm size should not exceed pool size" }
- shellInit.addInitCallback(this::onShellInit, this)
- }
-
- private fun onShellInit() {
- if (preWarmSize <= 0) {
- return
- }
- preWarmViewHosts(preWarmSize)
- }
-
- private fun preWarmViewHosts(preWarmSize: Int) {
- mainScope.launch {
- // Applying isn't needed, as the surface was never actually shown.
- val t = SurfaceControl.Transaction()
- repeat(preWarmSize) {
- val warmedViewHost = create(context, context.display).apply {
- warmUp()
- }
- // Put the warmed view host in the pool by releasing it.
- release(warmedViewHost, t)
- }
- }
- }
-
- override fun acquire(context: Context, display: Display): ReusableWindowDecorViewHost {
- val reusedDecorViewHost = pool.acquire()
- if (reusedDecorViewHost != null) {
- return reusedDecorViewHost
- }
- Trace.beginSection("WindowDecorViewHostPool#acquire-new")
- val newDecorViewHost = create(context, display)
- Trace.endSection()
- return newDecorViewHost
- }
-
- override fun release(viewHost: ReusableWindowDecorViewHost, t: SurfaceControl.Transaction) {
- val cached = pool.release(viewHost)
- if (!cached) {
- viewHost.release(t)
- }
- }
-
- private fun create(context: Context, display: Display): ReusableWindowDecorViewHost {
- return viewHostFactory.create(
- context,
- mainScope,
- display,
- nextDecorViewHostId++
- )
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/ReusableWindowDecorViewHost.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/ReusableWindowDecorViewHost.kt
deleted file mode 100644
index 64536d1..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/ReusableWindowDecorViewHost.kt
+++ /dev/null
@@ -1,161 +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.wm.shell.windowdecor.viewhost
-
-import android.content.Context
-import android.content.res.Configuration
-import android.graphics.PixelFormat
-import android.os.Trace
-import android.view.Display
-import android.view.SurfaceControl
-import android.view.SurfaceControlViewHost
-import android.view.View
-import android.view.WindowManager
-import android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-import android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
-import android.view.WindowManager.LayoutParams.TYPE_APPLICATION
-import android.widget.FrameLayout
-import com.android.internal.annotations.VisibleForTesting
-import com.android.wm.shell.shared.annotations.ShellMainThread
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.launch
-
-/**
- * An implementation of [WindowDecorViewHost] that supports:
- * 1) Replacing the root [View], meaning [WindowDecorViewHost.updateView] maybe be
- * called with different [View] instances. This is useful when reusing [WindowDecorViewHost]s
- * instances for vastly different view hierarchies, such as Desktop Windowing's App Handles and
- * App Headers.
- * 2) Pre-warming of the underlying [SurfaceControlViewHost]s. Useful because their creation and
- * first root view assignment are expensive, which is undesirable in latency-sensitive code
- * paths like during a shell transition.
- */
-class ReusableWindowDecorViewHost(
- private val context: Context,
- @ShellMainThread private val mainScope: CoroutineScope,
- display: Display,
- val id: Int,
- @VisibleForTesting val viewHostAdapter: SurfaceControlViewHostAdapter =
- SurfaceControlViewHostAdapter(context, display)
-) : WindowDecorViewHost, Warmable {
-
- @VisibleForTesting
- val rootView = FrameLayout(context)
-
- private var currentUpdateJob: Job? = null
-
- override val surfaceControl: SurfaceControl
- get() = viewHostAdapter.rootSurface
-
- override fun warmUp() {
- if (viewHostAdapter.isInitialized()) {
- // Already warmed up.
- return
- }
- Trace.beginSection("$TAG#warmUp")
- viewHostAdapter.prepareViewHost(context.resources.configuration)
- viewHostAdapter.updateView(
- rootView,
- WindowManager.LayoutParams(
- 0 /* width*/,
- 0 /* height */,
- TYPE_APPLICATION,
- FLAG_NOT_FOCUSABLE or FLAG_SPLIT_TOUCH,
- PixelFormat.TRANSPARENT
- ).apply {
- setTitle("View root of $TAG#$id")
- setTrustedOverlay()
- }
- )
- Trace.endSection()
- }
-
- override fun updateView(
- view: View,
- attrs: WindowManager.LayoutParams,
- configuration: Configuration,
- onDrawTransaction: SurfaceControl.Transaction?
- ) {
- clearCurrentUpdateJob()
- updateViewHost(view, attrs, configuration, onDrawTransaction)
- }
-
- override fun updateViewAsync(
- view: View,
- attrs: WindowManager.LayoutParams,
- configuration: Configuration
- ) {
- clearCurrentUpdateJob()
- currentUpdateJob = mainScope.launch {
- updateViewHost(view, attrs, configuration, onDrawTransaction = null)
- }
- }
-
- override fun release(t: SurfaceControl.Transaction) {
- clearCurrentUpdateJob()
- viewHostAdapter.release(t)
- }
-
- private fun updateViewHost(
- view: View,
- attrs: WindowManager.LayoutParams,
- configuration: Configuration,
- onDrawTransaction: SurfaceControl.Transaction?
- ) {
- viewHostAdapter.prepareViewHost(configuration)
- onDrawTransaction?.let {
- viewHostAdapter.applyTransactionOnDraw(it)
- }
- rootView.removeAllViews()
- rootView.addView(view)
- viewHostAdapter.updateView(rootView, attrs)
- }
-
- private fun clearCurrentUpdateJob() {
- currentUpdateJob?.cancel()
- currentUpdateJob = null
- }
-
- interface Factory {
- fun create(
- context: Context,
- @ShellMainThread mainScope: CoroutineScope,
- display: Display,
- id: Int
- ): ReusableWindowDecorViewHost
- }
-
- object DefaultFactory : Factory {
- override fun create(
- context: Context,
- @ShellMainThread mainScope: CoroutineScope,
- display: Display,
- id: Int
- ): ReusableWindowDecorViewHost {
- return ReusableWindowDecorViewHost(
- context,
- mainScope,
- display,
- id
- )
- }
- }
-
- companion object {
- private const val TAG = "ReusableWindowDecorViewHost"
- }
-}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/SurfaceControlViewHostAdapter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/SurfaceControlViewHostAdapter.kt
deleted file mode 100644
index a54c9ba..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/SurfaceControlViewHostAdapter.kt
+++ /dev/null
@@ -1,111 +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.wm.shell.windowdecor.viewhost
-
-import android.content.Context
-import android.content.res.Configuration
-import android.view.AttachedSurfaceControl
-import android.view.Display
-import android.view.SurfaceControl
-import android.view.SurfaceControlViewHost
-import android.view.View
-import android.view.WindowManager
-import android.view.WindowlessWindowManager
-import androidx.tracing.Trace
-import com.android.internal.annotations.VisibleForTesting
-typealias SurfaceControlViewHostFactory =
- (Context, Display, WindowlessWindowManager, String) -> SurfaceControlViewHost
-
-/**
- * Adapter for a [SurfaceControlViewHost] and its backing [SurfaceControl].
- *
- * It does not support swapping the root view added to the VRI of the [SurfaceControlViewHost], and
- * any attempts to do will throw, which means that once a [View] is added using [updateView], only
- * its properties and binding may be changed, its children views may be added, removed or changed
- * and its [WindowManager.LayoutParams] may be changed.
- */
-class SurfaceControlViewHostAdapter(
- private val context: Context,
- private val display: Display,
- private val surfaceControlViewHostFactory: SurfaceControlViewHostFactory = { c, d, wwm, s ->
- SurfaceControlViewHost(c, d, wwm, s)
- }
-) {
- val rootSurface: SurfaceControl = SurfaceControl.Builder()
- .setName("SurfaceControlViewHostAdapter surface")
- .setContainerLayer()
- .setCallsite("SurfaceControlViewHostAdapter#init")
- .build()
-
- private var wwm: WindowlessWindowManager? = null
- @VisibleForTesting
- var viewHost: SurfaceControlViewHost? = null
-
- /** Initialize the [SurfaceControlViewHost] if needed. */
- fun prepareViewHost(configuration: Configuration) {
- if (wwm == null) {
- wwm = WindowlessWindowManager(configuration, rootSurface, null)
- }
- requireWindowlessWindowManager().setConfiguration(configuration)
- if (viewHost == null) {
- viewHost = surfaceControlViewHostFactory.invoke(
- context,
- display,
- requireWindowlessWindowManager(),
- "SurfaceControlViewHostAdapter#prepareViewHost"
- )
- }
- }
-
- /**
- * Request to apply the transaction atomically with the next draw of the view hierarchy.
- * See [AttachedSurfaceControl.applyTransactionOnDraw].
- */
- fun applyTransactionOnDraw(t: SurfaceControl.Transaction) {
- requireViewHost().rootSurfaceControl.applyTransactionOnDraw(t)
- }
-
- /** Update the view hierarchy of the view host. */
- fun updateView(view: View, attrs: WindowManager.LayoutParams) {
- if (requireViewHost().view == null) {
- Trace.beginSection("SurfaceControlViewHostAdapter#updateView-setView")
- requireViewHost().setView(view, attrs)
- Trace.endSection()
- } else {
- check(requireViewHost().view == view) { "Changing view is not allowed" }
- Trace.beginSection("SurfaceControlViewHostAdapter#updateView-relayout")
- requireViewHost().relayout(attrs)
- Trace.endSection()
- }
- }
-
- /** Release the view host and remove the backing surface. */
- fun release(t: SurfaceControl.Transaction) {
- viewHost?.release()
- t.remove(rootSurface)
- }
-
- /** Whether the view host has had a view hierarchy set. */
- fun isInitialized(): Boolean = viewHost?.view != null
-
- private fun requireWindowlessWindowManager(): WindowlessWindowManager {
- return wwm ?: error("Expected non-null windowless window manager")
- }
-
- private fun requireViewHost(): SurfaceControlViewHost {
- return viewHost ?: error("Expected non-null view host")
- }
-}
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/SwitchBackToSplitFromRecent.kt
index c7cbc3e4..22adf6c 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/SwitchBackToSplitFromRecent.kt
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/SwitchBackToSplitFromRecent.kt
@@ -48,6 +48,7 @@
fun setup() {
tapl.workspace.switchToOverview().dismissAllTasks()
+ tapl.setExpectedRotationCheckEnabled(false)
tapl.setEnableRotation(true)
tapl.setExpectedRotation(rotation.value)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
index 24f4d92..e6bd05b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
@@ -47,6 +47,8 @@
private ActivityManager.TaskDescription.Builder mTaskDescriptionBuilder = null;
private final Point mPositionInParent = new Point();
private boolean mIsVisible = false;
+ private boolean mIsTopActivityTransparent = false;
+ private int mNumActivities = 1;
private long mLastActiveTime;
public static WindowContainerToken createMockWCToken() {
@@ -113,6 +115,16 @@
return this;
}
+ public TestRunningTaskInfoBuilder setTopActivityTransparent(boolean isTopActivityTransparent) {
+ mIsTopActivityTransparent = isTopActivityTransparent;
+ return this;
+ }
+
+ public TestRunningTaskInfoBuilder setNumActivities(int numActivities) {
+ mNumActivities = numActivities;
+ return this;
+ }
+
public TestRunningTaskInfoBuilder setLastActiveTime(long lastActiveTime) {
mLastActiveTime = lastActiveTime;
return this;
@@ -134,6 +146,8 @@
mTaskDescriptionBuilder != null ? mTaskDescriptionBuilder.build() : null;
info.positionInParent = mPositionInParent;
info.isVisible = mIsVisible;
+ info.isTopActivityTransparent = mIsTopActivityTransparent;
+ info.numActivities = mNumActivities;
info.lastActiveTime = mLastActiveTime;
return info;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/OWNERS
new file mode 100644
index 0000000..622f837
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 1168918
+# includes OWNERS from parent directories
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apptoweb/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apptoweb/OWNERS
new file mode 100644
index 0000000..553540c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apptoweb/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 929241
+# includes OWNERS from parent directories
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index b53ea38..227060d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -137,6 +137,8 @@
private Transitions mTransitions;
@Mock
private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
+ @Mock
+ private Handler mHandler;
private BackAnimationController mController;
private TestableContentResolver mContentResolver;
@@ -161,13 +163,14 @@
mTestableLooper = TestableLooper.get(this);
mShellInit = spy(new ShellInit(mShellExecutor));
mDefaultCrossActivityBackAnimation = new DefaultCrossActivityBackAnimation(mContext,
- mAnimationBackground, mRootTaskDisplayAreaOrganizer);
- mCrossTaskBackAnimation = new CrossTaskBackAnimation(mContext, mAnimationBackground);
+ mAnimationBackground, mRootTaskDisplayAreaOrganizer, mHandler);
+ mCrossTaskBackAnimation = new CrossTaskBackAnimation(mContext, mAnimationBackground,
+ mHandler);
mShellBackAnimationRegistry =
new ShellBackAnimationRegistry(mDefaultCrossActivityBackAnimation,
mCrossTaskBackAnimation, /* dialogCloseAnimation= */ null,
new CustomCrossActivityBackAnimation(mContext, mAnimationBackground,
- mRootTaskDisplayAreaOrganizer),
+ mRootTaskDisplayAreaOrganizer, mHandler),
/* defaultBackToHomeAnimation= */ null);
mController =
new BackAnimationController(
@@ -181,7 +184,8 @@
mAnimationBackground,
mShellBackAnimationRegistry,
mShellCommandHandler,
- mTransitions);
+ mTransitions,
+ mHandler);
mShellInit.init();
mShellExecutor.flushAll();
mTouchableRegion = new Rect(0, 0, 100, 100);
@@ -344,7 +348,8 @@
mAnimationBackground,
mShellBackAnimationRegistry,
mShellCommandHandler,
- mTransitions);
+ mTransitions,
+ mHandler);
shellInit.init();
registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
@@ -898,7 +903,8 @@
new BackAnimationRunner(
mAnimatorCallback,
mBackAnimationRunner,
- mContext));
+ mContext,
+ mHandler));
}
private void unregisterAnimation(int type) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt
index 080ad90..5b5ef6f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt
@@ -22,6 +22,7 @@
import android.graphics.Color
import android.graphics.Point
import android.graphics.Rect
+import android.os.Handler
import android.os.RemoteException
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -66,6 +67,7 @@
@Mock private lateinit var transitionAnimation: TransitionAnimation
@Mock private lateinit var appCompatTaskInfo: AppCompatTaskInfo
@Mock private lateinit var transaction: Transaction
+ @Mock private lateinit var handler: Handler
private lateinit var customCrossActivityBackAnimation: CustomCrossActivityBackAnimation
private lateinit var customAnimationLoader: CustomAnimationLoader
@@ -80,7 +82,8 @@
backAnimationBackground,
rootTaskDisplayAreaOrganizer,
transaction,
- customAnimationLoader
+ customAnimationLoader,
+ handler,
)
whenever(transitionAnimation.loadAppTransitionAnimation(eq(PACKAGE_NAME), eq(OPEN_RES_ID)))
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/OWNERS
new file mode 100644
index 0000000..983e878
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 555586
+# includes OWNERS from parent directories
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java
index f5847cc..cf69704 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/DividerViewTest.java
@@ -25,6 +25,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.os.Handler;
import android.os.SystemClock;
import android.provider.DeviceConfig;
import android.view.InputDevice;
@@ -55,6 +56,7 @@
private @Mock DisplayController mDisplayController;
private @Mock DisplayImeController mDisplayImeController;
private @Mock ShellTaskOrganizer mTaskOrganizer;
+ private @Mock Handler mHandler;
private SplitLayout mSplitLayout;
private DividerView mDividerView;
@@ -65,7 +67,7 @@
Configuration configuration = getConfiguration();
mSplitLayout = new SplitLayout("TestSplitLayout", mContext, configuration,
mSplitLayoutHandler, mCallbacks, mDisplayController, mDisplayImeController,
- mTaskOrganizer, SplitLayout.PARALLAX_NONE);
+ mTaskOrganizer, SplitLayout.PARALLAX_NONE, mHandler);
SplitWindowManager splitWindowManager = new SplitWindowManager("TestSplitWindowManager",
mContext,
configuration, mCallbacks);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index 82b3a7d..177e47a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -35,6 +35,7 @@
import android.app.ActivityManager;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.os.Handler;
import android.window.WindowContainerTransaction;
import androidx.test.annotation.UiThreadTest;
@@ -65,6 +66,7 @@
@Mock DisplayImeController mDisplayImeController;
@Mock ShellTaskOrganizer mTaskOrganizer;
@Mock WindowContainerTransaction mWct;
+ @Mock Handler mHandler;
@Captor ArgumentCaptor<Runnable> mRunnableCaptor;
private SplitLayout mSplitLayout;
@@ -80,7 +82,8 @@
mDisplayController,
mDisplayImeController,
mTaskOrganizer,
- SplitLayout.PARALLAX_NONE));
+ SplitLayout.PARALLAX_NONE,
+ mHandler));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/OWNERS
new file mode 100644
index 0000000..5b05af9
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 970984
+# includes OWNERS from parent directories
\ No newline at end of file
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 b47201e..8f20841 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
@@ -40,6 +40,7 @@
import android.graphics.PointF
import android.graphics.Rect
import android.os.Binder
+import android.os.Handler
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
@@ -181,6 +182,7 @@
private lateinit var mockInteractionJankMonitor: InteractionJankMonitor
@Mock private lateinit var mockSurface: SurfaceControl
@Mock private lateinit var taskbarDesktopTaskListener: TaskbarDesktopTaskListener
+ @Mock private lateinit var mockHandler: Handler
private lateinit var mockitoSession: StaticMockitoSession
private lateinit var controller: DesktopTasksController
@@ -221,7 +223,8 @@
shellTaskOrganizer,
MAX_TASK_LIMIT,
mockInteractionJankMonitor,
- mContext)
+ mContext,
+ mockHandler)
whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks }
whenever(transitions.startTransition(anyInt(), any(), isNull())).thenAnswer { Binder() }
@@ -274,7 +277,9 @@
shellExecutor,
Optional.of(desktopTasksLimiter),
recentTasksController,
- mockInteractionJankMonitor)
+ mockInteractionJankMonitor,
+ mockHandler,
+ )
}
@After
@@ -1759,6 +1764,37 @@
}
@Test
+ fun handleRequest_freeformTask_relaunchTask_enforceDesktop_freeformDisplay_noWinModeChange() {
+ assumeTrue(ENABLE_SHELL_TRANSITIONS)
+ whenever(DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context)).thenReturn(true)
+ val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!!
+ tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM
+
+ val freeformTask = setUpFreeformTask()
+ markTaskHidden(freeformTask)
+ val wct = controller.handleRequest(Binder(), createTransition(freeformTask))
+
+ assertNotNull(wct, "should handle request")
+ assertFalse(wct.anyWindowingModeChange(freeformTask.token))
+ }
+
+ @Test
+ fun handleRequest_freeformTask_relaunchTask_enforceDesktop_fullscreenDisplay_becomesUndefined() {
+ assumeTrue(ENABLE_SHELL_TRANSITIONS)
+ whenever(DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context)).thenReturn(true)
+ val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!!
+ tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
+
+ val freeformTask = setUpFreeformTask()
+ markTaskHidden(freeformTask)
+ val wct = controller.handleRequest(Binder(), createTransition(freeformTask))
+
+ assertNotNull(wct, "should handle request")
+ assertThat(wct.changes[freeformTask.token.asBinder()]?.windowingMode)
+ .isEqualTo(WINDOWING_MODE_UNDEFINED)
+ }
+
+ @Test
@DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
fun handleRequest_freeformTask_desktopWallpaperDisabled_freeformNotVisible_reorderedToTop() {
assumeTrue(ENABLE_SHELL_TRANSITIONS)
@@ -3488,6 +3524,14 @@
} ?: false
}
+private fun WindowContainerTransaction?.anyWindowingModeChange(
+ token: WindowContainerToken
+): Boolean {
+return this?.changes?.any { change ->
+ change.key == token.asBinder() && change.value.windowingMode >= 0
+} ?: false
+}
+
private fun createTaskInfo(id: Int) =
RecentTaskInfo().apply {
taskId = id
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
index 2d0e428..61d03ca 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
@@ -18,6 +18,7 @@
import android.app.ActivityManager.RunningTaskInfo
import android.os.Binder
+import android.os.Handler
import android.platform.test.flag.junit.SetFlagsRule
import android.testing.AndroidTestingRunner
import android.view.Display.DEFAULT_DISPLAY
@@ -70,6 +71,7 @@
@Mock lateinit var shellTaskOrganizer: ShellTaskOrganizer
@Mock lateinit var transitions: Transitions
@Mock lateinit var interactionJankMonitor: InteractionJankMonitor
+ @Mock lateinit var handler: Handler
private lateinit var mockitoSession: StaticMockitoSession
private lateinit var desktopTasksLimiter: DesktopTasksLimiter
@@ -85,7 +87,7 @@
desktopTasksLimiter =
DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, MAX_TASK_LIMIT,
- interactionJankMonitor, mContext)
+ interactionJankMonitor, mContext, handler)
}
@After
@@ -97,7 +99,7 @@
fun createDesktopTasksLimiter_withZeroLimit_shouldThrow() {
assertFailsWith<IllegalArgumentException> {
DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, 0,
- interactionJankMonitor, mContext)
+ interactionJankMonitor, mContext, handler)
}
}
@@ -105,7 +107,7 @@
fun createDesktopTasksLimiter_withNegativeLimit_shouldThrow() {
assertFailsWith<IllegalArgumentException> {
DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, -5,
- interactionJankMonitor, mContext)
+ interactionJankMonitor, mContext, handler)
}
}
@@ -334,7 +336,7 @@
fun getTaskToMinimizeIfNeeded_tasksAboveLimit_otherLimit_returnsBackTask() {
desktopTasksLimiter =
DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, MAX_TASK_LIMIT2,
- interactionJankMonitor, mContext)
+ interactionJankMonitor, mContext, handler)
val tasks = (1..MAX_TASK_LIMIT2 + 1).map { setUpFreeformTask() }
val minimizedTask = desktopTasksLimiter.getTaskToMinimizeIfNeeded(
@@ -375,6 +377,7 @@
verify(interactionJankMonitor).begin(
any(),
eq(mContext),
+ eq(handler),
eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW))
desktopTasksLimiter.getTransitionObserver().onTransitionFinished(
@@ -403,7 +406,9 @@
verify(interactionJankMonitor).begin(
any(),
eq(mContext),
- eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW))
+ eq(handler),
+ eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW),
+ )
desktopTasksLimiter.getTransitionObserver().onTransitionFinished(
transition,
@@ -432,6 +437,7 @@
verify(interactionJankMonitor).begin(
any(),
eq(mContext),
+ eq(handler),
eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW))
desktopTasksLimiter.getTransitionObserver().onTransitionMerged(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
index 497d0e5..d9387d2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
@@ -35,6 +35,7 @@
import java.util.function.Supplier
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -212,6 +213,60 @@
}
@Test
+ fun isHomeChange_withoutTaskInfo_returnsFalse() {
+ val change =
+ TransitionInfo.Change(mock(), homeTaskLeash).apply {
+ parent = null
+ taskInfo = null
+ }
+
+ assertFalse(defaultHandler.isHomeChange(change))
+ assertFalse(springHandler.isHomeChange(change))
+ }
+
+ @Test
+ fun isHomeChange_withStandardActivityTaskInfo_returnsFalse() {
+ val change =
+ TransitionInfo.Change(mock(), homeTaskLeash).apply {
+ parent = null
+ taskInfo =
+ TestRunningTaskInfoBuilder().setActivityType(ACTIVITY_TYPE_STANDARD).build()
+ }
+
+ assertFalse(defaultHandler.isHomeChange(change))
+ assertFalse(springHandler.isHomeChange(change))
+ }
+
+ @Test
+ fun isHomeChange_withHomeActivityTaskInfo_returnsTrue() {
+ val change =
+ TransitionInfo.Change(mock(), homeTaskLeash).apply {
+ parent = null
+ taskInfo = TestRunningTaskInfoBuilder().setActivityType(ACTIVITY_TYPE_HOME).build()
+ }
+
+ assertTrue(defaultHandler.isHomeChange(change))
+ assertTrue(springHandler.isHomeChange(change))
+ }
+
+ @Test
+ fun isHomeChange_withSingleTranslucentHomeActivityTaskInfo_returnsFalse() {
+ val change =
+ TransitionInfo.Change(mock(), homeTaskLeash).apply {
+ parent = null
+ taskInfo =
+ TestRunningTaskInfoBuilder()
+ .setActivityType(ACTIVITY_TYPE_HOME)
+ .setTopActivityTransparent(true)
+ .setNumActivities(1)
+ .build()
+ }
+
+ assertFalse(defaultHandler.isHomeChange(change))
+ assertFalse(springHandler.isHomeChange(change))
+ }
+
+ @Test
fun cancelDragToDesktop_startWasReady_cancel() {
startDrag(defaultHandler)
@@ -343,6 +398,8 @@
// Should show dragged task layer in start and finish transaction
verify(mergedStartTransaction).show(draggedTaskLeash)
verify(playingFinishTransaction).show(draggedTaskLeash)
+ // Should update the dragged task layer
+ verify(mergedStartTransaction).setLayer(eq(draggedTaskLeash), anyInt())
// Should merge animation
verify(finishCallback).onTransitionFinished(null)
}
@@ -373,6 +430,8 @@
// Should show dragged task layer in start and finish transaction
verify(mergedStartTransaction).show(draggedTaskLeash)
verify(playingFinishTransaction).show(draggedTaskLeash)
+ // Should update the dragged task layer
+ verify(mergedStartTransaction).setLayer(eq(draggedTaskLeash), anyInt())
// Should hide home task leash in finish transaction
verify(playingFinishTransaction).hide(homeTaskLeash)
// Should merge animation
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
index e0463b4..fefa933 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
@@ -34,6 +34,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
+import android.os.Handler;
import android.os.IBinder;
import android.util.DisplayMetrics;
import android.view.SurfaceControl;
@@ -81,6 +82,8 @@
Transitions.TransitionFinishCallback mTransitionFinishCallback;
@Mock
ShellExecutor mExecutor;
+ @Mock
+ Handler mHandler;
private Point mPoint;
private ExitDesktopTaskTransitionHandler mExitDesktopTaskTransitionHandler;
@@ -97,7 +100,7 @@
.thenReturn(getContext().getResources().getDisplayMetrics());
mExitDesktopTaskTransitionHandler = new ExitDesktopTaskTransitionHandler(mTransitions,
- mContext, mInteractionJankMonitor);
+ mContext, mInteractionJankMonitor, mHandler);
mPoint = new Point(0, 0);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/OWNERS
new file mode 100644
index 0000000..553540c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 929241
+# includes OWNERS from parent directories
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/WindowDecorCaptionHandleRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/WindowDecorCaptionHandleRepositoryTest.kt
new file mode 100644
index 0000000..e3caf2e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/WindowDecorCaptionHandleRepositoryTest.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED
+import android.graphics.Rect
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class WindowDecorCaptionHandleRepositoryTest {
+ private lateinit var captionHandleRepository: WindowDecorCaptionHandleRepository
+
+ @Before
+ fun setUp() {
+ captionHandleRepository = WindowDecorCaptionHandleRepository()
+ }
+
+ @Test
+ fun initialState_noAction_returnsNoCaption() {
+ // Check the initial value of `captionStateFlow`.
+ assertThat(captionHandleRepository.captionStateFlow.value).isEqualTo(CaptionState.NoCaption)
+ }
+
+ @Test
+ fun notifyCaptionChange_toAppHandleVisible_updatesStateWithCorrectData() {
+ val taskInfo = createTaskInfo(WINDOWING_MODE_FULLSCREEN, GMAIL_PACKAGE_NAME)
+ val appHandleCaptionState =
+ CaptionState.AppHandle(
+ taskInfo, false, Rect(/* left= */ 0, /* top= */ 1, /* right= */ 2, /* bottom= */ 3))
+
+ captionHandleRepository.notifyCaptionChanged(appHandleCaptionState)
+
+ assertThat(captionHandleRepository.captionStateFlow.value).isEqualTo(appHandleCaptionState)
+ }
+
+ @Test
+ fun notifyCaptionChange_toAppChipVisible_updatesStateWithCorrectData() {
+ val taskInfo = createTaskInfo(WINDOWING_MODE_FREEFORM, GMAIL_PACKAGE_NAME)
+ val appHeaderCaptionState =
+ CaptionState.AppHeader(
+ taskInfo, true, Rect(/* left= */ 0, /* top= */ 1, /* right= */ 2, /* bottom= */ 3))
+
+ captionHandleRepository.notifyCaptionChanged(appHeaderCaptionState)
+
+ assertThat(captionHandleRepository.captionStateFlow.value).isEqualTo(appHeaderCaptionState)
+ }
+
+ @Test
+ fun notifyCaptionChange_toNoCaption_updatesState() {
+ captionHandleRepository.notifyCaptionChanged(CaptionState.NoCaption)
+
+ assertThat(captionHandleRepository.captionStateFlow.value).isEqualTo(CaptionState.NoCaption)
+ }
+
+ private fun createTaskInfo(
+ deviceWindowingMode: Int = WINDOWING_MODE_UNDEFINED,
+ runningTaskPackageName: String = LAUNCHER_PACKAGE_NAME
+ ): RunningTaskInfo =
+ RunningTaskInfo().apply {
+ configuration.windowConfiguration.apply { windowingMode = deviceWindowingMode }
+ topActivityInfo?.apply { packageName = runningTaskPackageName }
+ }
+
+ private companion object {
+ const val GMAIL_PACKAGE_NAME = "com.google.android.gm"
+ const val LAUNCHER_PACKAGE_NAME = "com.google.android.apps.nexuslauncher"
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/OWNERS
new file mode 100644
index 0000000..cb12401
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 1214056
+# includes OWNERS from parent directories
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/OWNERS
new file mode 100644
index 0000000..553540c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 929241
+# includes OWNERS from parent directories
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OWNERS
new file mode 100644
index 0000000..b66cfc3
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 785166
+# includes OWNERS from parent directories
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
index 9c7f723..9146906 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
@@ -37,6 +37,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
+import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Display;
@@ -100,6 +101,8 @@
OneHandedSettingsUtil mMockSettingsUitl;
@Mock
InteractionJankMonitor mJankMonitor;
+ @Mock
+ Handler mMockHandler;
List<DisplayAreaAppearedInfo> mDisplayAreaAppearedInfoList = new ArrayList<>();
@@ -142,7 +145,8 @@
mMockAnimationController,
mTutorialHandler,
mJankMonitor,
- mMockShellMainExecutor));
+ mMockShellMainExecutor,
+ mMockHandler));
for (int i = 0; i < DISPLAYAREA_INFO_COUNT; i++) {
mDisplayAreaAppearedInfoList.add(getDummyDisplayAreaInfo());
@@ -429,7 +433,8 @@
mMockAnimationController,
mTutorialHandler,
mJankMonitor,
- mMockShellMainExecutor));
+ mMockShellMainExecutor,
+ mMockHandler));
assertThat(testSpiedDisplayAreaOrganizer.isReady()).isFalse();
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/OWNERS
new file mode 100644
index 0000000..ad3ca73
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 316251
+# includes OWNERS from parent directories
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index f3944d5..9600351 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -40,6 +40,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
+import android.os.Handler;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -115,6 +116,7 @@
@Mock private PipParamsChangedForwarder mMockPipParamsChangedForwarder;
@Mock private DisplayInsetsController mMockDisplayInsetsController;
@Mock private TabletopModeController mMockTabletopModeController;
+ @Mock private Handler mMockHandler;
@Mock private DisplayLayout mMockDisplayLayout1;
@Mock private DisplayLayout mMockDisplayLayout2;
@@ -138,7 +140,7 @@
mMockPipTransitionController, mMockWindowManagerShellWrapper,
mMockTaskStackListener, mMockPipParamsChangedForwarder,
mMockDisplayInsetsController, mMockTabletopModeController,
- mMockOneHandedController, mMockExecutor);
+ mMockOneHandedController, mMockExecutor, mMockHandler);
mShellInit.init();
when(mMockPipBoundsAlgorithm.getSnapAlgorithm()).thenReturn(mMockPipSnapAlgorithm);
when(mMockPipTouchHandler.getMotionHelper()).thenReturn(mMockPipMotionHelper);
@@ -230,7 +232,7 @@
mMockPipTransitionController, mMockWindowManagerShellWrapper,
mMockTaskStackListener, mMockPipParamsChangedForwarder,
mMockDisplayInsetsController, mMockTabletopModeController,
- mMockOneHandedController, mMockExecutor));
+ mMockOneHandedController, mMockExecutor, mMockHandler));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/OWNERS
new file mode 100644
index 0000000..ad3ca73
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 316251
+# includes OWNERS from parent directories
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/OWNERS
new file mode 100644
index 0000000..aa019cc
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 1199235
+# includes OWNERS from parent directories
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
index bc9b44e..0e5efa6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
@@ -18,7 +18,6 @@
import android.app.ActivityManager
import android.app.WindowConfiguration
-import android.content.Context
import android.os.IBinder
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
@@ -60,7 +59,6 @@
@JvmField @Rule val setFlagsRule = SetFlagsRule()
- @Mock private lateinit var context: Context
@Mock private lateinit var shellInit: ShellInit
@Mock lateinit var testExecutor: ShellExecutor
@Mock private lateinit var transitionsLazy: Lazy<Transitions>
@@ -74,7 +72,7 @@
MockitoAnnotations.initMocks(this)
shellInit = Mockito.spy(ShellInit(testExecutor))
whenever(transitionsLazy.get()).thenReturn(transitions)
- transitionObserver = TaskStackTransitionObserver(context, transitionsLazy, shellInit)
+ transitionObserver = TaskStackTransitionObserver(transitionsLazy, shellInit)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java)
verify(shellInit)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt
deleted file mode 100644
index 571bdd4..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt
+++ /dev/null
@@ -1,347 +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.wm.shell.shared.desktopmode
-
-import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
-import android.platform.test.flag.junit.SetFlagsRule
-import android.provider.Settings
-import android.testing.AndroidTestingRunner
-import androidx.test.filters.SmallTest
-import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
-import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY
-import com.android.window.flags.Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION
-import com.android.wm.shell.ShellTestCase
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags.Companion.convertToToggleOverrideWithFallback
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags.ToggleOverride.OVERRIDE_OFF
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags.ToggleOverride.OVERRIDE_ON
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags.ToggleOverride.OVERRIDE_UNSET
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY
-import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/**
- * Test class for [DesktopModeFlags]
- *
- * Usage: atest WMShellUnitTests:DesktopModeFlagsTest
- */
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-class DesktopModeFlagsTest : ShellTestCase() {
-
- @JvmField @Rule val setFlagsRule = SetFlagsRule()
-
- @After
- fun tearDown() {
- resetToggleOverrideCache()
- }
-
- // TODO(b/348193756): Add tests
- // isEnabled_flagNotOverridable_overrideOff_featureFlagOn_returnsTrue and
- // isEnabled_flagNotOverridable_overrideOn_featureFlagOff_returnsFalse after adding non
- // overridable flags to DesktopModeFlags.
-
- @Test
- @DisableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
- @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_devOptionFlagDisabled_overrideOff_featureFlagOn_returnsTrue() {
- setOverride(OVERRIDE_OFF.setting)
-
- // In absence of dev options, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
- }
-
- @Test
- @DisableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_devOptionFlagDisabled_overrideOn_featureFlagOff_returnsFalse() {
- setOverride(OVERRIDE_ON.setting)
-
- // In absence of dev options, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
- }
-
- @Test
- @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_overrideUnset_featureFlagOn_returnsTrue() {
- setOverride(OVERRIDE_UNSET.setting)
-
- // For overridableFlag, for unset overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
- }
-
- @Test
- @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
- @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_overrideUnset_featureFlagOff_returnsFalse() {
- setOverride(OVERRIDE_UNSET.setting)
-
- // For overridableFlag, for unset overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
- }
-
- @Test
- @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_noOverride_featureFlagOn_returnsTrue() {
- setOverride(null)
-
- // For overridableFlag, in absence of overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
- }
-
- @Test
- @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
- @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_noOverride_featureFlagOff_returnsFalse() {
- setOverride(null)
-
- // For overridableFlag, in absence of overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
- }
-
- @Test
- @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_unrecognizableOverride_featureFlagOn_returnsTrue() {
- setOverride(-2)
-
- // For overridableFlag, for recognizable overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
- }
-
- @Test
- @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
- @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_unrecognizableOverride_featureFlagOff_returnsFalse() {
- setOverride(-2)
-
- // For overridableFlag, for recognizable overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
- }
-
- @Test
- @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_overrideOff_featureFlagOn_returnsFalse() {
- setOverride(OVERRIDE_OFF.setting)
-
- // For overridableFlag, follow override if they exist
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
- }
-
- @Test
- @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
- @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_overrideOn_featureFlagOff_returnsTrue() {
- setOverride(OVERRIDE_ON.setting)
-
- // For overridableFlag, follow override if they exist
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
- }
-
- @Test
- @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_overrideOffThenOn_featureFlagOn_returnsFalseAndFalse() {
- setOverride(OVERRIDE_OFF.setting)
-
- // For overridableFlag, follow override if they exist
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
-
- setOverride(OVERRIDE_ON.setting)
-
- // Keep overrides constant through the process
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
- }
-
- @Test
- @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
- @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_overrideOnThenOff_featureFlagOff_returnsTrueAndTrue() {
- setOverride(OVERRIDE_ON.setting)
-
- // For overridableFlag, follow override if they exist
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
-
- setOverride(OVERRIDE_OFF.setting)
-
- // Keep overrides constant through the process
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
- }
-
- @Test
- @EnableFlags(
- FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION,
- FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
- FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
- fun isEnabled_dwFlagEnabled_overrideUnset_featureFlagOn_returnsTrue() {
- setOverride(OVERRIDE_UNSET.setting)
-
- // For unset overrides, follow flag
- assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue()
- }
-
- @Test
- @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
- fun isEnabled_dwFlagEnabled_overrideUnset_featureFlagOff_returnsFalse() {
- setOverride(OVERRIDE_UNSET.setting)
-
- // For unset overrides, follow flag
- assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse()
- }
-
- @Test
- @EnableFlags(
- FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION,
- FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
- FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
- fun isEnabled_dwFlagEnabled_overrideOn_featureFlagOn_returnsTrue() {
- setOverride(OVERRIDE_ON.setting)
-
- // When toggle override matches its default state (dw flag), don't override flags
- assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue()
- }
-
- @Test
- @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
- fun isEnabled_dwFlagEnabled_overrideOn_featureFlagOff_returnFalse() {
- setOverride(OVERRIDE_ON.setting)
-
- // When toggle override matches its default state (dw flag), don't override flags
- assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse()
- }
-
- @Test
- @EnableFlags(
- FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION,
- FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
- FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
- fun isEnabled_dwFlagEnabled_overrideOff_featureFlagOn_returnsFalse() {
- setOverride(OVERRIDE_OFF.setting)
-
- // Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse()
- }
-
- @Test
- @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
- fun isEnabled_dwFlagEnabled_overrideOff_featureFlagOff_returnsFalse() {
- setOverride(OVERRIDE_OFF.setting)
-
- // Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse()
- }
-
- @Test
- @EnableFlags(
- FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
- @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_dwFlagDisabled_overrideUnset_featureFlagOn_returnsTrue() {
- setOverride(OVERRIDE_UNSET.setting)
-
- // For unset overrides, follow flag
- assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue()
- }
-
- @Test
- @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
- @DisableFlags(
- FLAG_ENABLE_DESKTOP_WINDOWING_MODE, FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
- fun isEnabled_dwFlagDisabled_overrideUnset_featureFlagOff_returnsFalse() {
- setOverride(OVERRIDE_UNSET.setting)
-
- // For unset overrides, follow flag
- assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse()
- }
-
- @Test
- @EnableFlags(
- FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
- @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_dwFlagDisabled_overrideOn_featureFlagOn_returnsTrue() {
- setOverride(OVERRIDE_ON.setting)
-
- // Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue()
- }
-
- @Test
- @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
- @DisableFlags(
- FLAG_ENABLE_DESKTOP_WINDOWING_MODE, FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
- fun isEnabled_dwFlagDisabled_overrideOn_featureFlagOff_returnTrue() {
- setOverride(OVERRIDE_ON.setting)
-
- // Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue()
- }
-
- @Test
- @EnableFlags(
- FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
- @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_dwFlagDisabled_overrideOff_featureFlagOn_returnsTrue() {
- setOverride(OVERRIDE_OFF.setting)
-
- // When toggle override matches its default state (dw flag), don't override flags
- assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue()
- }
-
- @Test
- @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
- @DisableFlags(
- FLAG_ENABLE_DESKTOP_WINDOWING_MODE, FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
- fun isEnabled_dwFlagDisabled_overrideOff_featureFlagOff_returnsFalse() {
- setOverride(OVERRIDE_OFF.setting)
-
- // When toggle override matches its default state (dw flag), don't override flags
- assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse()
- }
-
- @Test
- fun convertToToggleOverrideWithFallback_validInt_returnsToggleOverride() {
- assertThat(convertToToggleOverrideWithFallback(0, OVERRIDE_UNSET)).isEqualTo(OVERRIDE_OFF)
- assertThat(convertToToggleOverrideWithFallback(1, OVERRIDE_UNSET)).isEqualTo(OVERRIDE_ON)
- assertThat(convertToToggleOverrideWithFallback(-1, OVERRIDE_ON)).isEqualTo(OVERRIDE_UNSET)
- }
-
- @Test
- fun convertToToggleOverrideWithFallback_invalidInt_returnsFallback() {
- assertThat(convertToToggleOverrideWithFallback(2, OVERRIDE_ON)).isEqualTo(OVERRIDE_ON)
- assertThat(convertToToggleOverrideWithFallback(-2, OVERRIDE_UNSET)).isEqualTo(OVERRIDE_UNSET)
- }
-
- private fun setOverride(setting: Int?) {
- val contentResolver = mContext.contentResolver
- val key = Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES
- if (setting == null) {
- Settings.Global.putString(contentResolver, key, null)
- } else {
- Settings.Global.putInt(contentResolver, key, setting)
- }
- }
-
- private fun resetToggleOverrideCache() {
- val cachedToggleOverride =
- DesktopModeFlags::class.java.getDeclaredField("cachedToggleOverride")
- cachedToggleOverride.isAccessible = true
- cachedToggleOverride.set(null, null)
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/OWNERS
deleted file mode 100644
index 2fabd4a..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file:/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/OWNERS
new file mode 100644
index 0000000..9d926b2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 928697
+# includes OWNERS from parent directories
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/OWNERS
new file mode 100644
index 0000000..a24088a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 316275
+# includes OWNERS from parent directories
\ No newline at end of file
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 fec9e3e..aea14b9 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
@@ -332,6 +332,35 @@
}
@Test
+ public void testTransitionFilterTaskFragmentToken() {
+ final IBinder taskFragmentToken = new Binder();
+
+ TransitionFilter filter = new TransitionFilter();
+ filter.mRequirements =
+ new TransitionFilter.Requirement[]{new TransitionFilter.Requirement()};
+ filter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+ filter.mRequirements[0].mTaskFragmentToken = taskFragmentToken;
+
+ // Transition with the same token should match.
+ final TransitionInfo infoHasTaskFragmentToken = new TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(TRANSIT_OPEN, taskFragmentToken).build();
+ assertTrue(filter.matches(infoHasTaskFragmentToken));
+
+ // Transition with a different token should not match.
+ final IBinder differentTaskFragmentToken = new Binder();
+ final TransitionInfo infoDifferentTaskFragmentToken =
+ new TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(TRANSIT_OPEN, differentTaskFragmentToken).build();
+ assertFalse(filter.matches(infoDifferentTaskFragmentToken));
+
+ // Transition without a token should not match.
+ final TransitionInfo infoNoTaskFragmentToken = new TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(TRANSIT_OPEN, createTaskInfo(
+ 1, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD)).build();
+ assertFalse(filter.matches(infoNoTaskFragmentToken));
+ }
+
+ @Test
public void testTransitionFilterMultiRequirement() {
// filter that requires at-least one opening and one closing app
TransitionFilter filter = new TransitionFilter();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/TransitionInfoBuilder.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/TransitionInfoBuilder.java
index b8939e6f..49ae182 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/TransitionInfoBuilder.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/TransitionInfoBuilder.java
@@ -20,8 +20,10 @@
import static org.mockito.Mockito.mock;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.ComponentName;
+import android.os.IBinder;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
@@ -51,21 +53,24 @@
}
public TransitionInfoBuilder addChange(@WindowManager.TransitionType int mode,
- @TransitionInfo.ChangeFlags int flags, ActivityManager.RunningTaskInfo taskInfo,
- ComponentName activityComponent) {
+ @TransitionInfo.ChangeFlags int flags,
+ @Nullable ActivityManager.RunningTaskInfo taskInfo,
+ @Nullable ComponentName activityComponent, @Nullable IBinder taskFragmentToken) {
final TransitionInfo.Change change = new TransitionInfo.Change(
taskInfo != null ? taskInfo.token : null, createMockSurface(true /* valid */));
change.setMode(mode);
change.setFlags(flags);
change.setTaskInfo(taskInfo);
change.setActivityComponent(activityComponent);
+ change.setTaskFragmentToken(taskFragmentToken);
return addChange(change);
}
/** Add a change to the TransitionInfo */
public TransitionInfoBuilder addChange(@WindowManager.TransitionType int mode,
@TransitionInfo.ChangeFlags int flags, ActivityManager.RunningTaskInfo taskInfo) {
- return addChange(mode, flags, taskInfo, null /* activityComponent */);
+ return addChange(mode, flags, taskInfo, null /* activityComponent */,
+ null /* taskFragmentToken */);
}
public TransitionInfoBuilder addChange(@WindowManager.TransitionType int mode,
@@ -76,13 +81,21 @@
/** Add a change to the TransitionInfo */
public TransitionInfoBuilder addChange(@WindowManager.TransitionType int mode,
ComponentName activityComponent) {
- return addChange(mode, TransitionInfo.FLAG_NONE, null /* taskinfo */, activityComponent);
+ return addChange(mode, TransitionInfo.FLAG_NONE, null /* taskinfo */, activityComponent,
+ null /* taskFragmentToken */);
}
public TransitionInfoBuilder addChange(@WindowManager.TransitionType int mode) {
return addChange(mode, TransitionInfo.FLAG_NONE, null /* taskInfo */);
}
+ /** Add a change with a TaskFragment token to the TransitionInfo */
+ public TransitionInfoBuilder addChange(@WindowManager.TransitionType int mode,
+ @Nullable IBinder taskFragmentToken) {
+ return addChange(mode, TransitionInfo.FLAG_NONE, null /* taskInfo */,
+ null /* activityComponent */, taskFragmentToken);
+ }
+
public TransitionInfoBuilder addChange(TransitionInfo.Change change) {
change.setDisplayId(DISPLAY_ID, DISPLAY_ID);
mInfo.addChange(change);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/OWNERS
new file mode 100644
index 0000000..f5ba614
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 1267635
+# includes OWNERS from parent directories
\ No newline at end of file
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 a18fbf0..ee2a41c 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
@@ -88,6 +88,7 @@
import com.android.wm.shell.desktopmode.DesktopTasksController
import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition
import com.android.wm.shell.desktopmode.DesktopTasksLimiter
+import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
@@ -98,6 +99,7 @@
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeKeyguardChangeListener
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener
+import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder
import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier
import java.util.Optional
import java.util.function.Consumer
@@ -164,6 +166,7 @@
DesktopModeWindowDecorViewModel.InputMonitorFactory
@Mock private lateinit var mockShellController: ShellController
@Mock private lateinit var mockShellExecutor: ShellExecutor
+ @Mock private lateinit var mockAppHeaderViewHolderFactory: AppHeaderViewHolder.Factory
@Mock private lateinit var mockRootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
@Mock private lateinit var mockShellCommandHandler: ShellCommandHandler
@Mock private lateinit var mockWindowManager: IWindowManager
@@ -182,6 +185,7 @@
@Mock private lateinit var mockTaskPositionerFactory:
DesktopModeWindowDecorViewModel.TaskPositionerFactory
@Mock private lateinit var mockTaskPositioner: TaskPositioner
+ @Mock private lateinit var mockCaptionHandleRepository: WindowDecorCaptionHandleRepository
@Mock private lateinit var mockWindowDecorViewHostSupplier: WindowDecorViewHostSupplier<*>
private lateinit var spyContext: TestableContext
@@ -236,10 +240,12 @@
mockDesktopModeWindowDecorFactory,
mockInputMonitorFactory,
transactionFactory,
+ mockAppHeaderViewHolderFactory,
mockRootTaskDisplayAreaOrganizer,
windowDecorByTaskIdSpy,
mockInteractionJankMonitor,
Optional.of(mockTasksLimiter),
+ mockCaptionHandleRepository,
Optional.of(mockActivityOrientationChangeHandler),
mockTaskPositionerFactory
)
@@ -247,7 +253,18 @@
whenever(mockDisplayController.getDisplayLayout(any())).thenReturn(mockDisplayLayout)
whenever(mockDisplayLayout.stableInsets()).thenReturn(STABLE_INSETS)
whenever(mockInputMonitorFactory.create(any(), any())).thenReturn(mockInputMonitor)
- whenever(mockTaskPositionerFactory.create(any(), any(), any(), any(), any(), any(), any()))
+ whenever(
+ mockTaskPositionerFactory.create(
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any()
+ )
+ )
.thenReturn(mockTaskPositioner)
doReturn(mockToast).`when` { Toast.makeText(any(), anyInt(), anyInt()) }
@@ -1200,7 +1217,7 @@
whenever(
mockDesktopModeWindowDecorFactory.create(
any(), any(), any(), any(), any(), eq(task), any(), any(), any(), any(), any(),
- any(), any(), any(), any(), any())
+ any(), any(), any(), any(), any(), any(), any())
).thenReturn(decoration)
decoration.mTaskInfo = task
whenever(decoration.isFocused).thenReturn(task.isFocused)
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 dff42da..a1867f3 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
@@ -19,9 +19,11 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
import static android.view.InsetsSource.FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR;
+import static android.view.WindowInsets.Type.statusBars;
import static android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
@@ -38,6 +40,7 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -55,6 +58,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.PointF;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.Handler;
import android.os.SystemProperties;
@@ -68,11 +72,13 @@
import android.view.Choreographer;
import android.view.Display;
import android.view.GestureDetector;
+import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
import android.view.View;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.window.WindowContainerTransaction;
@@ -94,9 +100,12 @@
import com.android.wm.shell.common.MultiInstanceHelper;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.desktopmode.CaptionState;
+import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams;
+import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;
import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHost;
import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
@@ -153,6 +162,10 @@
@Mock
private SyncTransactionQueue mMockSyncQueue;
@Mock
+ private AppHeaderViewHolder.Factory mMockAppHeaderViewHolderFactory;
+ @Mock
+ private AppHeaderViewHolder mMockAppHeaderViewHolder;
+ @Mock
private RootTaskDisplayAreaOrganizer mMockRootTaskDisplayAreaOrganizer;
@Mock
private Supplier<SurfaceControl.Transaction> mMockTransactionSupplier;
@@ -192,6 +205,8 @@
private HandleMenuFactory mMockHandleMenuFactory;
@Mock
private MultiInstanceHelper mMockMultiInstanceHelper;
+ @Mock
+ private WindowDecorCaptionHandleRepository mMockCaptionHandleRepository;
@Captor
private ArgumentCaptor<Function1<Boolean, Unit>> mOnMaxMenuHoverChangeListener;
@Captor
@@ -245,6 +260,8 @@
when(mMockWindowDecorViewHostSupplier.acquire(any(), eq(defaultDisplay)))
.thenReturn(mMockWindowDecorViewHost);
when(mMockWindowDecorViewHost.getSurfaceControl()).thenReturn(mock(SurfaceControl.class));
+ when(mMockAppHeaderViewHolderFactory.create(any(), any(), any(), any(), any(), any(), any(),
+ any())).thenReturn(mMockAppHeaderViewHolder);
}
@After
@@ -838,6 +855,143 @@
assertFalse(decoration.isHandleMenuActive());
}
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
+ public void notifyCaptionStateChanged_flagDisabled_doNoNotify() {
+ when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ when(mMockDisplayController.getInsetsState(taskInfo.displayId))
+ .thenReturn(createInsetsState(statusBars(), /* visible= */true));
+ final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ spyWindowDecor.relayout(taskInfo);
+
+ verify(mMockCaptionHandleRepository, never()).notifyCaptionChanged(any());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
+ public void notifyCaptionStateChanged_inFullscreenMode_notifiesAppHandleVisible() {
+ when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ when(mMockDisplayController.getInsetsState(taskInfo.displayId))
+ .thenReturn(createInsetsState(statusBars(), /* visible= */true));
+ final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
+ CaptionState.class);
+
+ spyWindowDecor.relayout(taskInfo);
+
+ verify(mMockCaptionHandleRepository, atLeastOnce()).notifyCaptionChanged(
+ captionStateArgumentCaptor.capture());
+ assertThat(captionStateArgumentCaptor.getValue()).isInstanceOf(
+ CaptionState.AppHandle.class);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
+ @Ignore("TODO(b/367235906): Due to MONITOR_INPUT permission error")
+ public void notifyCaptionStateChanged_inWindowingMode_notifiesAppHeaderVisible() {
+ when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ when(mMockDisplayController.getInsetsState(taskInfo.displayId))
+ .thenReturn(createInsetsState(statusBars(), /* visible= */true));
+ when(mMockAppHeaderViewHolder.getAppChipLocationInWindow()).thenReturn(
+ new Rect(/* left= */ 0, /* top= */ 1, /* right= */ 2, /* bottom= */ 3));
+ final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ // Make non-resizable to avoid dealing with input-permissions (MONITOR_INPUT)
+ taskInfo.isResizeable = false;
+ ArgumentCaptor<Function0<Unit>> runnableArgumentCaptor = ArgumentCaptor.forClass(
+ Function0.class);
+ ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
+ CaptionState.class);
+
+ spyWindowDecor.relayout(taskInfo);
+ verify(mMockAppHeaderViewHolder, atLeastOnce()).runOnAppChipGlobalLayout(
+ runnableArgumentCaptor.capture());
+ runnableArgumentCaptor.getValue().invoke();
+
+ verify(mMockCaptionHandleRepository, atLeastOnce()).notifyCaptionChanged(
+ captionStateArgumentCaptor.capture());
+ assertThat(captionStateArgumentCaptor.getValue()).isInstanceOf(
+ CaptionState.AppHeader.class);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
+ public void notifyCaptionStateChanged_taskNotVisible_notifiesNoCaptionVisible() {
+ when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ false);
+ when(mMockDisplayController.getInsetsState(taskInfo.displayId))
+ .thenReturn(createInsetsState(statusBars(), /* visible= */true));
+ final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_UNDEFINED);
+ ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
+ CaptionState.class);
+
+ spyWindowDecor.relayout(taskInfo);
+
+ verify(mMockCaptionHandleRepository, atLeastOnce()).notifyCaptionChanged(
+ captionStateArgumentCaptor.capture());
+ assertThat(captionStateArgumentCaptor.getValue()).isInstanceOf(
+ CaptionState.NoCaption.class);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
+ public void notifyCaptionStateChanged_captionHandleExpanded_notifiesHandleMenuExpanded() {
+ when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ when(mMockDisplayController.getInsetsState(taskInfo.displayId))
+ .thenReturn(createInsetsState(statusBars(), /* visible= */true));
+ final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
+ CaptionState.class);
+
+ spyWindowDecor.relayout(taskInfo);
+ createHandleMenu(spyWindowDecor);
+
+ verify(mMockCaptionHandleRepository, atLeastOnce()).notifyCaptionChanged(
+ captionStateArgumentCaptor.capture());
+ assertThat(captionStateArgumentCaptor.getValue()).isInstanceOf(
+ CaptionState.AppHandle.class);
+ assertThat(
+ ((CaptionState.AppHandle) captionStateArgumentCaptor.getValue())
+ .isHandleMenuExpanded()).isEqualTo(
+ true);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
+ public void notifyCaptionStateChanged_captionHandleClosed_notifiesHandleMenuClosed() {
+ when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ when(mMockDisplayController.getInsetsState(taskInfo.displayId))
+ .thenReturn(createInsetsState(statusBars(), /* visible= */true));
+ final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
+ CaptionState.class);
+
+ spyWindowDecor.relayout(taskInfo);
+ createHandleMenu(spyWindowDecor);
+ spyWindowDecor.closeHandleMenu();
+
+ verify(mMockCaptionHandleRepository, atLeastOnce()).notifyCaptionChanged(
+ captionStateArgumentCaptor.capture());
+ assertThat(captionStateArgumentCaptor.getValue()).isInstanceOf(
+ CaptionState.AppHandle.class);
+ assertThat(
+ ((CaptionState.AppHandle) captionStateArgumentCaptor.getValue())
+ .isHandleMenuExpanded()).isEqualTo(
+ false);
+
+ }
+
private void verifyHandleMenuCreated(@Nullable Uri uri) {
verify(mMockHandleMenuFactory).create(any(), any(), anyInt(), any(), any(),
any(), anyBoolean(), anyBoolean(), anyBoolean(), eq(uri), anyInt(),
@@ -906,12 +1060,13 @@
final DesktopModeWindowDecoration windowDecor = new DesktopModeWindowDecoration(mContext,
mContext, mMockDisplayController, mMockSplitScreenController,
mMockShellTaskOrganizer, taskInfo, mMockSurfaceControl, mMockHandler, mBgExecutor,
- mMockChoreographer, mMockSyncQueue, mMockRootTaskDisplayAreaOrganizer,
+ mMockChoreographer, mMockSyncQueue, mMockAppHeaderViewHolderFactory,
+ mMockRootTaskDisplayAreaOrganizer,
mMockGenericLinksParser, mMockAssistContentRequester, SurfaceControl.Builder::new,
mMockTransactionSupplier, WindowContainerTransaction::new, SurfaceControl::new,
new WindowManagerWrapper(mMockWindowManager), mMockSurfaceControlViewHostFactory,
mMockWindowDecorViewHostSupplier, maximizeMenuFactory, mMockHandleMenuFactory,
- mMockMultiInstanceHelper);
+ mMockMultiInstanceHelper, mMockCaptionHandleRepository);
windowDecor.setCaptionListeners(mMockTouchEventListener, mMockTouchEventListener,
mMockTouchEventListener, mMockTouchEventListener);
windowDecor.setExclusionRegionListener(mMockExclusionRegionListener);
@@ -951,6 +1106,14 @@
!= 0;
}
+ private InsetsState createInsetsState(@WindowInsets.Type.InsetsType int type, boolean visible) {
+ final InsetsState state = new InsetsState();
+ final InsetsSource source = new InsetsSource(/* id= */0, type);
+ source.setVisible(visible);
+ state.addSource(source);
+ return state;
+ }
+
private static class TestTouchEventListener extends GestureDetector.SimpleOnGestureListener
implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener,
View.OnGenericMotionListener, DragDetector.MotionEventHandler {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt
index 56224b4..7f7211d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt
@@ -21,6 +21,7 @@
import android.view.MotionEvent
import android.view.InputDevice
import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -34,6 +35,7 @@
import org.mockito.Mockito.argThat
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
+import org.mockito.kotlin.times
/**
* Tests for [DragDetector].
@@ -43,22 +45,17 @@
*/
@SmallTest
@RunWith(AndroidTestingRunner::class)
-class DragDetectorTest {
+class DragDetectorTest : ShellTestCase() {
private val motionEvents = mutableListOf<MotionEvent>()
@Mock
private lateinit var eventHandler: DragDetector.MotionEventHandler
- private lateinit var dragDetector: DragDetector
-
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
`when`(eventHandler.handleMotionEvent(any(), any())).thenReturn(true)
-
- dragDetector = DragDetector(eventHandler)
- dragDetector.setTouchSlop(SLOP)
}
@After
@@ -71,6 +68,7 @@
@Test
fun testNoMove_passesDownAndUp() {
+ val dragDetector = createDragDetector()
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_DOWN)))
verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_DOWN && it.x == X && it.y == Y &&
@@ -86,6 +84,7 @@
@Test
fun testNoMove_mouse_passesDownAndUp() {
+ val dragDetector = createDragDetector()
assertTrue(dragDetector.onMotionEvent(
createMotionEvent(MotionEvent.ACTION_DOWN, isTouch = false)))
verify(eventHandler).handleMotionEvent(any(), argThat {
@@ -103,6 +102,7 @@
@Test
fun testMoveInSlop_touch_passesDownAndUp() {
+ val dragDetector = createDragDetector()
`when`(eventHandler.handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_DOWN
})).thenReturn(false)
@@ -129,6 +129,7 @@
@Test
fun testMoveInSlop_mouse_passesDownMoveAndUp() {
+ val dragDetector = createDragDetector()
`when`(eventHandler.handleMotionEvent(any(), argThat {
it.action == MotionEvent.ACTION_DOWN
})).thenReturn(false)
@@ -158,6 +159,7 @@
@Test
fun testMoveBeyondSlop_passesDownMoveAndUp() {
+ val dragDetector = createDragDetector()
`when`(eventHandler.handleMotionEvent(any(), argThat {
it.action == MotionEvent.ACTION_DOWN
})).thenReturn(false)
@@ -184,6 +186,7 @@
@Test
fun testDownMoveDown_shouldIgnoreTheSecondDownMotion() {
+ val dragDetector = createDragDetector()
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_DOWN)))
verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_DOWN && it.x == X && it.y == Y &&
@@ -206,6 +209,7 @@
@Test
fun testDownMouseMoveDownTouch_shouldIgnoreTheTouchDownMotion() {
+ val dragDetector = createDragDetector()
assertTrue(dragDetector.onMotionEvent(
createMotionEvent(MotionEvent.ACTION_DOWN, isTouch = false)))
verify(eventHandler).handleMotionEvent(any(), argThat {
@@ -230,6 +234,7 @@
@Test
fun testPassesHoverEnter() {
+ val dragDetector = createDragDetector()
`when`(eventHandler.handleMotionEvent(any(), argThat {
it.action == MotionEvent.ACTION_HOVER_ENTER
})).thenReturn(false)
@@ -242,6 +247,7 @@
@Test
fun testPassesHoverMove() {
+ val dragDetector = createDragDetector()
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_HOVER_MOVE)))
verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_HOVER_MOVE && it.x == X && it.y == Y
@@ -250,21 +256,240 @@
@Test
fun testPassesHoverExit() {
+ val dragDetector = createDragDetector()
assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_HOVER_EXIT)))
verify(eventHandler).handleMotionEvent(any(), argThat {
return@argThat it.action == MotionEvent.ACTION_HOVER_EXIT && it.x == X && it.y == Y
})
}
- private fun createMotionEvent(action: Int, x: Float = X, y: Float = Y, isTouch: Boolean = true):
- MotionEvent {
- val time = SystemClock.uptimeMillis()
- val ev = MotionEvent.obtain(time, time, action, x, y, 0)
+ @Test
+ fun testHoldToDrag_holdsWithMovementWithinSlop_passesDragMoveEvents() {
+ val dragDetector = createDragDetector(holdToDragMinDurationMs = 100, slop = 20)
+ val downTime = SystemClock.uptimeMillis()
+ dragDetector.onMotionEvent(createMotionEvent(
+ action = MotionEvent.ACTION_DOWN,
+ x = 500f,
+ y = 10f,
+ isTouch = true,
+ downTime = downTime,
+ eventTime = downTime
+ ))
+
+ // Couple of movements within the slop, still counting as "holding"
+ dragDetector.onMotionEvent(createMotionEvent(
+ action = MotionEvent.ACTION_MOVE,
+ x = 500f + 10f, // within slop
+ y = 10f + 10f, // within slop
+ isTouch = true,
+ downTime = downTime,
+ eventTime = downTime + 30
+ ))
+ dragDetector.onMotionEvent(createMotionEvent(
+ action = MotionEvent.ACTION_MOVE,
+ x = 500f - 10f, // within slop
+ y = 10f - 5f, // within slop
+ isTouch = true,
+ downTime = downTime,
+ eventTime = downTime + 70
+ ))
+ // Now go beyond slop, but after the required holding period.
+ dragDetector.onMotionEvent(createMotionEvent(
+ action = MotionEvent.ACTION_MOVE,
+ x = 500f + 50f, // beyond slop
+ y = 10f + 50f, // beyond slop
+ isTouch = true,
+ downTime = downTime,
+ eventTime = downTime + 101 // after hold period
+ ))
+
+ // Had a valid hold, so there should be 1 "move".
+ verify(eventHandler, times(1))
+ .handleMotionEvent(any(), argThat { ev -> ev.action == MotionEvent.ACTION_MOVE })
+ }
+
+ @Test
+ fun testHoldToDrag_holdsWithoutAnyMovement_passesMoveEvents() {
+ val dragDetector = createDragDetector(holdToDragMinDurationMs = 100, slop = 20)
+ val downTime = SystemClock.uptimeMillis()
+ dragDetector.onMotionEvent(createMotionEvent(
+ action = MotionEvent.ACTION_DOWN,
+ x = 500f,
+ y = 10f,
+ isTouch = true,
+ downTime = downTime,
+ eventTime = downTime
+ ))
+
+ // First |move| is already beyond slop and after holding period.
+ dragDetector.onMotionEvent(createMotionEvent(
+ action = MotionEvent.ACTION_MOVE,
+ x = 500f + 50f, // beyond slop
+ y = 10f + 50f, // beyond slop
+ isTouch = true,
+ downTime = downTime,
+ eventTime = downTime + 101 // after hold period
+ ))
+
+ // Considered a valid hold, so there should be 1 "move".
+ verify(eventHandler, times(1))
+ .handleMotionEvent(any(), argThat { ev -> ev.action == MotionEvent.ACTION_MOVE })
+ }
+
+ @Test
+ fun testHoldToDrag_returnsWithinSlopAfterHoldPeriod_passesDragMoveEvents() {
+ val dragDetector = createDragDetector(holdToDragMinDurationMs = 100, slop = 20)
+ val downTime = SystemClock.uptimeMillis()
+ dragDetector.onMotionEvent(createMotionEvent(
+ action = MotionEvent.ACTION_DOWN,
+ x = 500f,
+ y = 10f,
+ isTouch = true,
+ downTime = downTime,
+ eventTime = downTime
+ ))
+ // Go beyond slop after the required holding period.
+ dragDetector.onMotionEvent(createMotionEvent(
+ action = MotionEvent.ACTION_MOVE,
+ x = 500f + 50f, // beyond slop
+ y = 10f + 50f, // beyond slop
+ isTouch = true,
+ downTime = downTime,
+ eventTime = downTime + 101 // after hold period
+ ))
+
+ // Return to original coordinates after holding period.
+ dragDetector.onMotionEvent(createMotionEvent(
+ action = MotionEvent.ACTION_MOVE,
+ x = 500f, // within slop
+ y = 10f, // within slop
+ isTouch = true,
+ downTime = downTime,
+ eventTime = downTime + 102 // after hold period
+ ))
+
+ // Both |moves| should be passed, even the one in the slop region since it was after the
+ // holding period. (e.g. after you drag the handle you may return to its original position).
+ verify(eventHandler, times(2))
+ .handleMotionEvent(any(), argThat { ev -> ev.action == MotionEvent.ACTION_MOVE })
+ }
+
+ @Test
+ fun testHoldToDrag_straysDuringHoldPeriod_skipsMoveEvents() {
+ val dragDetector = createDragDetector(holdToDragMinDurationMs = 100, slop = 20)
+ val downTime = SystemClock.uptimeMillis()
+ dragDetector.onMotionEvent(createMotionEvent(
+ action = MotionEvent.ACTION_DOWN,
+ x = 500f,
+ y = 10f,
+ isTouch = true,
+ downTime = downTime,
+ eventTime = downTime
+ ))
+
+ // Go beyond slop before the required holding period.
+ dragDetector.onMotionEvent(createMotionEvent(
+ action = MotionEvent.ACTION_MOVE,
+ x = 500f + 50f, // beyond slop
+ y = 10f + 50f, // beyond slop
+ isTouch = true,
+ downTime = downTime,
+ eventTime = downTime + 30 // during hold period
+ ))
+
+ // The |move| was too quick and did not held, do not pass it to the handler.
+ verify(eventHandler, never())
+ .handleMotionEvent(any(), argThat { ev -> ev.action == MotionEvent.ACTION_MOVE })
+ }
+
+ @Test
+ fun testHoldToDrag_straysDuringHoldPeriodAndReturnsWithinSlop_skipsMoveEvents() {
+ val dragDetector = createDragDetector(holdToDragMinDurationMs = 100, slop = 20)
+ val downTime = SystemClock.uptimeMillis()
+ dragDetector.onMotionEvent(createMotionEvent(
+ action = MotionEvent.ACTION_DOWN,
+ x = 500f,
+ y = 10f,
+ isTouch = true,
+ downTime = downTime,
+ eventTime = downTime
+ ))
+ // Go beyond slop before the required holding period.
+ dragDetector.onMotionEvent(createMotionEvent(
+ action = MotionEvent.ACTION_MOVE,
+ x = 500f + 50f, // beyond slop
+ y = 10f + 50f, // beyond slop
+ isTouch = true,
+ downTime = downTime,
+ eventTime = downTime + 30 // during hold period
+ ))
+
+ // Return to slop area during holding period.
+ dragDetector.onMotionEvent(createMotionEvent(
+ action = MotionEvent.ACTION_MOVE,
+ x = 500f + 10f, // within slop
+ y = 10f + 10f, // within slop
+ isTouch = true,
+ downTime = downTime,
+ eventTime = downTime + 50 // during hold period
+ ))
+
+ // The first |move| invalidates the drag even if you return within the hold period, so the
+ // |move| should not be passed to the handler.
+ verify(eventHandler, never())
+ .handleMotionEvent(any(), argThat { ev -> ev.action == MotionEvent.ACTION_MOVE })
+ }
+
+ @Test
+ fun testHoldToDrag_noHoldRequired_passesMoveEvents() {
+ val dragDetector = createDragDetector(holdToDragMinDurationMs = 0, slop = 20)
+ val downTime = SystemClock.uptimeMillis()
+ dragDetector.onMotionEvent(createMotionEvent(
+ action = MotionEvent.ACTION_DOWN,
+ x = 500f,
+ y = 10f,
+ isTouch = true,
+ downTime = downTime,
+ eventTime = downTime
+ ))
+
+ dragDetector.onMotionEvent(createMotionEvent(
+ action = MotionEvent.ACTION_MOVE,
+ x = 500f + 50f, // beyond slop
+ y = 10f + 50f, // beyond slop
+ isTouch = true,
+ downTime = downTime,
+ eventTime = downTime + 1
+ ))
+
+ // The |move| should be passed to the handler as no hold period was needed.
+ verify(eventHandler, times(1))
+ .handleMotionEvent(any(), argThat { ev -> ev.action == MotionEvent.ACTION_MOVE })
+ }
+
+ private fun createMotionEvent(
+ action: Int,
+ x: Float = X,
+ y: Float = Y,
+ isTouch: Boolean = true,
+ downTime: Long = SystemClock.uptimeMillis(),
+ eventTime: Long = SystemClock.uptimeMillis()
+ ): MotionEvent {
+ val ev = MotionEvent.obtain(downTime, eventTime, action, x, y, 0)
ev.source = if (isTouch) InputDevice.SOURCE_TOUCHSCREEN else InputDevice.SOURCE_MOUSE
motionEvents.add(ev)
return ev
}
+ private fun createDragDetector(
+ holdToDragMinDurationMs: Long = 0,
+ slop: Int = SLOP
+ ) = DragDetector(
+ eventHandler,
+ holdToDragMinDurationMs,
+ slop
+ )
+
companion object {
private const val SLOP = 10
private const val X = 123f
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
index 1691f07..57469bf 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
@@ -128,7 +128,7 @@
@Test
public void testRegionUnionContainsEdges() {
Region region = new Region();
- GEOMETRY.union(mContext, region);
+ GEOMETRY.union(region);
assertThat(region.isComplex()).isTrue();
// Region excludes task area. Note that coordinates start from top left.
assertThat(region.contains(TASK_SIZE.getWidth() / 2, TASK_SIZE.getHeight() / 2)).isFalse();
@@ -168,7 +168,7 @@
@EnableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
public void testRegionUnion_edgeDragResizeEnabled_containsLargeCorners() {
Region region = new Region();
- GEOMETRY.union(mContext, region);
+ GEOMETRY.union(region);
final int cornerRadius = LARGE_CORNER_SIZE / 2;
new TestPoints(mContext, TASK_SIZE, cornerRadius).validateRegion(region);
@@ -182,7 +182,7 @@
@DisableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
public void testRegionUnion_edgeDragResizeDisabled_containsFineCorners() {
Region region = new Region();
- GEOMETRY.union(mContext, region);
+ GEOMETRY.union(region);
final int cornerRadius = FINE_CORNER_SIZE / 2;
new TestPoints(mContext, TASK_SIZE, cornerRadius).validateRegion(region);
@@ -215,7 +215,7 @@
CTRL_TYPE_BOTTOM);
for (int i = 0; i < points.size(); i++) {
- assertThat(GEOMETRY.calculateCtrlType(mContext, isTouchscreen, isEdgeResizePermitted,
+ assertThat(GEOMETRY.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
points.get(i).x, points.get(i).y)).isEqualTo(
isEdgeResizePermitted ? expectedCtrlType.get(i) : CTRL_TYPE_UNDEFINED);
}
@@ -366,17 +366,17 @@
public void validateCtrlTypeForInnerPoints(@NonNull DragResizeWindowGeometry geometry,
boolean isTouchscreen, boolean isEdgeResizePermitted,
boolean expectedWithinGeometry) {
- assertThat(geometry.calculateCtrlType(mContext, isTouchscreen, isEdgeResizePermitted,
+ assertThat(geometry.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
mTopLeftPoint.x, mTopLeftPoint.y)).isEqualTo(
expectedWithinGeometry ? CTRL_TYPE_LEFT | CTRL_TYPE_TOP : CTRL_TYPE_UNDEFINED);
- assertThat(geometry.calculateCtrlType(mContext, isTouchscreen, isEdgeResizePermitted,
+ assertThat(geometry.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
mTopRightPoint.x, mTopRightPoint.y)).isEqualTo(
expectedWithinGeometry ? CTRL_TYPE_RIGHT | CTRL_TYPE_TOP : CTRL_TYPE_UNDEFINED);
- assertThat(geometry.calculateCtrlType(mContext, isTouchscreen, isEdgeResizePermitted,
+ assertThat(geometry.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
mBottomLeftPoint.x, mBottomLeftPoint.y)).isEqualTo(
expectedWithinGeometry ? CTRL_TYPE_LEFT | CTRL_TYPE_BOTTOM
: CTRL_TYPE_UNDEFINED);
- assertThat(geometry.calculateCtrlType(mContext, isTouchscreen, isEdgeResizePermitted,
+ assertThat(geometry.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
mBottomRightPoint.x, mBottomRightPoint.y)).isEqualTo(
expectedWithinGeometry ? CTRL_TYPE_RIGHT | CTRL_TYPE_BOTTOM
: CTRL_TYPE_UNDEFINED);
@@ -389,17 +389,17 @@
public void validateCtrlTypeForOutsidePoints(@NonNull DragResizeWindowGeometry geometry,
boolean isTouchscreen, boolean isEdgeResizePermitted,
boolean expectedWithinGeometry) {
- assertThat(geometry.calculateCtrlType(mContext, isTouchscreen, isEdgeResizePermitted,
+ assertThat(geometry.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
mTopLeftPointOutside.x, mTopLeftPointOutside.y)).isEqualTo(
expectedWithinGeometry ? CTRL_TYPE_LEFT | CTRL_TYPE_TOP : CTRL_TYPE_UNDEFINED);
- assertThat(geometry.calculateCtrlType(mContext, isTouchscreen, isEdgeResizePermitted,
+ assertThat(geometry.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
mTopRightPointOutside.x, mTopRightPointOutside.y)).isEqualTo(
expectedWithinGeometry ? CTRL_TYPE_RIGHT | CTRL_TYPE_TOP : CTRL_TYPE_UNDEFINED);
- assertThat(geometry.calculateCtrlType(mContext, isTouchscreen, isEdgeResizePermitted,
+ assertThat(geometry.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
mBottomLeftPointOutside.x, mBottomLeftPointOutside.y)).isEqualTo(
expectedWithinGeometry ? CTRL_TYPE_LEFT | CTRL_TYPE_BOTTOM
: CTRL_TYPE_UNDEFINED);
- assertThat(geometry.calculateCtrlType(mContext, isTouchscreen, isEdgeResizePermitted,
+ assertThat(geometry.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
mBottomRightPointOutside.x, mBottomRightPointOutside.y)).isEqualTo(
expectedWithinGeometry ? CTRL_TYPE_RIGHT | CTRL_TYPE_BOTTOM
: CTRL_TYPE_UNDEFINED);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/OWNERS
new file mode 100644
index 0000000..553540c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 929241
+# includes OWNERS from parent directories
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
index 7784af6..1273ee8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
@@ -21,7 +21,9 @@
import android.content.res.Resources
import android.graphics.Point
import android.graphics.Rect
+import android.os.Handler
import android.os.IBinder
+import android.os.Looper
import android.testing.AndroidTestingRunner
import android.view.Display
import android.view.Surface.ROTATION_0
@@ -33,6 +35,7 @@
import android.window.TransitionInfo
import android.window.WindowContainerToken
import androidx.test.filters.SmallTest
+import androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread
import com.android.internal.jank.InteractionJankMonitor
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
@@ -107,6 +110,7 @@
private lateinit var mockResources: Resources
@Mock
private lateinit var mockInteractionJankMonitor: InteractionJankMonitor
+ private val mainHandler = Handler(Looper.getMainLooper())
private lateinit var taskPositioner: VeiledResizeTaskPositioner
@@ -155,12 +159,13 @@
mockDragStartListener,
mockTransactionFactory,
mockTransitions,
- mockInteractionJankMonitor
+ mockInteractionJankMonitor,
+ mainHandler,
)
}
@Test
- fun testDragResize_noMove_doesNotShowResizeVeil() {
+ fun testDragResize_noMove_doesNotShowResizeVeil() = runOnUiThread {
taskPositioner.onDragPositioningStart(
CTRL_TYPE_TOP or CTRL_TYPE_RIGHT,
STARTING_BOUNDS.left.toFloat(),
@@ -172,6 +177,7 @@
STARTING_BOUNDS.left.toFloat(),
STARTING_BOUNDS.top.toFloat()
)
+
verify(mockTransitions, never()).startTransition(eq(TRANSIT_CHANGE), argThat { wct ->
return@argThat wct.changes.any { (token, change) ->
token == taskBinder &&
@@ -182,7 +188,7 @@
}
@Test
- fun testDragResize_movesTask_doesNotShowResizeVeil() {
+ fun testDragResize_movesTask_doesNotShowResizeVeil() = runOnUiThread {
taskPositioner.onDragPositioningStart(
CTRL_TYPE_UNDEFINED,
STARTING_BOUNDS.left.toFloat(),
@@ -217,7 +223,7 @@
}
@Test
- fun testDragResize_resize_boundsUpdateOnEnd() {
+ fun testDragResize_resize_boundsUpdateOnEnd() = runOnUiThread {
taskPositioner.onDragPositioningStart(
CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
STARTING_BOUNDS.right.toFloat(),
@@ -258,7 +264,7 @@
}
@Test
- fun testDragResize_noEffectiveMove_skipsTransactionOnEnd() {
+ fun testDragResize_noEffectiveMove_skipsTransactionOnEnd() = runOnUiThread {
taskPositioner.onDragPositioningStart(
CTRL_TYPE_TOP or CTRL_TYPE_RIGHT,
STARTING_BOUNDS.left.toFloat(),
@@ -290,9 +296,8 @@
})
}
-
@Test
- fun testDragResize_drag_setBoundsNotRunIfDragEndsInDisallowedEndArea() {
+ fun testDragResize_drag_setBoundsNotRunIfDragEndsInDisallowedEndArea() = runOnUiThread {
taskPositioner.onDragPositioningStart(
CTRL_TYPE_UNDEFINED, // drag
STARTING_BOUNDS.left.toFloat(),
@@ -317,7 +322,7 @@
}
@Test
- fun testDragResize_resize_resizingTaskReorderedToTopWhenNotFocused() {
+ fun testDragResize_resize_resizingTaskReorderedToTopWhenNotFocused() = runOnUiThread {
mockDesktopWindowDecoration.mTaskInfo.isFocused = false
taskPositioner.onDragPositioningStart(
CTRL_TYPE_RIGHT, // Resize right
@@ -333,7 +338,7 @@
}
@Test
- fun testDragResize_resize_resizingTaskNotReorderedToTopWhenFocused() {
+ fun testDragResize_resize_resizingTaskNotReorderedToTopWhenFocused() = runOnUiThread {
mockDesktopWindowDecoration.mTaskInfo.isFocused = true
taskPositioner.onDragPositioningStart(
CTRL_TYPE_RIGHT, // Resize right
@@ -349,7 +354,7 @@
}
@Test
- fun testDragResize_drag_draggedTaskNotReorderedToTop() {
+ fun testDragResize_drag_draggedTaskNotReorderedToTop() = runOnUiThread {
mockDesktopWindowDecoration.mTaskInfo.isFocused = false
taskPositioner.onDragPositioningStart(
CTRL_TYPE_UNDEFINED, // drag
@@ -366,7 +371,7 @@
}
@Test
- fun testDragResize_drag_updatesStableBoundsOnRotate() {
+ fun testDragResize_drag_updatesStableBoundsOnRotate() = runOnUiThread {
// Test landscape stable bounds
performDrag(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat(),
STARTING_BOUNDS.right.toFloat() + 2000, STARTING_BOUNDS.bottom.toFloat() + 2000,
@@ -412,7 +417,7 @@
}
@Test
- fun testIsResizingOrAnimatingResizeSet() {
+ fun testIsResizingOrAnimatingResizeSet() = runOnUiThread {
Assert.assertFalse(taskPositioner.isResizingOrAnimating)
taskPositioner.onDragPositioningStart(
@@ -439,7 +444,7 @@
}
@Test
- fun testIsResizingOrAnimatingResizeResetAfterStartAnimation() {
+ fun testIsResizingOrAnimatingResizeResetAfterStartAnimation() = runOnUiThread {
performDrag(
STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat(),
STARTING_BOUNDS.left.toFloat() - 20, STARTING_BOUNDS.top.toFloat() - 20,
@@ -453,7 +458,7 @@
}
@Test
- fun testStartAnimation_useEndRelOffset() {
+ fun testStartAnimation_useEndRelOffset() = runOnUiThread {
val changeMock = mock(TransitionInfo.Change::class.java)
val startTransaction = mock(Transaction::class.java)
val finishTransaction = mock(Transaction::class.java)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostTest.kt
index 1b0b7d9..1b2ce9e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostTest.kt
@@ -18,6 +18,7 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
import android.view.View
import android.view.WindowManager
import androidx.test.filters.SmallTest
@@ -27,6 +28,7 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertThrows
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
@@ -57,8 +59,54 @@
onDrawTransaction = null
)
- assertThat(windowDecorViewHost.viewHostAdapter.isInitialized()).isTrue()
- assertThat(windowDecorViewHost.view()).isEqualTo(view)
+ assertThat(windowDecorViewHost.viewHost).isNotNull()
+ assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(view)
+ }
+
+ @Test
+ fun updateView_alreadyLaidOut_relayouts() = runTest {
+ val windowDecorViewHost = createDefaultViewHost()
+ val view = View(context)
+ windowDecorViewHost.updateView(
+ view = view,
+ attrs = WindowManager.LayoutParams(100, 100),
+ configuration = context.resources.configuration,
+ onDrawTransaction = null
+ )
+
+ val otherParams = WindowManager.LayoutParams(200, 200)
+ windowDecorViewHost.updateView(
+ view = view,
+ attrs = otherParams,
+ configuration = context.resources.configuration,
+ onDrawTransaction = null
+ )
+
+ assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(view)
+ assertThat(windowDecorViewHost.viewHost!!.view!!.layoutParams.width)
+ .isEqualTo(otherParams.width)
+ }
+
+ @Test
+ fun updateView_replacingView_throws() = runTest {
+ val windowDecorViewHost = createDefaultViewHost()
+ val view = View(context)
+ windowDecorViewHost.updateView(
+ view = view,
+ attrs = WindowManager.LayoutParams(100, 100),
+ configuration = context.resources.configuration,
+ onDrawTransaction = null
+ )
+
+ val otherView = View(context)
+ assertThrows(Exception::class.java) {
+ windowDecorViewHost.updateView(
+ view = otherView,
+ attrs = WindowManager.LayoutParams(100, 100),
+ configuration = context.resources.configuration,
+ onDrawTransaction = null
+ )
+ }
}
@OptIn(ExperimentalCoroutinesApi::class)
@@ -77,7 +125,7 @@
)
// No view host yet, since the coroutine hasn't run.
- assertThat(windowDecorViewHost.viewHostAdapter.isInitialized()).isFalse()
+ assertThat(windowDecorViewHost.viewHost).isNull()
windowDecorViewHost.updateView(
view = syncView,
@@ -89,13 +137,14 @@
// Would run coroutine if it hadn't been cancelled.
advanceUntilIdle()
- assertThat(windowDecorViewHost.viewHostAdapter.isInitialized()).isTrue()
- assertThat(windowDecorViewHost.view()).isNotNull()
+ assertThat(windowDecorViewHost.viewHost).isNotNull()
+ assertThat(windowDecorViewHost.viewHost!!.view).isNotNull()
// View host view/attrs should match the ones from the sync call, plus, since the
// sync/async were made with different views, if the job hadn't been cancelled there
// would've been an exception thrown as replacing views isn't allowed.
- assertThat(windowDecorViewHost.view()).isEqualTo(syncView)
- assertThat(windowDecorViewHost.view()!!.layoutParams.width).isEqualTo(syncAttrs.width)
+ assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(syncView)
+ assertThat(windowDecorViewHost.viewHost!!.view!!.layoutParams.width)
+ .isEqualTo(syncAttrs.width)
}
@OptIn(ExperimentalCoroutinesApi::class)
@@ -111,11 +160,11 @@
configuration = context.resources.configuration,
)
- assertThat(windowDecorViewHost.viewHostAdapter.isInitialized()).isFalse()
+ assertThat(windowDecorViewHost.viewHost).isNull()
advanceUntilIdle()
- assertThat(windowDecorViewHost.viewHostAdapter.isInitialized()).isTrue()
+ assertThat(windowDecorViewHost.viewHost).isNotNull()
}
@OptIn(ExperimentalCoroutinesApi::class)
@@ -138,8 +187,9 @@
advanceUntilIdle()
- assertThat(windowDecorViewHost.viewHostAdapter.isInitialized()).isTrue()
- assertThat(windowDecorViewHost.view()).isEqualTo(otherView)
+ assertThat(windowDecorViewHost.viewHost).isNotNull()
+ assertThat(windowDecorViewHost.viewHost!!.view).isNotNull()
+ assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(otherView)
}
@Test
@@ -157,15 +207,16 @@
val t = mock(SurfaceControl.Transaction::class.java)
windowDecorViewHost.release(t)
- verify(windowDecorViewHost.viewHostAdapter).release(t)
+ verify(windowDecorViewHost.viewHost!!).release()
+ verify(t).remove(windowDecorViewHost.surfaceControl)
}
private fun CoroutineScope.createDefaultViewHost() = DefaultWindowDecorViewHost(
context = context,
mainScope = this,
display = context.display,
- viewHostAdapter = spy(SurfaceControlViewHostAdapter(context, context.display)),
+ surfaceControlViewHostFactory = { c, d, wwm, s ->
+ spy(SurfaceControlViewHost(c, d, wwm, s))
+ }
)
-
- private fun DefaultWindowDecorViewHost.view(): View? = viewHostAdapter.viewHost?.view
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/PooledWindowDecorViewHostSupplierTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/PooledWindowDecorViewHostSupplierTest.kt
deleted file mode 100644
index a7e4213..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/PooledWindowDecorViewHostSupplierTest.kt
+++ /dev/null
@@ -1,181 +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.wm.shell.windowdecor.viewhost
-
-import android.testing.AndroidTestingRunner
-import android.view.SurfaceControl
-import androidx.test.filters.SmallTest
-import com.android.wm.shell.ShellTestCase
-import com.android.wm.shell.TestShellExecutor
-import com.android.wm.shell.sysui.ShellInit
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.advanceUntilIdle
-import kotlinx.coroutines.test.runTest
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
-import org.mockito.kotlin.any
-import org.mockito.kotlin.mock
-import org.mockito.kotlin.never
-import org.mockito.kotlin.verify
-import org.mockito.kotlin.whenever
-
-/**
- * Tests for [PooledWindowDecorViewHostSupplier].
- *
- * Build/Install/Run:
- * atest WMShellUnitTests:PooledWindowDecorViewHostSupplierTest
- */
-@OptIn(ExperimentalCoroutinesApi::class)
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-class PooledWindowDecorViewHostSupplierTest : ShellTestCase() {
-
- private val testExecutor = TestShellExecutor()
- private val testShellInit = ShellInit(testExecutor)
- @Mock
- private lateinit var mockViewHostFactory: ReusableWindowDecorViewHost.Factory
-
- private lateinit var supplier: PooledWindowDecorViewHostSupplier
-
- @Test
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- }
-
- @Test
- fun onInit_warmsAndPoolsViewHosts() = runTest {
- supplier = createSupplier(maxPoolSize = 5, preWarmSize = 2)
- val mockViewHost1 = mock<ReusableWindowDecorViewHost>()
- val mockViewHost2 = mock<ReusableWindowDecorViewHost>()
- whenever(mockViewHostFactory
- .create(context, this, context.display, id = 0))
- .thenReturn(mockViewHost1)
- whenever(mockViewHostFactory
- .create(context, this, context.display, id = 1))
- .thenReturn(mockViewHost2)
-
- testExecutor.flushAll()
- advanceUntilIdle()
-
- // Both were warmed up.
- verify(mockViewHost1).warmUp()
- verify(mockViewHost2).warmUp()
- // Both were released, so re-acquiring them provides the same instance.
- assertThat(mockViewHost2)
- .isEqualTo(supplier.acquire(context, context.display))
- assertThat(mockViewHost1)
- .isEqualTo(supplier.acquire(context, context.display))
- }
-
- @Test(expected = Throwable::class)
- fun onInit_warmUpSizeExceedsPoolSize_throws() = runTest {
- createSupplier(maxPoolSize = 3, preWarmSize = 4)
- }
-
- @Test
- fun acquire_poolHasInstances_reuses() = runTest {
- supplier = createSupplier(maxPoolSize = 5, preWarmSize = 0)
-
- // Prepare the pool with one instance.
- val mockViewHost = mock<ReusableWindowDecorViewHost>()
- supplier.release(mockViewHost, SurfaceControl.Transaction())
-
- assertThat(mockViewHost)
- .isEqualTo(supplier.acquire(context, context.display))
- verify(mockViewHostFactory, never()).create(any(), any(), any(), any())
- }
-
- @Test
- fun acquire_pooledHasZeroInstances_creates() = runTest {
- supplier = createSupplier(maxPoolSize = 5, preWarmSize = 0)
-
- supplier.acquire(context, context.display)
-
- verify(mockViewHostFactory).create(context, this, context.display, id = 0)
- }
-
- @Test
- fun release_poolBelowLimit_caches() = runTest {
- supplier = createSupplier(maxPoolSize = 5, preWarmSize = 0)
-
- val mockViewHost = mock<ReusableWindowDecorViewHost>()
- val mockT = mock<SurfaceControl.Transaction>()
- supplier.release(mockViewHost, mockT)
-
- assertThat(mockViewHost)
- .isEqualTo(supplier.acquire(context, context.display))
- }
-
- @Test
- fun release_poolBelowLimit_doesNotReleaseViewHost() = runTest {
- supplier = createSupplier(maxPoolSize = 5, preWarmSize = 0)
-
- val mockViewHost = mock<ReusableWindowDecorViewHost>()
- val mockT = mock<SurfaceControl.Transaction>()
- supplier.release(mockViewHost, mockT)
-
- verify(mockViewHost, never()).release(mockT)
- }
-
- @Test
- fun release_poolAtLimit_doesNotCache() = runTest {
- supplier = createSupplier(maxPoolSize = 1, preWarmSize = 0)
- val mockT = mock<SurfaceControl.Transaction>()
- val mockViewHost = mock<ReusableWindowDecorViewHost>()
- supplier.release(mockViewHost, mockT) // Maxes pool.
-
- val mockViewHost2 = mock<ReusableWindowDecorViewHost>()
- supplier.release(mockViewHost2, mockT) // Beyond limit.
-
- assertThat(mockViewHost)
- .isEqualTo(supplier.acquire(context, context.display))
- // Second one wasn't cached, so the acquired one should've been a new instance.
- assertThat(mockViewHost2)
- .isNotEqualTo(supplier.acquire(context, context.display))
- }
-
- @Test
- fun release_poolAtLimit_releasesViewHost() = runTest {
- supplier = createSupplier(maxPoolSize = 1, preWarmSize = 0)
- val mockT = mock<SurfaceControl.Transaction>()
- val mockViewHost = mock<ReusableWindowDecorViewHost>()
- supplier.release(mockViewHost, mockT) // Maxes pool.
-
- val mockViewHost2 = mock<ReusableWindowDecorViewHost>()
- supplier.release(mockViewHost2, mockT) // Beyond limit.
-
- // Second one doesn't fit, so it needs to be released.
- verify(mockViewHost2).release(mockT)
- }
-
- private fun CoroutineScope.createSupplier(
- maxPoolSize: Int,
- preWarmSize: Int
- ) = PooledWindowDecorViewHostSupplier(
- context,
- this,
- testShellInit,
- mockViewHostFactory,
- maxPoolSize,
- preWarmSize
- ).also {
- testShellInit.init()
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/ReusableWindowDecorViewHostTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/ReusableWindowDecorViewHostTest.kt
deleted file mode 100644
index de2444e..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/ReusableWindowDecorViewHostTest.kt
+++ /dev/null
@@ -1,182 +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.wm.shell.windowdecor.viewhost
-
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.view.SurfaceControl
-import android.view.View
-import android.view.WindowManager
-import androidx.test.filters.SmallTest
-import com.android.wm.shell.ShellTestCase
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.advanceUntilIdle
-import kotlinx.coroutines.test.runTest
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito.mock
-import org.mockito.kotlin.spy
-import org.mockito.kotlin.verify
-
-/**
- * Tests for [ReusableWindowDecorViewHost].
- *
- * Build/Install/Run:
- * atest WMShellUnitTests:ReusableWindowDecorViewHostTest
- */
-@SmallTest
[email protected]
-@RunWith(AndroidTestingRunner::class)
-class ReusableWindowDecorViewHostTest : ShellTestCase() {
-
- @Test
- fun warmUp_addsRootView() = runTest {
- val reusableVH = createReusableViewHost().apply {
- warmUp()
- }
-
- assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue()
- assertThat(reusableVH.view()).isEqualTo(reusableVH.rootView)
- }
-
- @Test
- fun update_differentView_replacesView() = runTest {
- val view = View(context)
- val lp = WindowManager.LayoutParams()
- val reusableVH = createReusableViewHost()
- reusableVH.updateView(view, lp, context.resources.configuration, null)
-
- assertThat(reusableVH.rootView.childCount).isEqualTo(1)
- assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(view)
-
- val newView = View(context)
- val newLp = WindowManager.LayoutParams()
- reusableVH.updateView(newView, newLp, context.resources.configuration, null)
-
- assertThat(reusableVH.rootView.childCount).isEqualTo(1)
- assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(newView)
- }
-
- @OptIn(ExperimentalCoroutinesApi::class)
- @Test
- fun updateView_clearsPendingAsyncJob() = runTest {
- val reusableVH = createReusableViewHost()
- val asyncView = View(context)
- val syncView = View(context)
- val asyncAttrs = WindowManager.LayoutParams(100, 100)
- val syncAttrs = WindowManager.LayoutParams(200, 200)
-
- reusableVH.updateViewAsync(
- view = asyncView,
- attrs = asyncAttrs,
- configuration = context.resources.configuration,
- )
-
- // No view host yet, since the coroutine hasn't run.
- assertThat(reusableVH.viewHostAdapter.isInitialized()).isFalse()
-
- reusableVH.updateView(
- view = syncView,
- attrs = syncAttrs,
- configuration = context.resources.configuration,
- onDrawTransaction = null
- )
-
- // Would run coroutine if it hadn't been cancelled.
- advanceUntilIdle()
-
- assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue()
- // View host view/attrs should match the ones from the sync call, plus, since the
- // sync/async were made with different views, if the job hadn't been cancelled there
- // would've been an exception thrown as replacing views isn't allowed.
- assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(syncView)
- assertThat(reusableVH.view()!!.layoutParams.width).isEqualTo(syncAttrs.width)
- }
-
- @OptIn(ExperimentalCoroutinesApi::class)
- @Test
- fun updateViewAsync() = runTest {
- val reusableVH = createReusableViewHost()
- val view = View(context)
- val attrs = WindowManager.LayoutParams(100, 100)
-
- reusableVH.updateViewAsync(
- view = view,
- attrs = attrs,
- configuration = context.resources.configuration,
- )
-
- assertThat(reusableVH.viewHostAdapter.isInitialized()).isFalse()
-
- advanceUntilIdle()
-
- assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue()
- }
-
- @OptIn(ExperimentalCoroutinesApi::class)
- @Test
- fun updateViewAsync_clearsPendingAsyncJob() = runTest {
- val reusableVH = createReusableViewHost()
-
- val view = View(context)
- reusableVH.updateViewAsync(
- view = view,
- attrs = WindowManager.LayoutParams(100, 100),
- configuration = context.resources.configuration,
- )
- val otherView = View(context)
- reusableVH.updateViewAsync(
- view = otherView,
- attrs = WindowManager.LayoutParams(100, 100),
- configuration = context.resources.configuration,
- )
-
- advanceUntilIdle()
-
- assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue()
- assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(otherView)
- }
-
- @Test
- fun release() = runTest {
- val reusableVH = createReusableViewHost()
-
- val view = View(context)
- reusableVH.updateView(
- view = view,
- attrs = WindowManager.LayoutParams(100, 100),
- configuration = context.resources.configuration,
- onDrawTransaction = null
- )
-
- val t = mock(SurfaceControl.Transaction::class.java)
- reusableVH.release(t)
-
- verify(reusableVH.viewHostAdapter).release(t)
- }
-
- private fun CoroutineScope.createReusableViewHost() = ReusableWindowDecorViewHost(
- context = context,
- mainScope = this,
- display = context.display,
- id = 1,
- viewHostAdapter = spy(SurfaceControlViewHostAdapter(context, context.display)),
- )
-
- private fun ReusableWindowDecorViewHost.view(): View? = viewHostAdapter.viewHost?.view
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/SurfaceControlViewHostAdapterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/SurfaceControlViewHostAdapterTest.kt
deleted file mode 100644
index d6c80a7..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/SurfaceControlViewHostAdapterTest.kt
+++ /dev/null
@@ -1,144 +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.wm.shell.windowdecor.viewhost
-
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.view.SurfaceControl
-import android.view.SurfaceControlViewHost
-import android.view.View
-import android.view.WindowManager
-import androidx.test.filters.SmallTest
-import com.android.wm.shell.ShellTestCase
-import com.google.common.truth.Truth.assertThat
-import org.junit.Assert.assertThrows
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito.mock
-import org.mockito.kotlin.spy
-import org.mockito.kotlin.verify
-
-/**
- * Tests for [SurfaceControlViewHostAdapter].
- *
- * Build/Install/Run:
- * atest WMShellUnitTests:SurfaceControlViewHostAdapterTest
- */
-@SmallTest
[email protected]
-@RunWith(AndroidTestingRunner::class)
-class SurfaceControlViewHostAdapterTest : ShellTestCase() {
-
- private lateinit var adapter: SurfaceControlViewHostAdapter
-
- @Before
- fun setUp() {
- adapter = SurfaceControlViewHostAdapter(
- context,
- context.display,
- surfaceControlViewHostFactory = { c, d, wwm, s ->
- spy(SurfaceControlViewHost(c, d, wwm, s))
- }
- )
- }
-
- @Test
- fun prepareViewHost() {
- adapter.prepareViewHost(context.resources.configuration)
-
- assertThat(adapter.viewHost).isNotNull()
- }
-
- @Test
- fun prepareViewHost_alreadyCreated_skips() {
- adapter.prepareViewHost(context.resources.configuration)
-
- val viewHost = adapter.viewHost!!
-
- adapter.prepareViewHost(context.resources.configuration)
-
- assertThat(adapter.viewHost).isEqualTo(viewHost)
- }
-
- @Test
- fun updateView_layoutInViewHost() {
- val view = View(context)
- adapter.prepareViewHost(context.resources.configuration)
-
- adapter.updateView(
- view = view,
- attrs = WindowManager.LayoutParams(100, 100)
- )
-
- assertThat(adapter.isInitialized()).isTrue()
- assertThat(adapter.view()).isEqualTo(view)
- }
-
- @Test
- fun updateView_alreadyLaidOut_relayouts() {
- val view = View(context)
- adapter.prepareViewHost(context.resources.configuration)
- adapter.updateView(
- view = view,
- attrs = WindowManager.LayoutParams(100, 100)
- )
-
- val otherParams = WindowManager.LayoutParams(200, 200)
- adapter.updateView(
- view = view,
- attrs = otherParams
- )
-
- assertThat(adapter.view()).isEqualTo(view)
- assertThat(adapter.view()!!.layoutParams.width).isEqualTo(otherParams.width)
- }
-
- @Test
- fun updateView_replacingView_throws() {
- val view = View(context)
- adapter.prepareViewHost(context.resources.configuration)
- adapter.updateView(
- view = view,
- attrs = WindowManager.LayoutParams(100, 100)
- )
-
- val otherView = View(context)
- assertThrows(Exception::class.java) {
- adapter.updateView(
- view = otherView,
- attrs = WindowManager.LayoutParams(100, 100)
- )
- }
- }
-
- @Test
- fun release() {
- adapter.prepareViewHost(context.resources.configuration)
- adapter.updateView(
- view = View(context),
- attrs = WindowManager.LayoutParams(100, 100)
- )
-
- val mockT = mock(SurfaceControl.Transaction::class.java)
- adapter.release(mockT)
-
- verify(adapter.viewHost!!).release()
- verify(mockT).remove(adapter.rootSurface)
- }
-
- private fun SurfaceControlViewHostAdapter.view(): View? = viewHost?.view
-}
diff --git a/libs/appfunctions/Android.bp b/libs/appfunctions/Android.bp
new file mode 100644
index 0000000..c6cee07
--- /dev/null
+++ b/libs/appfunctions/Android.bp
@@ -0,0 +1,39 @@
+// 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_sdk_library {
+ name: "com.google.android.appfunctions.sidecar",
+ owner: "google",
+ srcs: ["java/**/*.java"],
+ api_packages: ["com.google.android.appfunctions.sidecar"],
+ dex_preopt: {
+ enabled: false,
+ },
+ system_ext_specific: true,
+ no_dist: true,
+ unsafe_ignore_missing_latest_api: true,
+}
+
+prebuilt_etc {
+ name: "appfunctions.sidecar.xml",
+ system_ext_specific: true,
+ sub_dir: "permissions",
+ src: "appfunctions.sidecar.xml",
+ filename_from_src: true,
+}
diff --git a/libs/appfunctions/api/current.txt b/libs/appfunctions/api/current.txt
new file mode 100644
index 0000000..504e329
--- /dev/null
+++ b/libs/appfunctions/api/current.txt
@@ -0,0 +1,49 @@
+// Signature format: 2.0
+package com.google.android.appfunctions.sidecar {
+
+ public final class AppFunctionManager {
+ ctor public AppFunctionManager(android.content.Context);
+ method public void executeAppFunction(@NonNull com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse>);
+ }
+
+ public abstract class AppFunctionService extends android.app.Service {
+ ctor public AppFunctionService();
+ method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
+ method @MainThread public abstract void onExecuteFunction(@NonNull com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest, @NonNull java.util.function.Consumer<com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse>);
+ field @NonNull public static final String BIND_APP_FUNCTION_SERVICE = "android.permission.BIND_APP_FUNCTION_SERVICE";
+ field @NonNull public static final String SERVICE_INTERFACE = "android.app.appfunctions.AppFunctionService";
+ }
+
+ public final class ExecuteAppFunctionRequest {
+ method @NonNull public android.os.Bundle getExtras();
+ method @NonNull public String getFunctionIdentifier();
+ method @NonNull public android.app.appsearch.GenericDocument getParameters();
+ method @NonNull public String getTargetPackageName();
+ }
+
+ public static final class ExecuteAppFunctionRequest.Builder {
+ ctor public ExecuteAppFunctionRequest.Builder(@NonNull String, @NonNull String);
+ method @NonNull public com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest build();
+ method @NonNull public com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest.Builder setExtras(@NonNull android.os.Bundle);
+ method @NonNull public com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest.Builder setParameters(@NonNull android.app.appsearch.GenericDocument);
+ }
+
+ public final class ExecuteAppFunctionResponse {
+ method @Nullable public String getErrorMessage();
+ method @NonNull public android.os.Bundle getExtras();
+ method public int getResultCode();
+ method @NonNull public android.app.appsearch.GenericDocument getResultDocument();
+ method public boolean isSuccess();
+ method @NonNull public static com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse newFailure(int, @Nullable String, @Nullable android.os.Bundle);
+ method @NonNull public static com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse newSuccess(@NonNull android.app.appsearch.GenericDocument, @Nullable android.os.Bundle);
+ field public static final String PROPERTY_RETURN_VALUE = "returnValue";
+ field public static final int RESULT_APP_UNKNOWN_ERROR = 2; // 0x2
+ field public static final int RESULT_DENIED = 1; // 0x1
+ field public static final int RESULT_INTERNAL_ERROR = 3; // 0x3
+ field public static final int RESULT_INVALID_ARGUMENT = 4; // 0x4
+ field public static final int RESULT_OK = 0; // 0x0
+ field public static final int RESULT_TIMED_OUT = 5; // 0x5
+ }
+
+}
+
diff --git a/libs/appfunctions/api/removed.txt b/libs/appfunctions/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/libs/appfunctions/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/libs/appfunctions/api/system-current.txt b/libs/appfunctions/api/system-current.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/libs/appfunctions/api/system-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/libs/appfunctions/api/system-removed.txt b/libs/appfunctions/api/system-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/libs/appfunctions/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/libs/appfunctions/api/test-current.txt b/libs/appfunctions/api/test-current.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/libs/appfunctions/api/test-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/libs/appfunctions/api/test-removed.txt b/libs/appfunctions/api/test-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/libs/appfunctions/api/test-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/libs/appfunctions/appfunctions.sidecar.xml b/libs/appfunctions/appfunctions.sidecar.xml
new file mode 100644
index 0000000..bef8b6e
--- /dev/null
+++ b/libs/appfunctions/appfunctions.sidecar.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<permissions>
+ <library
+ name="com.google.android.appfunctions.sidecar"
+ file="/system_ext/framework/com.google.android.appfunctions.sidecar.jar"/>
+</permissions>
\ No newline at end of file
diff --git a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionManager.java b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionManager.java
new file mode 100644
index 0000000..b1dd467
--- /dev/null
+++ b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionManager.java
@@ -0,0 +1,82 @@
+/*
+ * 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.google.android.appfunctions.sidecar;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.content.Context;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+
+/**
+ * Provides app functions related functionalities.
+ *
+ * <p>App function is a specific piece of functionality that an app offers to the system. These
+ * functionalities can be integrated into various system features.
+ *
+ * <p>This class wraps {@link android.app.appfunctions.AppFunctionManager} functionalities and
+ * exposes it here as a sidecar library (avoiding direct dependency on the platform API).
+ */
+// TODO(b/357551503): Implement get and set enabled app function APIs.
+// TODO(b/367329899): Add sidecar library to Android B builds.
+public final class AppFunctionManager {
+ private final android.app.appfunctions.AppFunctionManager mManager;
+ private final Context mContext;
+
+ /**
+ * Creates an instance.
+ *
+ * @param context A {@link Context}.
+ * @throws java.lang.IllegalStateException if the underlying {@link
+ * android.app.appfunctions.AppFunctionManager} is not found.
+ */
+ public AppFunctionManager(Context context) {
+ mContext = Objects.requireNonNull(context);
+ mManager = context.getSystemService(android.app.appfunctions.AppFunctionManager.class);
+ if (mManager == null) {
+ throw new IllegalStateException(
+ "Underlying AppFunctionManager system service not found.");
+ }
+ }
+
+ /**
+ * Executes the app function.
+ *
+ * <p>Proxies request and response to the underlying {@link
+ * android.app.appfunctions.AppFunctionManager#executeAppFunction}, converting the request and
+ * response in the appropriate type required by the function.
+ */
+ public void executeAppFunction(
+ @NonNull ExecuteAppFunctionRequest sidecarRequest,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<ExecuteAppFunctionResponse> callback) {
+ Objects.requireNonNull(sidecarRequest);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ android.app.appfunctions.ExecuteAppFunctionRequest platformRequest =
+ SidecarConverter.getPlatformExecuteAppFunctionRequest(sidecarRequest);
+ mManager.executeAppFunction(
+ platformRequest, executor, (platformResponse) -> {
+ callback.accept(SidecarConverter.getSidecarExecuteAppFunctionResponse(
+ platformResponse));
+ });
+ }
+}
diff --git a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionService.java b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionService.java
new file mode 100644
index 0000000..65959df
--- /dev/null
+++ b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/AppFunctionService.java
@@ -0,0 +1,114 @@
+/*
+ * 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.google.android.appfunctions.sidecar;
+
+import static android.Manifest.permission.BIND_APP_FUNCTION_SERVICE;
+
+import android.annotation.MainThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+
+import java.util.function.Consumer;
+
+/**
+ * Abstract base class to provide app functions to the system.
+ *
+ * <p>Include the following in the manifest:
+ *
+ * <pre>
+ * {@literal
+ * <service android:name=".YourService"
+ * android:permission="android.permission.BIND_APP_FUNCTION_SERVICE">
+ * <intent-filter>
+ * <action android:name="android.app.appfunctions.AppFunctionService" />
+ * </intent-filter>
+ * </service>
+ * }
+ * </pre>
+ *
+ * <p>This class wraps {@link android.app.appfunctions.AppFunctionService} functionalities and
+ * exposes it here as a sidecar library (avoiding direct dependency on the platform API).
+ *
+ * @see AppFunctionManager
+ */
+public abstract class AppFunctionService extends Service {
+ /**
+ * The permission to only allow system access to the functions through {@link
+ * AppFunctionManagerService}.
+ */
+ @NonNull
+ public static final String BIND_APP_FUNCTION_SERVICE =
+ "android.permission.BIND_APP_FUNCTION_SERVICE";
+
+ /**
+ * The {@link Intent} that must be declared as handled by the service. To be supported, the
+ * service must also require the {@link BIND_APP_FUNCTION_SERVICE} permission so that other
+ * applications can not abuse it.
+ */
+ @NonNull
+ public static final String SERVICE_INTERFACE = "android.app.appfunctions.AppFunctionService";
+
+ private final Binder mBinder =
+ android.app.appfunctions.AppFunctionService.createBinder(
+ /* context= */ this,
+ /* onExecuteFunction= */ (platformRequest, callback) -> {
+ AppFunctionService.this.onExecuteFunction(
+ SidecarConverter.getSidecarExecuteAppFunctionRequest(
+ platformRequest),
+ (sidecarResponse) -> {
+ callback.accept(
+ SidecarConverter.getPlatformExecuteAppFunctionResponse(
+ sidecarResponse));
+ });
+ }
+ );
+
+ @NonNull
+ @Override
+ public final IBinder onBind(@Nullable Intent intent) {
+ return mBinder;
+ }
+
+ /**
+ * Called by the system to execute a specific app function.
+ *
+ * <p>This method is triggered when the system requests your AppFunctionService to handle a
+ * particular function you have registered and made available.
+ *
+ * <p>To ensure proper routing of function requests, assign a unique identifier to each
+ * function. This identifier doesn't need to be globally unique, but it must be unique within
+ * your app. For example, a function to order food could be identified as "orderFood". In most
+ * cases this identifier should come from the ID automatically generated by the AppFunctions
+ * SDK. You can determine the specific function to invoke by calling {@link
+ * ExecuteAppFunctionRequest#getFunctionIdentifier()}.
+ *
+ * <p>This method is always triggered in the main thread. You should run heavy tasks on a worker
+ * thread and dispatch the result with the given callback. You should always report back the
+ * result using the callback, no matter if the execution was successful or not.
+ *
+ * @param request The function execution request.
+ * @param callback A callback to report back the result.
+ */
+ @MainThread
+ public abstract void onExecuteFunction(
+ @NonNull ExecuteAppFunctionRequest request,
+ @NonNull Consumer<ExecuteAppFunctionResponse> callback);
+}
diff --git a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionRequest.java b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionRequest.java
new file mode 100644
index 0000000..fa6d2ff
--- /dev/null
+++ b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionRequest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.google.android.appfunctions.sidecar;
+
+import android.annotation.NonNull;
+import android.app.appsearch.GenericDocument;
+import android.os.Bundle;
+
+import java.util.Objects;
+
+/**
+ * A request to execute an app function.
+ *
+ * <p>This class copies {@link android.app.appfunctions.ExecuteAppFunctionRequest} without parcel
+ * functionality and exposes it here as a sidecar library (avoiding direct dependency on the
+ * platform API).
+ */
+public final class ExecuteAppFunctionRequest {
+ /** Returns the package name of the app that hosts the function. */
+ @NonNull private final String mTargetPackageName;
+
+ /**
+ * Returns the unique string identifier of the app function to be executed. TODO(b/357551503):
+ * Document how callers can get the available function identifiers.
+ */
+ @NonNull private final String mFunctionIdentifier;
+
+ /** Returns additional metadata relevant to this function execution request. */
+ @NonNull private final Bundle mExtras;
+
+ /**
+ * Returns the parameters required to invoke this function. Within this [GenericDocument], the
+ * property names are the names of the function parameters and the property values are the
+ * values of those parameters.
+ *
+ * <p>The document may have missing parameters. Developers are advised to implement defensive
+ * handling measures.
+ *
+ * <p>TODO(b/357551503): Document how function parameters can be obtained for function execution
+ */
+ @NonNull private final GenericDocument mParameters;
+
+ private ExecuteAppFunctionRequest(
+ @NonNull String targetPackageName,
+ @NonNull String functionIdentifier,
+ @NonNull Bundle extras,
+ @NonNull GenericDocument parameters) {
+ mTargetPackageName = Objects.requireNonNull(targetPackageName);
+ mFunctionIdentifier = Objects.requireNonNull(functionIdentifier);
+ mExtras = Objects.requireNonNull(extras);
+ mParameters = Objects.requireNonNull(parameters);
+ }
+
+ /** Returns the package name of the app that hosts the function. */
+ @NonNull
+ public String getTargetPackageName() {
+ return mTargetPackageName;
+ }
+
+ /** Returns the unique string identifier of the app function to be executed. */
+ @NonNull
+ public String getFunctionIdentifier() {
+ return mFunctionIdentifier;
+ }
+
+ /**
+ * Returns the function parameters. The key is the parameter name, and the value is the
+ * parameter value.
+ *
+ * <p>The bundle may have missing parameters. Developers are advised to implement defensive
+ * handling measures.
+ */
+ @NonNull
+ public GenericDocument getParameters() {
+ return mParameters;
+ }
+
+ /** Returns the additional data relevant to this function execution. */
+ @NonNull
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ /** Builder for {@link ExecuteAppFunctionRequest}. */
+ public static final class Builder {
+ @NonNull private final String mTargetPackageName;
+ @NonNull private final String mFunctionIdentifier;
+ @NonNull private Bundle mExtras = Bundle.EMPTY;
+
+ @NonNull
+ private GenericDocument mParameters = new GenericDocument.Builder<>("", "", "").build();
+
+ public Builder(@NonNull String targetPackageName, @NonNull String functionIdentifier) {
+ mTargetPackageName = Objects.requireNonNull(targetPackageName);
+ mFunctionIdentifier = Objects.requireNonNull(functionIdentifier);
+ }
+
+ /** Sets the additional data relevant to this function execution. */
+ @NonNull
+ public Builder setExtras(@NonNull Bundle extras) {
+ mExtras = Objects.requireNonNull(extras);
+ return this;
+ }
+
+ /** Sets the function parameters. */
+ @NonNull
+ public Builder setParameters(@NonNull GenericDocument parameters) {
+ Objects.requireNonNull(parameters);
+ mParameters = parameters;
+ return this;
+ }
+
+ /** Builds the {@link ExecuteAppFunctionRequest}. */
+ @NonNull
+ public ExecuteAppFunctionRequest build() {
+ return new ExecuteAppFunctionRequest(
+ mTargetPackageName,
+ mFunctionIdentifier,
+ mExtras,
+ mParameters);
+ }
+ }
+}
diff --git a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionResponse.java b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionResponse.java
new file mode 100644
index 0000000..60c25fa
--- /dev/null
+++ b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/ExecuteAppFunctionResponse.java
@@ -0,0 +1,240 @@
+/*
+ * 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.google.android.appfunctions.sidecar;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.appsearch.GenericDocument;
+import android.os.Bundle;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * The response to an app function execution.
+ *
+ * <p>This class copies {@link android.app.appfunctions.ExecuteAppFunctionResponse} without parcel
+ * functionality and exposes it here as a sidecar library (avoiding direct dependency on the
+ * platform API).
+ */
+public final class ExecuteAppFunctionResponse {
+ /**
+ * The name of the property that stores the function return value within the {@code
+ * resultDocument}.
+ *
+ * <p>See {@link GenericDocument#getProperty(String)} for more information.
+ *
+ * <p>If the function returns {@code void} or throws an error, the {@code resultDocument} will
+ * be empty {@link GenericDocument}.
+ *
+ * <p>If the {@code resultDocument} is empty, {@link GenericDocument#getProperty(String)} will
+ * return {@code null}.
+ *
+ * <p>See {@link #getResultDocument} for more information on extracting the return value.
+ */
+ public static final String PROPERTY_RETURN_VALUE = "returnValue";
+
+ /** The call was successful. */
+ public static final int RESULT_OK = 0;
+
+ /** The caller does not have the permission to execute an app function. */
+ public static final int RESULT_DENIED = 1;
+
+ /** An unknown error occurred while processing the call in the AppFunctionService. */
+ public static final int RESULT_APP_UNKNOWN_ERROR = 2;
+
+ /**
+ * An internal error occurred within AppFunctionManagerService.
+ *
+ * <p>This error may be considered similar to {@link IllegalStateException}
+ */
+ public static final int RESULT_INTERNAL_ERROR = 3;
+
+ /**
+ * The caller supplied invalid arguments to the call.
+ *
+ * <p>This error may be considered similar to {@link IllegalArgumentException}.
+ */
+ public static final int RESULT_INVALID_ARGUMENT = 4;
+
+ /** The operation was timed out. */
+ public static final int RESULT_TIMED_OUT = 5;
+
+ /** The result code of the app function execution. */
+ @ResultCode private final int mResultCode;
+
+ /**
+ * The error message associated with the result, if any. This is {@code null} if the result code
+ * is {@link #RESULT_OK}.
+ */
+ @Nullable private final String mErrorMessage;
+
+ /**
+ * Returns the return value of the executed function.
+ *
+ * <p>The return value is stored in a {@link GenericDocument} with the key {@link
+ * #PROPERTY_RETURN_VALUE}.
+ *
+ * <p>See {@link #getResultDocument} for more information on extracting the return value.
+ */
+ @NonNull private final GenericDocument mResultDocument;
+
+ /** Returns the additional metadata data relevant to this function execution response. */
+ @NonNull private final Bundle mExtras;
+
+ private ExecuteAppFunctionResponse(
+ @NonNull GenericDocument resultDocument,
+ @NonNull Bundle extras,
+ @ResultCode int resultCode,
+ @Nullable String errorMessage) {
+ mResultDocument = Objects.requireNonNull(resultDocument);
+ mExtras = Objects.requireNonNull(extras);
+ mResultCode = resultCode;
+ mErrorMessage = errorMessage;
+ }
+
+ /**
+ * Returns result codes from throwable.
+ *
+ * @hide
+ */
+ static @ResultCode int getResultCode(@NonNull Throwable t) {
+ if (t instanceof IllegalArgumentException) {
+ return ExecuteAppFunctionResponse.RESULT_INVALID_ARGUMENT;
+ }
+ return ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR;
+ }
+
+ /**
+ * Returns a successful response.
+ *
+ * @param resultDocument The return value of the executed function.
+ * @param extras The additional metadata data relevant to this function execution response.
+ */
+ @NonNull
+ public static ExecuteAppFunctionResponse newSuccess(
+ @NonNull GenericDocument resultDocument, @Nullable Bundle extras) {
+ Objects.requireNonNull(resultDocument);
+ Bundle actualExtras = getActualExtras(extras);
+
+ return new ExecuteAppFunctionResponse(
+ resultDocument, actualExtras, RESULT_OK, /* errorMessage= */ null);
+ }
+
+ /**
+ * Returns a failure response.
+ *
+ * @param resultCode The result code of the app function execution.
+ * @param extras The additional metadata data relevant to this function execution response.
+ * @param errorMessage The error message associated with the result, if any.
+ */
+ @NonNull
+ public static ExecuteAppFunctionResponse newFailure(
+ @ResultCode int resultCode, @Nullable String errorMessage, @Nullable Bundle extras) {
+ if (resultCode == RESULT_OK) {
+ throw new IllegalArgumentException("resultCode must not be RESULT_OK");
+ }
+ Bundle actualExtras = getActualExtras(extras);
+ GenericDocument emptyDocument = new GenericDocument.Builder<>("", "", "").build();
+ return new ExecuteAppFunctionResponse(
+ emptyDocument, actualExtras, resultCode, errorMessage);
+ }
+
+ private static Bundle getActualExtras(@Nullable Bundle extras) {
+ if (extras == null) {
+ return Bundle.EMPTY;
+ }
+ return extras;
+ }
+
+ /**
+ * Returns a generic document containing the return value of the executed function.
+ *
+ * <p>The {@link #PROPERTY_RETURN_VALUE} key can be used to obtain the return value.
+ *
+ * <p>An empty document is returned if {@link #isSuccess} is {@code false} or if the executed
+ * function does not produce a return value.
+ *
+ * <p>Sample code for extracting the return value:
+ *
+ * <pre>
+ * GenericDocument resultDocument = response.getResultDocument();
+ * Object returnValue = resultDocument.getProperty(PROPERTY_RETURN_VALUE);
+ * if (returnValue != null) {
+ * // Cast returnValue to expected type, or use {@link GenericDocument#getPropertyString},
+ * // {@link GenericDocument#getPropertyLong} etc.
+ * // Do something with the returnValue
+ * }
+ * </pre>
+ */
+ @NonNull
+ public GenericDocument getResultDocument() {
+ return mResultDocument;
+ }
+
+ /** Returns the extras of the app function execution. */
+ @NonNull
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ /**
+ * Returns {@code true} if {@link #getResultCode} equals {@link
+ * ExecuteAppFunctionResponse#RESULT_OK}.
+ */
+ public boolean isSuccess() {
+ return getResultCode() == RESULT_OK;
+ }
+
+ /**
+ * Returns one of the {@code RESULT} constants defined in {@link ExecuteAppFunctionResponse}.
+ */
+ @ResultCode
+ public int getResultCode() {
+ return mResultCode;
+ }
+
+ /**
+ * Returns the error message associated with this result.
+ *
+ * <p>If {@link #isSuccess} is {@code true}, the error message is always {@code null}.
+ */
+ @Nullable
+ public String getErrorMessage() {
+ return mErrorMessage;
+ }
+
+ /**
+ * Result codes.
+ *
+ * @hide
+ */
+ @IntDef(
+ prefix = {"RESULT_"},
+ value = {
+ RESULT_OK,
+ RESULT_DENIED,
+ RESULT_APP_UNKNOWN_ERROR,
+ RESULT_INTERNAL_ERROR,
+ RESULT_INVALID_ARGUMENT,
+ RESULT_TIMED_OUT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ResultCode {}
+}
diff --git a/libs/appfunctions/java/com/google/android/appfunctions/sidecar/SidecarConverter.java b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/SidecarConverter.java
new file mode 100644
index 0000000..b1b05f7
--- /dev/null
+++ b/libs/appfunctions/java/com/google/android/appfunctions/sidecar/SidecarConverter.java
@@ -0,0 +1,104 @@
+/*
+ * 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.google.android.appfunctions.sidecar;
+
+import android.annotation.NonNull;
+
+/**
+ * Utility class containing methods to convert Sidecar objects of AppFunctions API into the
+ * underlying platform classes.
+ *
+ * @hide
+ */
+public final class SidecarConverter {
+ private SidecarConverter() {}
+
+ /**
+ * Converts sidecar's {@link com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest}
+ * into platform's {@link android.app.appfunctions.ExecuteAppFunctionRequest}
+ *
+ * @hide
+ */
+ @NonNull
+ public static android.app.appfunctions.ExecuteAppFunctionRequest
+ getPlatformExecuteAppFunctionRequest(@NonNull ExecuteAppFunctionRequest request) {
+ return new
+ android.app.appfunctions.ExecuteAppFunctionRequest.Builder(
+ request.getTargetPackageName(),
+ request.getFunctionIdentifier())
+ .setExtras(request.getExtras())
+ .setParameters(request.getParameters())
+ .build();
+ }
+
+ /**
+ * Converts sidecar's {@link com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse}
+ * into platform's {@link android.app.appfunctions.ExecuteAppFunctionResponse}
+ *
+ * @hide
+ */
+ @NonNull
+ public static android.app.appfunctions.ExecuteAppFunctionResponse
+ getPlatformExecuteAppFunctionResponse(@NonNull ExecuteAppFunctionResponse response) {
+ if (response.isSuccess()) {
+ return android.app.appfunctions.ExecuteAppFunctionResponse.newSuccess(
+ response.getResultDocument(), response.getExtras());
+ } else {
+ return android.app.appfunctions.ExecuteAppFunctionResponse.newFailure(
+ response.getResultCode(),
+ response.getErrorMessage(),
+ response.getExtras());
+ }
+ }
+
+ /**
+ * Converts platform's {@link android.app.appfunctions.ExecuteAppFunctionRequest}
+ * into sidecar's {@link com.google.android.appfunctions.sidecar.ExecuteAppFunctionRequest}
+ *
+ * @hide
+ */
+ @NonNull
+ public static ExecuteAppFunctionRequest getSidecarExecuteAppFunctionRequest(
+ @NonNull android.app.appfunctions.ExecuteAppFunctionRequest request) {
+ return new ExecuteAppFunctionRequest.Builder(
+ request.getTargetPackageName(),
+ request.getFunctionIdentifier())
+ .setExtras(request.getExtras())
+ .setParameters(request.getParameters())
+ .build();
+ }
+
+ /**
+ * Converts platform's {@link android.app.appfunctions.ExecuteAppFunctionResponse}
+ * into sidecar's {@link com.google.android.appfunctions.sidecar.ExecuteAppFunctionResponse}
+ *
+ * @hide
+ */
+ @NonNull
+ public static ExecuteAppFunctionResponse getSidecarExecuteAppFunctionResponse(
+ @NonNull android.app.appfunctions.ExecuteAppFunctionResponse response) {
+ if (response.isSuccess()) {
+ return ExecuteAppFunctionResponse.newSuccess(
+ response.getResultDocument(), response.getExtras());
+ } else {
+ return ExecuteAppFunctionResponse.newFailure(
+ response.getResultCode(),
+ response.getErrorMessage(),
+ response.getExtras());
+ }
+ }
+}
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 589abb4..2c23864 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -404,13 +404,19 @@
}
}
+inline bool RenderNode::isForceInvertDark(TreeInfo& info) {
+ return CC_UNLIKELY(
+ info.forceDarkType == android::uirenderer::ForceDarkType::FORCE_INVERT_COLOR_DARK);
+}
+
inline bool RenderNode::shouldEnableForceDark(TreeInfo* info) {
return CC_UNLIKELY(
info &&
- (!info->disableForceDark ||
- info->forceDarkType == android::uirenderer::ForceDarkType::FORCE_INVERT_COLOR_DARK));
+ (!info->disableForceDark || isForceInvertDark(*info)));
}
+
+
void RenderNode::handleForceDark(android::uirenderer::TreeInfo *info) {
if (!shouldEnableForceDark(info)) {
return;
@@ -421,7 +427,7 @@
children.push_back(node);
});
if (mDisplayList.hasText()) {
- if (mDisplayList.hasFill()) {
+ if (isForceInvertDark(*info) && mDisplayList.hasFill()) {
// Handle a special case for custom views that draw both text and background in the
// same RenderNode, which would otherwise be altered to white-on-white text.
usage = UsageHint::Container;
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index c904542..afbbce7 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -234,6 +234,7 @@
void syncDisplayList(TreeObserver& observer, TreeInfo* info);
void handleForceDark(TreeInfo* info);
bool shouldEnableForceDark(TreeInfo* info);
+ bool isForceInvertDark(TreeInfo& info);
void prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer);
void pushStagingPropertiesChanges(TreeInfo& info);
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 1854361..84bd45d 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -264,6 +264,7 @@
, mPixelStorageType(PixelStorageType::Heap) {
mPixelStorage.heap.address = address;
mPixelStorage.heap.size = size;
+ traceBitmapCreate();
}
Bitmap::Bitmap(SkPixelRef& pixelRef, const SkImageInfo& info)
@@ -272,6 +273,7 @@
, mPixelStorageType(PixelStorageType::WrappedPixelRef) {
pixelRef.ref();
mPixelStorage.wrapped.pixelRef = &pixelRef;
+ traceBitmapCreate();
}
Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes)
@@ -281,6 +283,7 @@
mPixelStorage.ashmem.address = address;
mPixelStorage.ashmem.fd = fd;
mPixelStorage.ashmem.size = mappedSize;
+ traceBitmapCreate();
}
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
@@ -297,10 +300,12 @@
setImmutable(); // HW bitmaps are always immutable
mImage = SkImages::DeferredFromAHardwareBuffer(buffer, mInfo.alphaType(),
mInfo.refColorSpace());
+ traceBitmapCreate();
}
#endif
Bitmap::~Bitmap() {
+ traceBitmapDelete();
switch (mPixelStorageType) {
case PixelStorageType::WrappedPixelRef:
mPixelStorage.wrapped.pixelRef->unref();
@@ -572,4 +577,28 @@
mGainmap = std::move(gainmap);
}
+std::mutex Bitmap::mLock{};
+size_t Bitmap::mTotalBitmapBytes = 0;
+size_t Bitmap::mTotalBitmapCount = 0;
+
+void Bitmap::traceBitmapCreate() {
+ if (ATRACE_ENABLED()) {
+ std::lock_guard lock{mLock};
+ mTotalBitmapBytes += getAllocationByteCount();
+ mTotalBitmapCount++;
+ ATRACE_INT64("Bitmap Memory", mTotalBitmapBytes);
+ ATRACE_INT64("Bitmap Count", mTotalBitmapCount);
+ }
+}
+
+void Bitmap::traceBitmapDelete() {
+ if (ATRACE_ENABLED()) {
+ std::lock_guard lock{mLock};
+ mTotalBitmapBytes -= getAllocationByteCount();
+ mTotalBitmapCount--;
+ ATRACE_INT64("Bitmap Memory", mTotalBitmapBytes);
+ ATRACE_INT64("Bitmap Count", mTotalBitmapCount);
+ }
+}
+
} // namespace android
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index dd344e2..3d55d85 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -25,6 +25,7 @@
#include <cutils/compiler.h>
#include <utils/StrongPointer.h>
+#include <mutex>
#include <optional>
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
@@ -227,6 +228,13 @@
} mPixelStorage;
sk_sp<SkImage> mImage; // Cache is used only for HW Bitmaps with Skia pipeline.
+
+ // for tracing total number and memory usage of bitmaps
+ static std::mutex mLock;
+ static size_t mTotalBitmapBytes;
+ static size_t mTotalBitmapCount;
+ void traceBitmapCreate();
+ void traceBitmapDelete();
};
} // namespace android
diff --git a/libs/hwui/hwui/DrawTextFunctor.h b/libs/hwui/hwui/DrawTextFunctor.h
index d7bf201..e13e1365 100644
--- a/libs/hwui/hwui/DrawTextFunctor.h
+++ b/libs/hwui/hwui/DrawTextFunctor.h
@@ -73,6 +73,7 @@
}
paint->setStrokeJoin(SkPaint::kRound_Join);
paint->setLooper(nullptr);
+ paint->setBlendMode(SkBlendMode::kSrcOver);
}
class DrawTextFunctor {
diff --git a/libs/hwui/jni/GraphicsStatsService.cpp b/libs/hwui/jni/GraphicsStatsService.cpp
index 54369b9..80a8ae1 100644
--- a/libs/hwui/jni/GraphicsStatsService.cpp
+++ b/libs/hwui/jni/GraphicsStatsService.cpp
@@ -42,8 +42,9 @@
return reinterpret_cast<jlong>(dump);
}
-static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jstring jpackage,
- jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
+static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jint uid,
+ jstring jpackage, jlong versionCode, jlong startTime, jlong endTime,
+ jbyteArray jdata) {
std::string path;
const ProfileData* data = nullptr;
LOG_ALWAYS_FATAL_IF(jdata == nullptr && jpath == nullptr, "Path and data can't both be null");
@@ -68,7 +69,8 @@
LOG_ALWAYS_FATAL_IF(!dump, "null passed for dump pointer");
const std::string package(packageChars.c_str(), packageChars.size());
- GraphicsStatsService::addToDump(dump, path, package, versionCode, startTime, endTime, data);
+ GraphicsStatsService::addToDump(dump, path, static_cast<uid_t>(uid), package, versionCode,
+ startTime, endTime, data);
}
static void addFileToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath) {
@@ -91,7 +93,7 @@
GraphicsStatsService::finishDumpInMemory(dump, data, lastFullDay == JNI_TRUE);
}
-static void saveBuffer(JNIEnv* env, jobject clazz, jstring jpath, jstring jpackage,
+static void saveBuffer(JNIEnv* env, jobject clazz, jstring jpath, jint uid, jstring jpackage,
jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
ScopedByteArrayRO buffer(env, jdata);
LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
@@ -106,7 +108,8 @@
const std::string path(pathChars.c_str(), pathChars.size());
const std::string package(packageChars.c_str(), packageChars.size());
const ProfileData* data = reinterpret_cast<const ProfileData*>(buffer.get());
- GraphicsStatsService::saveBuffer(path, package, versionCode, startTime, endTime, data);
+ GraphicsStatsService::saveBuffer(path, static_cast<uid_t>(uid), package, versionCode, startTime,
+ endTime, data);
}
static jobject gGraphicsStatsServiceObject = nullptr;
@@ -173,16 +176,16 @@
} // namespace android
using namespace android;
-static const JNINativeMethod sMethods[] =
- {{"nGetAshmemSize", "()I", (void*)getAshmemSize},
- {"nCreateDump", "(IZ)J", (void*)createDump},
- {"nAddToDump", "(JLjava/lang/String;Ljava/lang/String;JJJ[B)V", (void*)addToDump},
- {"nAddToDump", "(JLjava/lang/String;)V", (void*)addFileToDump},
- {"nFinishDump", "(J)V", (void*)finishDump},
- {"nFinishDumpInMemory", "(JJZ)V", (void*)finishDumpInMemory},
- {"nSaveBuffer", "(Ljava/lang/String;Ljava/lang/String;JJJ[B)V", (void*)saveBuffer},
- {"nativeInit", "()V", (void*)nativeInit},
- {"nativeDestructor", "()V", (void*)nativeDestructor}};
+static const JNINativeMethod sMethods[] = {
+ {"nGetAshmemSize", "()I", (void*)getAshmemSize},
+ {"nCreateDump", "(IZ)J", (void*)createDump},
+ {"nAddToDump", "(JLjava/lang/String;ILjava/lang/String;JJJ[B)V", (void*)addToDump},
+ {"nAddToDump", "(JLjava/lang/String;)V", (void*)addFileToDump},
+ {"nFinishDump", "(J)V", (void*)finishDump},
+ {"nFinishDumpInMemory", "(JJZ)V", (void*)finishDumpInMemory},
+ {"nSaveBuffer", "(Ljava/lang/String;ILjava/lang/String;JJJ[B)V", (void*)saveBuffer},
+ {"nativeInit", "()V", (void*)nativeInit},
+ {"nativeDestructor", "()V", (void*)nativeDestructor}};
int register_android_graphics_GraphicsStatsService(JNIEnv* env) {
jclass graphicsStatsService_class =
diff --git a/libs/hwui/platform/host/thread/ThreadBase.h b/libs/hwui/platform/host/thread/ThreadBase.h
index d709430..b4e7bd3 100644
--- a/libs/hwui/platform/host/thread/ThreadBase.h
+++ b/libs/hwui/platform/host/thread/ThreadBase.h
@@ -48,7 +48,7 @@
nsecs_t nextWakeup = mQueue.nextWakeup(lock);
std::chrono::nanoseconds duration = std::chrono::nanoseconds::max();
if (nextWakeup < std::numeric_limits<nsecs_t>::max()) {
- int timeout = nextWakeup - WorkQueue::clock::now();
+ nsecs_t timeout = nextWakeup - WorkQueue::clock::now();
if (timeout < 0) timeout = 0;
duration = std::chrono::nanoseconds(timeout);
}
diff --git a/libs/hwui/protos/graphicsstats.proto b/libs/hwui/protos/graphicsstats.proto
index 745393c..a6e786c 100644
--- a/libs/hwui/protos/graphicsstats.proto
+++ b/libs/hwui/protos/graphicsstats.proto
@@ -58,6 +58,9 @@
// HWUI renders pipeline type: GL or Vulkan
optional PipelineType pipeline = 8;
+
+ // The UID of the app
+ optional int32 uid = 9;
}
message GraphicsStatsJankSummaryProto {
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index ece5905..702f2a5 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -22,6 +22,7 @@
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <inttypes.h>
#include <log/log.h>
+#include <stats_annotations.h>
#include <stats_event.h>
#include <statslog_hwui.h>
#include <sys/mman.h>
@@ -45,9 +46,9 @@
constexpr int sHistogramSize = ProfileData::HistogramSize();
constexpr int sGPUHistogramSize = ProfileData::GPUHistogramSize();
-static bool mergeProfileDataIntoProto(protos::GraphicsStatsProto* proto, const std::string& package,
- int64_t versionCode, int64_t startTime, int64_t endTime,
- const ProfileData* data);
+static bool mergeProfileDataIntoProto(protos::GraphicsStatsProto* proto, uid_t uid,
+ const std::string& package, int64_t versionCode,
+ int64_t startTime, int64_t endTime, const ProfileData* data);
static void dumpAsTextToFd(protos::GraphicsStatsProto* proto, int outFd);
class FileDescriptor {
@@ -159,15 +160,16 @@
return success;
}
-bool mergeProfileDataIntoProto(protos::GraphicsStatsProto* proto, const std::string& package,
- int64_t versionCode, int64_t startTime, int64_t endTime,
- const ProfileData* data) {
+bool mergeProfileDataIntoProto(protos::GraphicsStatsProto* proto, uid_t uid,
+ const std::string& package, int64_t versionCode, int64_t startTime,
+ int64_t endTime, const ProfileData* data) {
if (proto->stats_start() == 0 || proto->stats_start() > startTime) {
proto->set_stats_start(startTime);
}
if (proto->stats_end() == 0 || proto->stats_end() < endTime) {
proto->set_stats_end(endTime);
}
+ proto->set_uid(static_cast<int32_t>(uid));
proto->set_package_name(package);
proto->set_version_code(versionCode);
proto->set_pipeline(data->pipelineType() == RenderPipelineType::SkiaGL ?
@@ -286,6 +288,7 @@
proto->package_name().c_str(), proto->has_summary());
return;
}
+ dprintf(fd, "\nUID: %d", proto->uid());
dprintf(fd, "\nPackage: %s", proto->package_name().c_str());
dprintf(fd, "\nVersion: %" PRId64, proto->version_code());
dprintf(fd, "\nStats since: %" PRId64 "ns", proto->stats_start());
@@ -319,14 +322,15 @@
dprintf(fd, "\n");
}
-void GraphicsStatsService::saveBuffer(const std::string& path, const std::string& package,
- int64_t versionCode, int64_t startTime, int64_t endTime,
- const ProfileData* data) {
+void GraphicsStatsService::saveBuffer(const std::string& path, uid_t uid,
+ const std::string& package, int64_t versionCode,
+ int64_t startTime, int64_t endTime, const ProfileData* data) {
protos::GraphicsStatsProto statsProto;
if (!parseFromFile(path, &statsProto)) {
statsProto.Clear();
}
- if (!mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data)) {
+ if (!mergeProfileDataIntoProto(&statsProto, uid, package, versionCode, startTime, endTime,
+ data)) {
return;
}
// Although we might not have read any data from the file, merging the existing data
@@ -383,7 +387,7 @@
private:
// use package name and app version for a key
- typedef std::pair<std::string, int64_t> DumpKey;
+ typedef std::tuple<uid_t, std::string, int64_t> DumpKey;
std::map<DumpKey, protos::GraphicsStatsProto> mStats;
int mFd;
@@ -392,7 +396,8 @@
};
void GraphicsStatsService::Dump::mergeStat(const protos::GraphicsStatsProto& stat) {
- auto dumpKey = std::make_pair(stat.package_name(), stat.version_code());
+ auto dumpKey = std::make_tuple(static_cast<uid_t>(stat.uid()), stat.package_name(),
+ stat.version_code());
auto findIt = mStats.find(dumpKey);
if (findIt == mStats.end()) {
mStats[dumpKey] = stat;
@@ -437,15 +442,15 @@
return new Dump(outFd, type);
}
-void GraphicsStatsService::addToDump(Dump* dump, const std::string& path,
+void GraphicsStatsService::addToDump(Dump* dump, const std::string& path, uid_t uid,
const std::string& package, int64_t versionCode,
int64_t startTime, int64_t endTime, const ProfileData* data) {
protos::GraphicsStatsProto statsProto;
if (!path.empty() && !parseFromFile(path, &statsProto)) {
statsProto.Clear();
}
- if (data &&
- !mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data)) {
+ if (data && !mergeProfileDataIntoProto(&statsProto, uid, package, versionCode, startTime,
+ endTime, data)) {
return;
}
if (!statsProto.IsInitialized()) {
@@ -556,6 +561,8 @@
// TODO: fill in UI mainline module version, when the feature is available.
AStatsEvent_writeInt64(event, (int64_t)0);
AStatsEvent_writeBool(event, !lastFullDay);
+ AStatsEvent_writeInt32(event, stat.uid());
+ AStatsEvent_addBoolAnnotation(event, ASTATSLOG_ANNOTATION_ID_IS_UID, true);
AStatsEvent_build(event);
}
delete dump;
diff --git a/libs/hwui/service/GraphicsStatsService.h b/libs/hwui/service/GraphicsStatsService.h
index 4063f74..68c7355 100644
--- a/libs/hwui/service/GraphicsStatsService.h
+++ b/libs/hwui/service/GraphicsStatsService.h
@@ -44,13 +44,14 @@
ProtobufStatsd,
};
- static void saveBuffer(const std::string& path, const std::string& package, int64_t versionCode,
- int64_t startTime, int64_t endTime, const ProfileData* data);
+ static void saveBuffer(const std::string& path, uid_t uid, const std::string& package,
+ int64_t versionCode, int64_t startTime, int64_t endTime,
+ const ProfileData* data);
static Dump* createDump(int outFd, DumpType type);
- static void addToDump(Dump* dump, const std::string& path, const std::string& package,
- int64_t versionCode, int64_t startTime, int64_t endTime,
- const ProfileData* data);
+ static void addToDump(Dump* dump, const std::string& path, uid_t uid,
+ const std::string& package, int64_t versionCode, int64_t startTime,
+ int64_t endTime, const ProfileData* data);
static void addToDump(Dump* dump, const std::string& path);
static void finishDump(Dump* dump);
static void finishDumpInMemory(Dump* dump, AStatsEventList* data, bool lastFullDay);
diff --git a/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp b/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
index c2d23e6..eb164f9 100644
--- a/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
+++ b/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
@@ -62,6 +62,7 @@
TEST(GraphicsStats, saveLoad) {
std::string path = findRootPath() + "/test_saveLoad";
+ uid_t uid = 123;
std::string packageName = "com.test.saveLoad";
MockProfileData mockData;
mockData.editJankFrameCount() = 20;
@@ -75,12 +76,13 @@
for (size_t i = 0; i < mockData.editSlowFrameCounts().size(); i++) {
mockData.editSlowFrameCounts()[i] = (i % 5) + 1;
}
- GraphicsStatsService::saveBuffer(path, packageName, 5, 3000, 7000, &mockData);
+ GraphicsStatsService::saveBuffer(path, uid, packageName, 5, 3000, 7000, &mockData);
protos::GraphicsStatsProto loadedProto;
EXPECT_TRUE(GraphicsStatsService::parseFromFile(path, &loadedProto));
// Clean up the file
unlink(path.c_str());
+ EXPECT_EQ(uid, loadedProto.uid());
EXPECT_EQ(packageName, loadedProto.package_name());
EXPECT_EQ(5, loadedProto.version_code());
EXPECT_EQ(3000, loadedProto.stats_start());
@@ -109,6 +111,7 @@
TEST(GraphicsStats, merge) {
std::string path = findRootPath() + "/test_merge";
std::string packageName = "com.test.merge";
+ uid_t uid = 123;
MockProfileData mockData;
mockData.editJankFrameCount() = 20;
mockData.editTotalFrameCount() = 100;
@@ -121,7 +124,7 @@
for (size_t i = 0; i < mockData.editSlowFrameCounts().size(); i++) {
mockData.editSlowFrameCounts()[i] = (i % 5) + 1;
}
- GraphicsStatsService::saveBuffer(path, packageName, 5, 3000, 7000, &mockData);
+ GraphicsStatsService::saveBuffer(path, uid, packageName, 5, 3000, 7000, &mockData);
mockData.editJankFrameCount() = 50;
mockData.editTotalFrameCount() = 500;
for (size_t i = 0; i < mockData.editFrameCounts().size(); i++) {
@@ -130,13 +133,15 @@
for (size_t i = 0; i < mockData.editSlowFrameCounts().size(); i++) {
mockData.editSlowFrameCounts()[i] = ((i % 10) + 1) * 2;
}
- GraphicsStatsService::saveBuffer(path, packageName, 5, 7050, 10000, &mockData);
+
+ GraphicsStatsService::saveBuffer(path, uid, packageName, 5, 7050, 10000, &mockData);
protos::GraphicsStatsProto loadedProto;
EXPECT_TRUE(GraphicsStatsService::parseFromFile(path, &loadedProto));
// Clean up the file
unlink(path.c_str());
+ EXPECT_EQ(uid, loadedProto.uid());
EXPECT_EQ(packageName, loadedProto.package_name());
EXPECT_EQ(5, loadedProto.version_code());
EXPECT_EQ(3000, loadedProto.stats_start());
diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp
index 1afef75..d993b87 100644
--- a/libs/input/MouseCursorController.cpp
+++ b/libs/input/MouseCursorController.cpp
@@ -64,25 +64,6 @@
mLocked.pointerSprite.clear();
}
-std::optional<FloatRect> MouseCursorController::getBounds() const {
- std::scoped_lock lock(mLock);
-
- return getBoundsLocked();
-}
-
-std::optional<FloatRect> MouseCursorController::getBoundsLocked() const REQUIRES(mLock) {
- if (!mLocked.viewport.isValid()) {
- return {};
- }
-
- return FloatRect{
- static_cast<float>(mLocked.viewport.logicalLeft),
- static_cast<float>(mLocked.viewport.logicalTop),
- static_cast<float>(mLocked.viewport.logicalRight - 1),
- static_cast<float>(mLocked.viewport.logicalBottom - 1),
- };
-}
-
void MouseCursorController::move(float deltaX, float deltaY) {
#if DEBUG_MOUSE_CURSOR_UPDATES
ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
@@ -105,11 +86,20 @@
}
void MouseCursorController::setPositionLocked(float x, float y) REQUIRES(mLock) {
- const auto bounds = getBoundsLocked();
- if (!bounds) return;
+ const auto& v = mLocked.viewport;
+ if (!v.isValid()) return;
- mLocked.pointerX = std::max(bounds->left, std::min(bounds->right, x));
- mLocked.pointerY = std::max(bounds->top, std::min(bounds->bottom, y));
+ // The valid bounds for a mouse cursor. Since the right and bottom edges are considered outside
+ // the display, clip the bounds by one pixel instead of letting the cursor get arbitrarily
+ // close to the outside edge.
+ const FloatRect bounds{
+ static_cast<float>(mLocked.viewport.logicalLeft),
+ static_cast<float>(mLocked.viewport.logicalTop),
+ static_cast<float>(mLocked.viewport.logicalRight - 1),
+ static_cast<float>(mLocked.viewport.logicalBottom - 1),
+ };
+ mLocked.pointerX = std::max(bounds.left, std::min(bounds.right, x));
+ mLocked.pointerY = std::max(bounds.top, std::min(bounds.bottom, y));
updatePointerLocked();
}
@@ -216,9 +206,11 @@
// Reset cursor position to center if size or display changed.
if (oldViewport.displayId != viewport.displayId || oldDisplayWidth != newDisplayWidth ||
oldDisplayHeight != newDisplayHeight) {
- if (const auto bounds = getBoundsLocked(); bounds) {
- mLocked.pointerX = (bounds->left + bounds->right) * 0.5f;
- mLocked.pointerY = (bounds->top + bounds->bottom) * 0.5f;
+ if (viewport.isValid()) {
+ // Use integer coordinates as the starting point for the cursor location.
+ // We usually expect display sizes to be even numbers, so the flooring is precautionary.
+ mLocked.pointerX = std::floor((viewport.logicalLeft + viewport.logicalRight) / 2);
+ mLocked.pointerY = std::floor((viewport.logicalTop + viewport.logicalBottom) / 2);
// Reload icon resources for density may be changed.
loadResourcesLocked(getAdditionalMouseResources);
} else {
diff --git a/libs/input/MouseCursorController.h b/libs/input/MouseCursorController.h
index 8600341..12b31a8 100644
--- a/libs/input/MouseCursorController.h
+++ b/libs/input/MouseCursorController.h
@@ -43,7 +43,6 @@
MouseCursorController(PointerControllerContext& context);
~MouseCursorController();
- std::optional<FloatRect> getBounds() const;
void move(float deltaX, float deltaY);
void setPosition(float x, float y);
FloatPoint getPosition() const;
@@ -104,7 +103,6 @@
} mLocked GUARDED_BY(mLock);
- std::optional<FloatRect> getBoundsLocked() const;
void setPositionLocked(float x, float y);
void updatePointerLocked();
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 5ae967b..78d7d3a 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -138,10 +138,6 @@
return mDisplayInfoListener->mLock;
}
-std::optional<FloatRect> PointerController::getBounds() const {
- return mCursorController.getBounds();
-}
-
void PointerController::move(float deltaX, float deltaY) {
const ui::LogicalDisplayId displayId = mCursorController.getDisplayId();
vec2 transformed;
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 4d1e1d7..ee8d121 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -51,7 +51,6 @@
~PointerController() override;
- std::optional<FloatRect> getBounds() const override;
void move(float deltaX, float deltaY) override;
void setPosition(float x, float y) override;
FloatPoint getPosition() const override;
@@ -166,9 +165,6 @@
~TouchPointerController() override;
- std::optional<FloatRect> getBounds() const override {
- LOG_ALWAYS_FATAL("Should not be called");
- }
void move(float, float) override {
LOG_ALWAYS_FATAL("Should not be called");
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 6342489..306643d 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -451,7 +451,7 @@
private static final long MAX_SINGLE_LOCATION_TIMEOUT_MS = 30 * 1000;
private static final String CACHE_KEY_LOCATION_ENABLED_PROPERTY =
- "cache_key.location_enabled";
+ PropertyInvalidatedCache.createSystemCacheKey("location_enabled");
static ILocationManager getService() throws RemoteException {
try {
diff --git a/location/java/android/location/flags/location.aconfig b/location/java/android/location/flags/location.aconfig
index dcf5c5b..c3cb492 100644
--- a/location/java/android/location/flags/location.aconfig
+++ b/location/java/android/location/flags/location.aconfig
@@ -94,6 +94,16 @@
}
flag {
+ name: "use_legacy_ntp_time"
+ namespace: "location"
+ description: "Flag for switching to legacy NtpNetworkTimeHelper"
+ bug: "368034558"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "subscriptions_changed_listener_thread"
namespace: "location"
description: "Flag for running onSubscriptionsChangedListener on FgThread"
@@ -111,6 +121,17 @@
}
flag {
+ name: "enable_ni_supl_message_injection_by_carrier_config_bugfix"
+ namespace: "location"
+ description: "Flag for enabling NI SUPL message injection by carrier config"
+ bug: "242105192"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "enable_ni_supl_message_injection_by_carrier_config"
namespace: "location"
description: "Flag for enabling NI SUPL message injection by carrier config"
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e2e7a46..cdb517b3 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -6318,7 +6318,14 @@
/**
* @hide
* Get the audio devices that would be used for the routing of the given audio attributes.
- * @param attributes the {@link AudioAttributes} for which the routing is being queried
+ * @param attributes the {@link AudioAttributes} for which the routing is being queried.
+ * For queries about output devices (playback use cases), a valid usage must be specified in
+ * the audio attributes via AudioAttributes.Builder.setUsage(). The capture preset MUST NOT
+ * be changed from default.
+ * For queries about input devices (capture use case), a valid capture preset MUST be
+ * specified in the audio attributes via AudioAttributes.Builder.setCapturePreset(). If a
+ * capture preset is present, then this has precedence over any usage or content type also
+ * present in the audio attrirutes.
* @return an empty list if there was an issue with the request, a list of audio devices
* otherwise (typically one device, except for duplicated paths).
*/
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 9af6b28..8394daf 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -709,6 +709,10 @@
@EnforcePermission("MODIFY_AUDIO_ROUTING")
List<AudioFocusInfo> getFocusStack();
+ @EnforcePermission("MODIFY_AUDIO_ROUTING")
+ oneway void sendFocusLossAndUpdate(in AudioFocusInfo focusLoser, in IAudioPolicyCallback apcb);
+
+ @EnforcePermission("MODIFY_AUDIO_ROUTING")
boolean sendFocusLoss(in AudioFocusInfo focusLoser, in IAudioPolicyCallback apcb);
@EnforcePermission("MODIFY_AUDIO_ROUTING")
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 293a8f8..2c8e352 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -927,6 +927,29 @@
}
/**
+ * @hide
+ * Causes the given audio focus owner to lose audio focus with
+ * {@link android.media.AudioManager#AUDIOFOCUS_LOSS}, and be removed from the focus stack.
+ * Unlike {@link #sendFocusLoss(AudioFocusInfo)}, the method causes the focus stack
+ * to be reevaluated as the discarded focus owner may have been at the top of stack,
+ * and now the new owner needs to be notified of the gain.
+ * @param focusLoser identifies the focus owner to discard from the focus stack
+ * @throws IllegalStateException if used on an unregistered policy, or a registered policy
+ * with no {@link AudioPolicyFocusListener} set
+ * @see #getFocusStack()
+ * @see #sendFocusLoss(AudioFocusInfo)
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public void sendFocusLossAndUpdate(@NonNull AudioFocusInfo focusLoser)
+ throws IllegalStateException {
+ try {
+ getService().sendFocusLossAndUpdate(Objects.requireNonNull(focusLoser), cb());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Send AUDIOFOCUS_LOSS to a specific stack entry, causing it to be notified of the focus
* loss, and for it to exit the focus stack (its focus listener will not be invoked after that).
* This operation is only valid for a registered policy (with
diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java
index 244292d..bfc1324 100644
--- a/media/java/android/media/midi/MidiManager.java
+++ b/media/java/android/media/midi/MidiManager.java
@@ -393,6 +393,16 @@
/**
* Opens a Bluetooth MIDI device for reading and writing.
+ * Bluetooth MIDI devices are only available after openBluetoothDevice() is called.
+ * Once that happens anywhere in the system, then the BLE-MIDI device will appear as just
+ * another MidiDevice to other apps.
+ *
+ * If the device opened using openBluetoothDevice() is closed, then it will no longer be
+ * available. To other apps, it will appear as if the BLE MidiDevice had been unplugged.
+ * If a MidiDevice is garbage collected then it will be closed automatically.
+ * If you want the BLE-MIDI device to remain available you should keep the object alive.
+ *
+ * You may close the device with MidiDevice.close().
*
* @param bluetoothDevice a {@link android.bluetooth.BluetoothDevice} to open as a MIDI device
* @param listener a {@link MidiManager.OnDeviceOpenedListener} to be called to receive the
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 3cc0ad2..31f8996 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -90,24 +90,24 @@
mDisplayManager = displayManager;
}
- /**
- * Register a listener to receive notifications about when the {@link MediaProjection} or captured
- * content changes state.
- *
- * <p>The callback must be registered before invoking {@link #createVirtualDisplay(String, int,
- * int, int, int, Surface, VirtualDisplay.Callback, Handler)} to ensure that any notifications on
- * the callback are not missed. The client must implement {@link Callback#onStop()} and clean up
- * any resources it is holding, e.g. the {@link VirtualDisplay} and {@link Surface}. This should
- * also update any application UI indicating the MediaProjection status as MediaProjection has
- * stopped.
- *
- * @param callback The callback to call.
- * @param handler The handler on which the callback should be invoked, or null if the callback
- * should be invoked on the calling thread's looper.
- * @throws NullPointerException If the given callback is null.
- * @see #unregisterCallback
- */
- public void registerCallback(@NonNull Callback callback, @Nullable Handler handler) {
+ /**
+ * Register a listener to receive notifications about when the {@link MediaProjection} or
+ * captured content changes state.
+ *
+ * <p>The callback must be registered before invoking {@link #createVirtualDisplay(String, int,
+ * int, int, int, Surface, VirtualDisplay.Callback, Handler)} to ensure that any notifications
+ * on the callback are not missed. The client must implement {@link Callback#onStop()} to
+ * properly handle MediaProjection clean up any resources it is holding, e.g. the {@link
+ * VirtualDisplay} and {@link Surface}. This should also update any application UI indicating
+ * the MediaProjection status as MediaProjection has stopped.
+ *
+ * @param callback The callback to call.
+ * @param handler The handler on which the callback should be invoked, or null if the callback
+ * should be invoked on the calling thread's looper.
+ * @throws NullPointerException If the given callback is null.
+ * @see #unregisterCallback
+ */
+ public void registerCallback(@NonNull Callback callback, @Nullable Handler handler) {
try {
final Callback c = Objects.requireNonNull(callback);
if (handler == null) {
@@ -313,7 +313,7 @@
*/
public abstract static class Callback {
/**
- * Called when the MediaProjection session is no longer valid.
+ * Called when the MediaProjection session has been stopped and is no longer valid.
*
* <p>Once a MediaProjection has been stopped, it's up to the application to release any
* resources it may be holding (e.g. releasing the {@link VirtualDisplay} and {@link
@@ -321,9 +321,9 @@
* it should be updated to indicate that MediaProjection is no longer active.
*
* <p>MediaProjection stopping can be a result of the system stopping the ongoing
- * MediaProjection due to various reasons, such as another MediaProjection session starting.
- * MediaProjection may also stop due to the user explicitly stopping ongoing MediaProjection
- * via any available system-level UI.
+ * MediaProjection due to various reasons, such as another MediaProjection session starting,
+ * a user stopping the session via UI affordances in system-level UI, or the screen being
+ * locked.
*
* <p>After this callback any call to {@link MediaProjection#createVirtualDisplay} will
* fail, even if no such {@link VirtualDisplay} was ever created for this MediaProjection
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index 03fd2c6..dc55e41 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -60,13 +60,14 @@
* <li>Register a {@link MediaProjection.Callback} by calling {@link
* MediaProjection#registerCallback(MediaProjection.Callback, Handler)}. This is required to
* receive notifications about when the {@link MediaProjection} or captured content changes
- * state. When receiving an `onStop()` callback, the client must clean up any resources it is
- * holding, e.g. the {@link VirtualDisplay} and {@link Surface}. The MediaProjection may
- * further no longer create any new {@link VirtualDisplay}s via {@link
- * MediaProjection#createVirtualDisplay(String, int, int, int, int, Surface,
- * VirtualDisplay.Callback, Handler)}. Note that the `onStop()` callback can be a result of
- * the system stopping MediaProjection due to various reasons or the user stopping the
- * MediaProjection via UI affordances in system-level UI.
+ * state. When receiving an `onStop()` callback the {@link MediaProjection} session has been
+ * finished and the client must clean up any resources it is holding, e.g. the {@link
+ * VirtualDisplay} and {@link Surface}. The MediaProjection may further no longer create any
+ * new {@link VirtualDisplay}s via {@link MediaProjection#createVirtualDisplay(String, int,
+ * int, int, int, Surface, VirtualDisplay.Callback, Handler)}. Note that the `onStop()`
+ * callback can be a result of the system stopping MediaProjection due to various reasons.
+ * This includes the user stopping the MediaProjection via UI affordances in system-level UI,
+ * the screen being locked, or another {@link MediaProjection} session starting.
* <li>Start the screen capture session for media projection by calling {@link
* MediaProjection#createVirtualDisplay(String, int, int, int, int, Surface,
* android.hardware.display.VirtualDisplay.Callback, Handler)}.
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index bc8a7af..9603c0a 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -60,8 +60,13 @@
method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public java.util.List<java.lang.String> getActiveNfceeList();
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void maybeTriggerFirmwareUpdate();
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcOemExtension.Callback);
+ method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void setControllerAlwaysOn(int);
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void synchronizeScreenState();
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void unregisterCallback(@NonNull android.nfc.NfcOemExtension.Callback);
+ field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int DISABLE = 0; // 0x0
+ field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int ENABLE_DEFAULT = 1; // 0x1
+ field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int ENABLE_EE = 3; // 0x3
+ field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int ENABLE_TRANSPARENT = 2; // 0x2
field public static final int HCE_ACTIVATE = 1; // 0x1
field public static final int HCE_DATA_TRANSFERRED = 2; // 0x2
field public static final int HCE_DEACTIVATE = 3; // 0x3
diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
index e2ec952..246efc7 100644
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
@@ -73,7 +73,7 @@
boolean setNfcSecure(boolean enable);
NfcAntennaInfo getNfcAntennaInfo();
- boolean setControllerAlwaysOn(boolean value);
+ void setControllerAlwaysOn(int mode);
boolean isControllerAlwaysOn();
boolean isControllerAlwaysOnSupported();
void registerControllerAlwaysOnListener(in INfcControllerAlwaysOnListener listener);
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index f478793..2804546 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -258,7 +258,7 @@
/**
* Mandatory String extra field in {@link #ACTION_TRANSACTION_DETECTED}
* Indicates the Secure Element on which the transaction occurred.
- * eSE1...eSEn for Embedded Secure Elements, SIM1...SIMn for UICC, etc.
+ * eSE1...eSEn for Embedded Secure Elements, SIM1...SIMn for UICC/EUICC, etc.
*/
public static final String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME";
@@ -559,6 +559,18 @@
@Retention(RetentionPolicy.SOURCE)
public @interface TagIntentAppPreferenceResult {}
+ /**
+ * Mode Type for {@link NfcOemExtension#setControllerAlwaysOn(int)}.
+ * @hide
+ */
+ public static final int CONTROLLER_ALWAYS_ON_MODE_DEFAULT = 1;
+
+ /**
+ * Mode Type for {@link NfcOemExtension#setControllerAlwaysOn(int)}.
+ * @hide
+ */
+ public static final int CONTROLLER_ALWAYS_ON_DISABLE = 0;
+
// Guarded by sLock
static boolean sIsInitialized = false;
static boolean sHasNfcFeature;
@@ -721,7 +733,7 @@
*
* @return List<String> containing secure elements on the device which supports
* off host card emulation. eSE for Embedded secure element,
- * SIM for UICC, eSIM for EUICC and so on.
+ * SIM for UICC/EUICC and so on.
* @hide
*/
public @NonNull List<String> getSupportedOffHostSecureElements() {
@@ -741,11 +753,6 @@
if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE)) {
offHostSE.add("eSE");
}
- if (Flags.enableCardEmulationEuicc()
- && callServiceReturn(
- () -> sCardEmulationService.isEuiccSupported(), false)) {
- offHostSE.add("eSIM");
- }
return offHostSE;
}
@@ -2330,7 +2337,8 @@
* FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
* FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
* are unavailable
- * @return void
+ * @return true if feature is supported by the device and operation has bee initiated,
+ * false if the feature is not supported by the device.
* @hide
*/
@SystemApi
@@ -2339,8 +2347,13 @@
if (!sHasNfcFeature && !sHasCeFeature) {
throw new UnsupportedOperationException();
}
- return callServiceReturn(() -> sService.setControllerAlwaysOn(value), false);
-
+ int mode = value ? CONTROLLER_ALWAYS_ON_MODE_DEFAULT : CONTROLLER_ALWAYS_ON_DISABLE;
+ try {
+ callService(() -> sService.setControllerAlwaysOn(mode));
+ } catch (UnsupportedOperationException e) {
+ return false;
+ }
+ return true;
}
/**
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
index d51b704..45038d4 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -70,6 +70,58 @@
private boolean mRfDiscoveryStarted = false;
/**
+ * Mode Type for {@link #setControllerAlwaysOn(int)}.
+ * Enables the controller in default mode when NFC is disabled (existing API behavior).
+ * works same as {@link NfcAdapter#setControllerAlwaysOn(boolean)}.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ public static final int ENABLE_DEFAULT = NfcAdapter.CONTROLLER_ALWAYS_ON_MODE_DEFAULT;
+
+ /**
+ * Mode Type for {@link #setControllerAlwaysOn(int)}.
+ * Enables the controller in transparent mode when NFC is disabled.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ public static final int ENABLE_TRANSPARENT = 2;
+
+ /**
+ * Mode Type for {@link #setControllerAlwaysOn(int)}.
+ * Enables the controller and initializes and enables the EE subsystem when NFC is disabled.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ public static final int ENABLE_EE = 3;
+
+ /**
+ * Mode Type for {@link #setControllerAlwaysOn(int)}.
+ * Disable the Controller Always On Mode.
+ * works same as {@link NfcAdapter#setControllerAlwaysOn(boolean)}.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ public static final int DISABLE = NfcAdapter.CONTROLLER_ALWAYS_ON_DISABLE;
+
+ /**
+ * Possible controller modes for {@link #setControllerAlwaysOn(int)}.
+ *
+ * @hide
+ */
+ @IntDef(prefix = { "" }, value = {
+ ENABLE_DEFAULT,
+ ENABLE_TRANSPARENT,
+ ENABLE_EE,
+ DISABLE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ControllerMode{}
+
+ /**
* Event that Host Card Emulation is activated.
*/
public static final int HCE_ACTIVATE = 1;
@@ -389,6 +441,32 @@
NfcAdapter.sService.fetchActiveNfceeList(), new ArrayList<String>());
}
+ /**
+ * Sets NFC controller always on feature.
+ * <p>This API is for the NFCC internal state management. It allows to discriminate
+ * the controller function from the NFC function by keeping the NFC controller on without
+ * any NFC RF enabled if necessary.
+ * <p>This call is asynchronous, register listener {@link NfcAdapter.ControllerAlwaysOnListener}
+ * by {@link NfcAdapter#registerControllerAlwaysOnListener} to find out when the operation is
+ * complete.
+ * @param mode one of {@link ControllerMode} modes
+ * @throws UnsupportedOperationException if
+ * <li> if FEATURE_NFC, FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
+ * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
+ * are unavailable </li>
+ * <li> if the feature is unavailable @see NfcAdapter#isNfcControllerAlwaysOnSupported() </li>
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
+ public void setControllerAlwaysOn(@ControllerMode int mode) {
+ if (!NfcAdapter.sHasNfcFeature && !NfcAdapter.sHasCeFeature) {
+ throw new UnsupportedOperationException();
+ }
+ NfcAdapter.callService(() -> NfcAdapter.sService.setControllerAlwaysOn(mode));
+ }
+
private final class NfcOemExtensionCallback extends INfcOemExtensionCallback.Stub {
@Override
diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
index b28237c..2983875 100644
--- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -331,8 +331,6 @@
mOffHostName = "eSE1";
} else if (mOffHostName.equals("SIM")) {
mOffHostName = "SIM1";
- } else if (Flags.enableCardEmulationEuicc() && mOffHostName.equals("eSIM")) {
- mOffHostName = "eSIM1";
}
}
mStaticOffHostName = mOffHostName;
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index 83ad32c..4be082c 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -548,13 +548,11 @@
List<String> validSE = adapter.getSupportedOffHostSecureElements();
if ((offHostSecureElement.startsWith("eSE") && !validSE.contains("eSE"))
- || (offHostSecureElement.startsWith("SIM") && !validSE.contains("SIM"))
- || (offHostSecureElement.startsWith("eSIM") && !validSE.contains("eSIM"))) {
+ || (offHostSecureElement.startsWith("SIM") && !validSE.contains("SIM"))) {
return false;
}
- if (!offHostSecureElement.startsWith("eSE") && !offHostSecureElement.startsWith("SIM")
- && !(Flags.enableCardEmulationEuicc() && offHostSecureElement.startsWith("eSIM"))) {
+ if (!offHostSecureElement.startsWith("eSE") && !offHostSecureElement.startsWith("SIM")) {
return false;
}
@@ -562,8 +560,6 @@
offHostSecureElement = "eSE1";
} else if (offHostSecureElement.equals("SIM")) {
offHostSecureElement = "SIM1";
- } else if (Flags.enableCardEmulationEuicc() && offHostSecureElement.equals("eSIM")) {
- offHostSecureElement = "eSIM1";
}
final String offHostSecureElementV = new String(offHostSecureElement);
return callServiceReturn(() ->
diff --git a/packages/CarrierDefaultApp/res/values-bs/strings.xml b/packages/CarrierDefaultApp/res/values-bs/strings.xml
index 4fad224..bc725fe 100644
--- a/packages/CarrierDefaultApp/res/values-bs/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-bs/strings.xml
@@ -16,7 +16,7 @@
<string name="ssl_error_continue" msgid="1138548463994095584">"Ipak nastavi preko preglednika"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Pojačavanje performansi"</string>
<string name="performance_boost_notification_title" msgid="3126203390685781861">"Opcije 5G mreže operatera"</string>
- <string name="performance_boost_notification_detail" msgid="216569851036236346">"Posjetite web lokaciju operatera %s da vidite opcije za iskustvo u aplikaciji"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Posjetite web lokaciju operatera %s da vidite opcije za iskustvo s aplikacijom"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ne sada"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Upravljajte"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Kupite pojačavanje performansi."</string>
diff --git a/packages/PackageInstaller/Android.bp b/packages/PackageInstaller/Android.bp
index bd84b58..a30c0c3 100644
--- a/packages/PackageInstaller/Android.bp
+++ b/packages/PackageInstaller/Android.bp
@@ -13,6 +13,7 @@
// limitations under the License.
package {
+ default_team: "trendy_team_framework_android_packages",
default_applicable_licenses: [
"frameworks_base_packages_PackageInstaller_license",
],
diff --git a/packages/PackageInstaller/TEST_MAPPING b/packages/PackageInstaller/TEST_MAPPING
index 717ec02..91882fd 100644
--- a/packages/PackageInstaller/TEST_MAPPING
+++ b/packages/PackageInstaller/TEST_MAPPING
@@ -65,6 +65,17 @@
"name": "CtsIntentSignatureTestCases"
},
{
+ "name": "CtsPackageInstallerCUJDeviceAdminTestCases",
+ "options":[
+ {
+ "exclude-annotation":"androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation":"org.junit.Ignore"
+ }
+ ]
+ },
+ {
"name": "CtsPackageInstallerCUJInstallationTestCases",
"options":[
{
@@ -76,6 +87,17 @@
]
},
{
+ "name": "CtsPackageInstallerCUJMultiUsersTestCases",
+ "options":[
+ {
+ "exclude-annotation":"androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation":"org.junit.Ignore"
+ }
+ ]
+ },
+ {
"name": "CtsPackageInstallerCUJUninstallationTestCases",
"options":[
{
diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp
index 996477c..1661dfb 100644
--- a/packages/SettingsLib/SettingsTheme/Android.bp
+++ b/packages/SettingsLib/SettingsTheme/Android.bp
@@ -10,8 +10,15 @@
android_library {
name: "SettingsLibSettingsTheme",
use_resource_processor: true,
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
resource_dirs: ["res"],
- static_libs: ["androidx.preference_preference"],
+ static_libs: [
+ "androidx.preference_preference",
+ "com.google.android.material_material",
+ ],
sdk_version: "system_current",
min_sdk_version: "21",
apex_available: [
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_check.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_check.xml
new file mode 100644
index 0000000..309dbdf
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_check.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M382,720L154,492L211,435L382,606L749,239L806,296L382,720Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_close.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_close.xml
new file mode 100644
index 0000000..e6df8a4
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_close.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M256,760L200,704L424,480L200,256L256,200L480,424L704,200L760,256L536,480L760,704L704,760L480,536L256,760Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_switch_thumb_icon.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_switch_thumb_icon.xml
new file mode 100644
index 0000000..342729d
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_switch_thumb_icon.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_checked="true" android:drawable="@drawable/settingslib_expressive_icon_check"/>
+ <item android:state_checked="false" android:drawable="@drawable/settingslib_expressive_icon_close"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom_selected.xml
index f4766ee..543b237 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom_selected.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom_selected.xml
@@ -26,7 +26,10 @@
<solid
android:color="@color/settingslib_materialColorSurfaceContainer" />
<corners
- android:radius="@dimen/settingslib_preference_corner_radius_selected" />
+ android:topLeftRadius="4dp"
+ android:bottomLeftRadius="@dimen/settingslib_preference_corner_radius"
+ android:topRightRadius="4dp"
+ android:bottomRightRadius="@dimen/settingslib_preference_corner_radius" />
<padding
android:bottom="16dp"/>
</shape>
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center_selected.xml
index 40eafc2..6d2cd1a 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center_selected.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center_selected.xml
@@ -25,7 +25,7 @@
<solid
android:color="@color/settingslib_materialColorSurfaceContainer" />
<corners
- android:radius="@dimen/settingslib_preference_corner_radius_selected" />
+ android:radius="4dp" />
</shape>
</item>
</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_selected.xml
index f4766ee..bcdbf1d 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_selected.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_selected.xml
@@ -26,7 +26,7 @@
<solid
android:color="@color/settingslib_materialColorSurfaceContainer" />
<corners
- android:radius="@dimen/settingslib_preference_corner_radius_selected" />
+ android:radius="@dimen/settingslib_preference_corner_radius" />
<padding
android:bottom="16dp"/>
</shape>
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top_selected.xml
index 40eafc2..d4b658c 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top_selected.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top_selected.xml
@@ -25,7 +25,10 @@
<solid
android:color="@color/settingslib_materialColorSurfaceContainer" />
<corners
- android:radius="@dimen/settingslib_preference_corner_radius_selected" />
+ android:topLeftRadius="@dimen/settingslib_preference_corner_radius"
+ android:bottomLeftRadius="4dp"
+ android:topRightRadius="@dimen/settingslib_preference_corner_radius"
+ android:bottomRightRadius="4dp" />
</shape>
</item>
</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference.xml
new file mode 100644
index 0000000..2475dfd
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ 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">
+
+ <include layout="@layout/settingslib_expressive_preference_icon_frame"/>
+
+ <include layout="@layout/settingslib_expressive_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/SettingsTheme/res/layout-v35/settingslib_expressive_preference_icon_frame.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_icon_frame.xml
new file mode 100644
index 0000000..f5017a5
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_icon_frame.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/icon_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="@dimen/settingslib_expressive_space_medium3"
+ android:minHeight="@dimen/settingslib_expressive_space_medium3"
+ android:gravity="center"
+ android:layout_marginEnd="-8dp">
+
+ <androidx.preference.internal.PreferenceImageView
+ android:id="@android:id/icon"
+ android:layout_width="@dimen/settingslib_expressive_space_medium3"
+ android:layout_height="@dimen/settingslib_expressive_space_medium3"
+ android:scaleType="centerInside"/>
+
+</LinearLayout>
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_switch.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_switch.xml
new file mode 100644
index 0000000..4cbdfd5
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_switch.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<com.google.android.material.materialswitch.MaterialSwitch
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:theme="@style/Theme.Material3.DynamicColors.DayNight"
+ android:id="@+id/switchWidget"
+ style="@style/SettingslibSwitchStyle.Expressive"/>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_text_frame.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_text_frame.xml
new file mode 100644
index 0000000..e3e689b
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_text_frame.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<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:padding="@dimen/settingslib_expressive_space_small1">
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:maxLines="2"
+ 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_alignLeft="@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>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/dimens_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/dimens_expressive.xml
new file mode 100644
index 0000000..2320aab
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-v35/dimens_expressive.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <!-- Expressive design start -->
+ <!-- corner radius token -->
+ <dimen name="settingslib_expressive_radius_none">0dp</dimen>
+ <dimen name="settingslib_expressive_radius_full">360dp</dimen>
+ <dimen name="settingslib_expressive_radius_extrasmall1">2dp</dimen>
+ <dimen name="settingslib_expressive_radius_extrasmall2">4dp</dimen>
+ <dimen name="settingslib_expressive_radius_small">8dp</dimen>
+ <dimen name="settingslib_expressive_radius_medium">12dp</dimen>
+ <dimen name="settingslib_expressive_radius_large1">16dp</dimen>
+ <dimen name="settingslib_expressive_radius_large2">20dp</dimen>
+ <dimen name="settingslib_expressive_radius_large3">24dp</dimen>
+ <dimen name="settingslib_expressive_radius_extralarge1">28dp</dimen>
+ <dimen name="settingslib_expressive_radius_extralarge2">32dp</dimen>
+ <dimen name="settingslib_expressive_radius_extralarge3">42dp</dimen>
+
+ <!-- space token -->
+ <dimen name="settingslib_expressive_space_none">0dp</dimen>
+ <dimen name="settingslib_expressive_space_extrasmall1">2dp</dimen>
+ <dimen name="settingslib_expressive_space_extrasmall2">4dp</dimen>
+ <dimen name="settingslib_expressive_space_extrasmall3">6dp</dimen>
+ <dimen name="settingslib_expressive_space_extrasmall4">8dp</dimen>
+ <dimen name="settingslib_expressive_space_extrasmall5">10dp</dimen>
+ <dimen name="settingslib_expressive_space_extrasmall6">12dp</dimen>
+ <dimen name="settingslib_expressive_space_extrasmall7">14dp</dimen>
+ <dimen name="settingslib_expressive_space_small1">16dp</dimen>
+ <dimen name="settingslib_expressive_space_small2">18dp</dimen>
+ <dimen name="settingslib_expressive_space_small3">20dp</dimen>
+ <dimen name="settingslib_expressive_space_small4">24dp</dimen>
+ <dimen name="settingslib_expressive_space_medium1">32dp</dimen>
+ <dimen name="settingslib_expressive_space_medium2">36dp</dimen>
+ <dimen name="settingslib_expressive_space_medium3">40dp</dimen>
+ <dimen name="settingslib_expressive_space_medium4">48dp</dimen>
+ <dimen name="settingslib_expressive_space_large1">60dp</dimen>
+ <dimen name="settingslib_expressive_space_large2">64dp</dimen>
+ <dimen name="settingslib_expressive_space_large3">72dp</dimen>
+ <dimen name="settingslib_expressive_space_large4">80dp</dimen>
+ <dimen name="settingslib_expressive_space_large5">96dp</dimen>
+ <!-- Expressive theme end -->
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/styles_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/styles_expressive.xml
new file mode 100644
index 0000000..04ae80e
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-v35/styles_expressive.xml
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <style name="SettingsLibTextAppearance" parent="@android:style/TextAppearance.DeviceDefault">
+ <!--item name="android:fontFamily"></item-->
+ <item name="android:hyphenationFrequency">normalFast</item>
+ <item name="android:lineBreakWordStyle">phrase</item>
+ </style>
+
+ <style name="SettingsLibTextAppearance.Primary">
+ <!--item name="android:fontFamily"></item-->
+ </style>
+
+ <style name="SettingsLibTextAppearance.Primary.Display">
+ <!--item name="android:fontFamily"></item-->
+ </style>
+ <style name="SettingsLibTextAppearance.Primary.Display.Large">
+ <item name="android:textSize">57sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Primary.Display.Medium">
+ <item name="android:textSize">45sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Primary.Display.Small">
+ <item name="android:textSize">36sp</item>
+ </style>
+
+ <style name="SettingsLibTextAppearance.Primary.Headline">
+ <!--item name="android:fontFamily"></item-->
+ </style>
+ <style name="SettingsLibTextAppearance.Primary.Headline.Large">
+ <item name="android:textSize">32sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Primary.Headline.Medium">
+ <item name="android:textSize">28sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Primary.Headline.Small">
+ <item name="android:textSize">24sp</item>
+ </style>
+
+ <style name="SettingsLibTextAppearance.Primary.Title">
+ <!--item name="android:fontFamily"></item-->
+ </style>
+ <style name="SettingsLibTextAppearance.Primary.Title.Large">
+ <item name="android:textSize">22sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Primary.Title.Medium">
+ <item name="android:textSize">16sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Primary.Title.Small">
+ <item name="android:textSize">14sp</item>
+ </style>
+
+ <style name="SettingsLibTextAppearance.Primary.Label">
+ <!--item name="android:fontFamily"></item-->
+ </style>
+ <style name="SettingsLibTextAppearance.Primary.Label.Large">
+ <item name="android:textSize">14sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Primary.Label.Medium">
+ <item name="android:textSize">12sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Primary.Label.Small">
+ <item name="android:textSize">11sp</item>
+ </style>
+
+ <style name="SettingsLibTextAppearance.Primary.Body">
+ <!--item name="android:fontFamily"></item-->
+ </style>
+ <style name="SettingsLibTextAppearance.Primary.Body.Large">
+ <item name="android:textSize">16sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Primary.Body.Medium">
+ <item name="android:textSize">14sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Primary.Body.Small">
+ <item name="android:textSize">12sp</item>
+ </style>
+
+ <style name="SettingsLibTextAppearance.Emphasized">
+ <!--item name="android:fontFamily"></item-->
+ </style>
+
+ <style name="SettingsLibTextAppearance.Emphasized.Display">
+ <!--item name="android:fontFamily"></item-->
+ </style>
+ <style name="SettingsLibTextAppearance.Emphasized.Display.Large">
+ <item name="android:textSize">57sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Emphasized.Display.Medium">
+ <item name="android:textSize">45sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Emphasized.Display.Small">
+ <item name="android:textSize">36sp</item>
+ </style>
+
+ <style name="SettingsLibTextAppearance.Emphasized.Headline">
+ <!--item name="android:fontFamily"></item-->
+ </style>
+ <style name="SettingsLibTextAppearance.Emphasized.Headline.Large">
+ <item name="android:textSize">32sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Emphasized.Headline.Medium">
+ <item name="android:textSize">28sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Emphasized.Headline.Small">
+ <item name="android:textSize">24sp</item>
+ </style>
+
+ <style name="SettingsLibTextAppearance.Emphasized.Title">
+ <!--item name="android:fontFamily"></item-->
+ </style>
+ <style name="SettingsLibTextAppearance.Emphasized.Title.Large">
+ <item name="android:textSize">22sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Emphasized.Title.Medium">
+ <item name="android:textSize">16sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Emphasized.Title.Small">
+ <item name="android:textSize">14sp</item>
+ </style>
+
+ <style name="SettingsLibTextAppearance.Emphasized.Label">
+ <!--item name="android:fontFamily"></item-->
+ </style>
+ <style name="SettingsLibTextAppearance.Emphasized.Label.Large">
+ <item name="android:textSize">14sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Emphasized.Label.Medium">
+ <item name="android:textSize">12sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Emphasized.Label.Small">
+ <item name="android:textSize">11sp</item>
+ </style>
+
+ <style name="SettingsLibTextAppearance.Emphasized.Body">
+ <!--item name="android:fontFamily"></item-->
+ </style>
+ <style name="SettingsLibTextAppearance.Emphasized.Body.Large">
+ <item name="android:textSize">16sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Emphasized.Body.Medium">
+ <item name="android:textSize">14sp</item>
+ </style>
+ <style name="SettingsLibTextAppearance.Emphasized.Body.Small">
+ <item name="android:textSize">12sp</item>
+ </style>
+
+ <style name="SettingslibSwitchStyle.Expressive" parent="">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:minWidth">@dimen/settingslib_expressive_space_medium4</item>
+ <item name="android:background">@null</item>
+ <item name="android:clickable">false</item>
+ <item name="android:focusable">false</item>
+ <item name="thumbIcon">@drawable/settingslib_expressive_switch_thumb_icon</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/styles_preference_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/styles_preference_expressive.xml
new file mode 100644
index 0000000..3c69027
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-v35/styles_preference_expressive.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<resources>
+ <style name="SettingsLibPreference" parent="SettingsPreference.SettingsLib"/>
+
+ <style name="SettingsLibPreference.Category" parent="SettingsCategoryPreference.SettingsLib"/>
+
+ <style name="SettingsLibPreference.CheckBoxPreference" parent="SettingsCheckBoxPreference.SettingsLib"/>
+
+ <style name="SettingsLibPreference.SwitchPreferenceCompat" parent="SettingsSwitchPreferenceCompat.SettingsLib"/>
+
+ <style name="SettingsLibPreference.SeekBarPreference" parent="SettingsSeekbarPreference.SettingsLib"/>
+
+ <style name="SettingsLibPreference.PreferenceScreen" parent="SettingsPreferenceScreen.SettingsLib"/>
+
+ <style name="SettingsLibPreference.DialogPreference" parent="SettingsPreference.SettingsLib"/>
+
+ <style name="SettingsLibPreference.DialogPreference.EditTextPreference" parent="SettingsEditTextPreference.SettingsLib"/>
+
+ <style name="SettingsLibPreference.DropDown" parent="SettingsDropdownPreference.SettingsLib"/>
+
+ <style name="SettingsLibPreference.SwitchPreference" parent="SettingsSwitchPreference.SettingsLib"/>
+
+ <style name="SettingsLibPreference.Expressive">
+ <item name="android:layout">@layout/settingslib_expressive_preference</item>
+ </style>
+
+ <style name="SettingsLibPreference.Category.Expressive">
+ </style>
+
+ <style name="SettingsLibPreference.CheckBoxPreference.Expressive">
+ <item name="android:layout">@layout/settingslib_expressive_preference</item>
+ </style>
+
+ <style name="SettingsLibPreference.SwitchPreferenceCompat.Expressive">
+ <item name="android:layout">@layout/settingslib_expressive_preference</item>
+ <item name="android:widgetLayout">@layout/settingslib_expressive_preference_switch</item>
+ </style>
+
+ <style name="SettingsLibPreference.SeekBarPreference.Expressive"/>
+
+ <style name="SettingsLibPreference.PreferenceScreen.Expressive">
+ <item name="android:layout">@layout/settingslib_expressive_preference</item>
+ </style>
+
+ <style name="SettingsLibPreference.DialogPreference.Expressive">
+ </style>
+
+ <style name="SettingsLibPreference.DialogPreference.EditTextPreference.Expressive">
+ <item name="android:layout">@layout/settingslib_expressive_preference</item>
+ <item name="android:dialogLayout">@layout/settingslib_preference_dialog_edittext</item>
+ </style>
+
+ <style name="SettingsLibPreference.DropDown.Expressive">
+ </style>
+
+ <style name="SettingsLibPreference.SwitchPreference.Expressive"/>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/themes_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/themes_expressive.xml
new file mode 100644
index 0000000..fea8739
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-v35/themes_expressive.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <style name="Theme.SettingsBase.Expressive">
+ <!-- Set up Preference title text style -->
+ <!--item name="android:textAppearanceListItem">@style/TextAppearance.PreferenceTitle.SettingsLib</item-->
+ <!--item name="android:textAppearanceListItemSecondary">@style/textAppearanceListItemSecondary</item-->
+
+ <!-- Set up list item padding -->
+ <item name="android:listPreferredItemPaddingStart">@dimen/settingslib_expressive_space_small1</item>
+ <item name="android:listPreferredItemPaddingLeft">@dimen/settingslib_expressive_space_small1</item>
+ <item name="android:listPreferredItemPaddingEnd">@dimen/settingslib_expressive_space_small1</item>
+ <item name="android:listPreferredItemPaddingRight">@dimen/settingslib_expressive_space_small1</item>
+ <item name="android:listPreferredItemHeightSmall">@dimen/settingslib_expressive_space_large3</item>
+
+ <!-- Set up preference theme -->
+ <item name="preferenceTheme">@style/PreferenceTheme.SettingsLib.Expressive</item>
+
+ <!-- Set up Spinner style -->
+ <!--item name="android:spinnerStyle"></item>
+ <item name="android:spinnerItemStyle"></item>
+ <item name="android:spinnerDropDownItemStyle"></item-->
+
+ <!-- Set up edge-to-edge configuration for top app bar -->
+ <item name="android:clipToPadding">false</item>
+ <item name="android:clipChildren">false</item>
+ </style>
+
+ <!-- Using in SubSettings page including injected settings page -->
+ <style name="Theme.SubSettingsBase.Expressive" parent="Theme.SettingsBase.Expressive">
+ <!-- Suppress the built-in action bar -->
+ <item name="android:windowActionBar">false</item>
+ <item name="android:windowNoTitle">true</item>
+
+ <!-- Set up edge-to-edge configuration for top app bar -->
+ <item name="android:navigationBarColor">@android:color/transparent</item>
+ <item name="android:statusBarColor">@android:color/transparent</item>
+ <item name="colorControlNormal">?android:attr/colorControlNormal</item>
+
+ <!-- For AndroidX AlertDialog -->
+ <!--item name="alertDialogTheme">@style/Theme.AlertDialog.SettingsLib</item-->
+ </style>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/themes_preference_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/themes_preference_expressive.xml
new file mode 100644
index 0000000..41fe225
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-v35/themes_preference_expressive.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <style name="PreferenceTheme.SettingsLib.Expressive">
+ <item name="checkBoxPreferenceStyle">@style/SettingsLibPreference.CheckBoxPreference.Expressive</item>
+ <item name="dialogPreferenceStyle">@style/SettingsLibPreference.DialogPreference.Expressive</item>
+ <item name="dropdownPreferenceStyle">@style/SettingsLibPreference.DropDown.Expressive</item>
+ <item name="editTextPreferenceStyle">@style/SettingsLibPreference.DialogPreference.EditTextPreference.Expressive</item>
+ <item name="seekBarPreferenceStyle">@style/SettingsLibPreference.SeekBarPreference.Expressive</item>
+ <item name="preferenceCategoryStyle">@style/SettingsLibPreference.Category.Expressive</item>
+ <item name="preferenceScreenStyle">@style/SettingsLibPreference.PreferenceScreen.Expressive</item>
+ <item name="preferenceStyle">@style/SettingsLibPreference.Expressive</item>
+ <item name="switchPreferenceCompatStyle">@style/SettingsLibPreference.SwitchPreferenceCompat.Expressive</item>
+ <item name="preferenceCategoryTitleTextAppearance">@style/TextAppearance.CategoryTitle.SettingsLib</item>
+ <item name="preferenceCategoryTitleTextColor">@color/settingslib_materialColorPrimary</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt
new file mode 100644
index 0000000..10e5267
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt
@@ -0,0 +1,78 @@
+/*
+* 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.settingslib.widget
+
+import android.content.Context
+import android.os.Build
+import android.os.SystemProperties
+
+object SettingsThemeHelper {
+ private const val IS_EXPRESSIVE_DESIGN_ENABLED = "is_expressive_design_enabled"
+ private var expressiveThemeState: ExpressiveThemeState = ExpressiveThemeState.UNKNOWN
+
+ enum class ExpressiveThemeState {
+ UNKNOWN,
+ ENABLED,
+ DISABLED,
+ }
+
+ @JvmStatic
+ fun isExpressiveTheme(context: Context): Boolean {
+ tryInit(context)
+ if (expressiveThemeState == ExpressiveThemeState.UNKNOWN) {
+ throw Exception(
+ "need to call com.android.settingslib.widget.SettingsThemeHelper.init(Context) first."
+ )
+ }
+
+ return expressiveThemeState == ExpressiveThemeState.ENABLED
+ }
+
+ private fun tryInit(context: Context) {
+ if (expressiveThemeState != ExpressiveThemeState.UNKNOWN) {
+ return
+ }
+
+ expressiveThemeState =
+ if (
+ (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) &&
+ (SystemProperties.getBoolean(IS_EXPRESSIVE_DESIGN_ENABLED, false) ||
+ getPropBoolean(context, IS_EXPRESSIVE_DESIGN_ENABLED, false))
+ ) {
+ ExpressiveThemeState.ENABLED
+ } else {
+ ExpressiveThemeState.DISABLED
+ }
+ }
+
+ private fun getPropBoolean(context: Context, property: String, def: Boolean): Boolean {
+ return try {
+ val systemProperties = context.classLoader.loadClass("android.os.SystemProperties")
+
+ val paramTypes =
+ arrayOf<Class<*>?>(String::class.java, Boolean::class.javaPrimitiveType)
+ val getBoolean = systemProperties.getMethod("getBoolean", *paramTypes)
+
+ val params = arrayOf<Any>(property, def)
+ getBoolean.invoke(systemProperties, *params) as Boolean
+ } catch (iae: IllegalArgumentException) {
+ throw iae
+ } catch (exception: Exception) {
+ def
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/SettingsBanner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/SettingsBanner.kt
index e3f4860..185fd29 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/SettingsBanner.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/SettingsBanner.kt
@@ -19,6 +19,7 @@
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.ExperimentalLayoutApi
@@ -55,6 +56,7 @@
import com.android.settingslib.spa.framework.theme.SettingsShape.CornerExtraLarge
import com.android.settingslib.spa.framework.theme.SettingsShape.CornerExtraSmall
import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled
import com.android.settingslib.spa.widget.ui.SettingsBody
import com.android.settingslib.spa.widget.ui.SettingsTitle
@@ -62,15 +64,13 @@
fun SettingsBanner(content: @Composable ColumnScope.() -> Unit) {
Card(
shape = CornerExtraLarge,
- colors = CardDefaults.cardColors(
- containerColor = Color.Transparent,
- ),
- modifier = Modifier
- .fillMaxWidth()
- .padding(
- horizontal = SettingsDimension.itemPaddingEnd,
- vertical = SettingsDimension.itemPaddingAround,
- ),
+ colors = CardDefaults.cardColors(containerColor = Color.Transparent),
+ modifier =
+ Modifier.fillMaxWidth()
+ .padding(
+ horizontal = SettingsDimension.itemPaddingEnd,
+ vertical = SettingsDimension.itemPaddingAround,
+ ),
content = content,
)
}
@@ -81,40 +81,64 @@
content: @Composable ColumnScope.() -> Unit,
) {
Card(
- shape = CornerExtraSmall,
- colors = CardDefaults.cardColors(
- containerColor = containerColor.takeOrElse { MaterialTheme.colorScheme.surface },
- ),
- modifier = Modifier
- .fillMaxWidth()
- .padding(vertical = 1.dp),
+ shape = if (isSpaExpressiveEnabled) CornerExtraLarge else CornerExtraSmall,
+ colors =
+ CardDefaults.cardColors(
+ containerColor = containerColor.takeOrElse { MaterialTheme.colorScheme.surface }
+ ),
+ modifier = Modifier.fillMaxWidth().padding(vertical = 1.dp),
content = content,
)
}
@Composable
fun SettingsBanner(model: BannerModel) {
- SettingsBanner {
- SettingsBannerImpl(model)
- }
+ SettingsBanner { SettingsBannerImpl(model) }
}
@Composable
internal fun SettingsBannerImpl(model: BannerModel) {
AnimatedVisibility(visible = model.isVisible()) {
SettingsBannerContent(containerColor = model.containerColor) {
- Column(
- modifier = (model.onClick?.let { Modifier.clickable(onClick = it) } ?: Modifier)
- .padding(
- horizontal = SettingsDimension.dialogItemPaddingHorizontal,
- vertical = SettingsDimension.itemPaddingAround,
- ),
- verticalArrangement = Arrangement.spacedBy(SettingsDimension.itemPaddingAround)
- ) {
- BannerHeader(model.imageVector, model.tintColor, model.onDismiss)
- SettingsTitle(model.title)
- SettingsBody(model.text)
- Buttons(model.buttons, model.tintColor)
+ if (isSpaExpressiveEnabled) {
+ Column(
+ modifier =
+ (model.onClick?.let { Modifier.clickable(onClick = it) } ?: Modifier)
+ .padding(
+ start = SettingsDimension.paddingLarge,
+ end = SettingsDimension.paddingLarge,
+ top = SettingsDimension.paddingLarge,
+ bottom = SettingsDimension.paddingSmall,
+ )
+ ) {
+ Row(verticalAlignment = Alignment.CenterVertically) {
+ BannerIcon(model.imageVector, model.tintColor)
+ Column(
+ modifier = Modifier.padding(start = SettingsDimension.paddingLarge),
+ verticalArrangement =
+ Arrangement.spacedBy(SettingsDimension.itemPaddingAround),
+ ) {
+ BannerTitleHeader(model.title, model.onDismiss)
+ SettingsBody(model.text)
+ }
+ }
+ Buttons(model.buttons, model.tintColor)
+ }
+ } else {
+ Column(
+ modifier =
+ (model.onClick?.let { Modifier.clickable(onClick = it) } ?: Modifier)
+ .padding(
+ horizontal = SettingsDimension.dialogItemPaddingHorizontal,
+ vertical = SettingsDimension.itemPaddingAround,
+ ),
+ verticalArrangement = Arrangement.spacedBy(SettingsDimension.itemPaddingAround),
+ ) {
+ BannerHeader(model.imageVector, model.tintColor, model.onDismiss)
+ SettingsTitle(model.title)
+ SettingsBody(model.text)
+ Buttons(model.buttons, model.tintColor)
+ }
}
}
}
@@ -133,6 +157,15 @@
}
@Composable
+fun BannerTitleHeader(title: String, onDismiss: (() -> Unit)? = null) {
+ Row(Modifier.fillMaxWidth()) {
+ Box(modifier = Modifier.weight(1f)) { SettingsTitle(title) }
+ Spacer(modifier = Modifier.padding(SettingsDimension.paddingSmall))
+ DismissButton(onDismiss)
+ }
+}
+
+@Composable
private fun BannerIcon(imageVector: ImageVector?, color: Color) {
if (imageVector != null) {
Icon(
@@ -147,19 +180,12 @@
@Composable
private fun DismissButton(onDismiss: (() -> Unit)?) {
if (onDismiss == null) return
- Surface(
- shape = CircleShape,
- color = MaterialTheme.colorScheme.secondaryContainer,
- ) {
- IconButton(
- onClick = onDismiss,
- modifier = Modifier.size(SettingsDimension.itemIconSize)
- ) {
+ Surface(shape = CircleShape, color = MaterialTheme.colorScheme.secondaryContainer) {
+ IconButton(onClick = onDismiss, modifier = Modifier.size(SettingsDimension.itemIconSize)) {
Icon(
imageVector = Icons.Outlined.Close,
- contentDescription = stringResource(
- androidx.compose.material3.R.string.m3c_snackbar_dismiss
- ),
+ contentDescription =
+ stringResource(androidx.compose.material3.R.string.m3c_snackbar_dismiss),
modifier = Modifier.padding(SettingsDimension.paddingSmall),
)
}
@@ -172,10 +198,11 @@
if (buttons.isNotEmpty()) {
FlowRow(
modifier = Modifier.fillMaxWidth(),
- horizontalArrangement = Arrangement.spacedBy(
- space = SettingsDimension.itemPaddingEnd,
- alignment = Alignment.End,
- ),
+ horizontalArrangement =
+ Arrangement.spacedBy(
+ space = SettingsDimension.itemPaddingEnd,
+ alignment = Alignment.End,
+ ),
) {
for (button in buttons) {
Button(button, color)
@@ -205,9 +232,7 @@
title = "Lorem ipsum",
text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
imageVector = Icons.Outlined.WarningAmber,
- buttons = listOf(
- BannerButton(text = "Action") {},
- )
+ buttons = listOf(BannerButton(text = "Action") {}),
)
)
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialog.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialog.kt
index 022dded..265864e 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialog.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialog.kt
@@ -17,11 +17,16 @@
package com.android.settingslib.spa.widget.dialog
import android.content.res.Configuration
+import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.AlertDialog
+import androidx.compose.material3.Button
+import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
@@ -32,9 +37,11 @@
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
+import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled
data class AlertDialogButton(
val text: String,
@@ -85,27 +92,41 @@
AlertDialog(
onDismissRequest = ::close,
modifier = Modifier.width(getDialogWidth()),
- confirmButton = { confirmButton?.let { Button(it) } },
- dismissButton = dismissButton?.let { { Button(it) } },
- title = title?.let { { Text(it) } },
- text = text?.let {
- {
- Column(Modifier.verticalScroll(rememberScrollState())) {
- text()
- }
- }
+ confirmButton = {
+ confirmButton?.let { if (isSpaExpressiveEnabled) ConfirmButton(it) else Button(it) }
},
+ dismissButton =
+ dismissButton?.let {
+ { if (isSpaExpressiveEnabled) DismissButton(it) else Button(it) }
+ },
+ title = title?.let { { CenterRow { Text(it) } } },
+ text =
+ text?.let {
+ { CenterRow { Column(Modifier.verticalScroll(rememberScrollState())) { text() } } }
+ },
properties = DialogProperties(usePlatformDefaultWidth = false),
)
}
@Composable
+internal fun CenterRow(content: @Composable (() -> Unit)) {
+ if (isSpaExpressiveEnabled) {
+ Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
+ content()
+ }
+ } else {
+ content()
+ }
+}
+
+@Composable
fun getDialogWidth(): Dp {
val configuration = LocalConfiguration.current
- return configuration.screenWidthDp.dp * when (configuration.orientation) {
- Configuration.ORIENTATION_LANDSCAPE -> 0.65f
- else -> 0.85f
- }
+ return configuration.screenWidthDp.dp *
+ when (configuration.orientation) {
+ Configuration.ORIENTATION_LANDSCAPE -> 0.65f
+ else -> 0.85f
+ }
}
@Composable
@@ -120,3 +141,47 @@
Text(button.text)
}
}
+
+@Composable
+private fun AlertDialogPresenter.DismissButton(button: AlertDialogButton) {
+ OutlinedButton(
+ onClick = {
+ close()
+ button.onClick()
+ },
+ enabled = button.enabled,
+ ) {
+ Text(button.text)
+ }
+}
+
+@Composable
+private fun AlertDialogPresenter.ConfirmButton(button: AlertDialogButton) {
+ Button(
+ onClick = {
+ close()
+ button.onClick()
+ },
+ enabled = button.enabled,
+ ) {
+ Text(button.text)
+ }
+}
+
+@Preview
+@Composable
+private fun AlertDialogPreview() {
+ val alertDialogPresenter = remember {
+ object : AlertDialogPresenter {
+ override fun open() {}
+
+ override fun close() {}
+ }
+ }
+ alertDialogPresenter.SettingsAlertDialog(
+ confirmButton = AlertDialogButton("Ok"),
+ dismissButton = AlertDialogButton("Cancel"),
+ title = "Title",
+ text = { Text("Text") },
+ )
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialogWithIcon.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialogWithIcon.kt
index 030522d..58a83fa 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialogWithIcon.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialogWithIcon.kt
@@ -40,10 +40,7 @@
dismissButton: AlertDialogButton?,
title: String?,
icon: @Composable (() -> Unit)? = {
- Icon(
- Icons.Default.WarningAmber,
- contentDescription = null
- )
+ Icon(Icons.Default.WarningAmber, contentDescription = null)
},
text: @Composable (() -> Unit)?,
) {
@@ -52,43 +49,22 @@
icon = icon,
modifier = Modifier.width(getDialogWidth()),
confirmButton = {
- confirmButton?.let {
- Button(
- onClick = {
- it.onClick()
- },
- ) {
- Text(it.text)
+ confirmButton?.let { Button(onClick = { it.onClick() }) { Text(it.text) } }
+ },
+ dismissButton =
+ dismissButton?.let { { OutlinedButton(onClick = { it.onClick() }) { Text(it.text) } } },
+ title =
+ title?.let {
+ {
+ CenterRow {
+ Text(it, modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center)
+ }
}
- }
- },
- dismissButton = dismissButton?.let {
- {
- OutlinedButton(
- onClick = {
- it.onClick()
- },
- ) {
- Text(it.text)
- }
- }
- },
- title = title?.let {
- {
- Text(
- it,
- modifier = Modifier.fillMaxWidth(),
- textAlign = TextAlign.Center
- )
- }
- },
- text = text?.let {
- {
- Column(Modifier.verticalScroll(rememberScrollState())) {
- text()
- }
- }
- },
+ },
+ text =
+ text?.let {
+ { CenterRow { Column(Modifier.verticalScroll(rememberScrollState())) { text() } } }
+ },
properties = DialogProperties(usePlatformDefaultWidth = false),
)
-}
\ No newline at end of file
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlterDialogContent.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlterDialogContent.kt
index bef0bca..9f2210d 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlterDialogContent.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlterDialogContent.kt
@@ -58,10 +58,7 @@
dismissButton: AlertDialogButton?,
title: String?,
icon: @Composable (() -> Unit)? = {
- Icon(
- Icons.Default.WarningAmber,
- contentDescription = null
- )
+ Icon(Icons.Default.WarningAmber, contentDescription = null)
},
text: @Composable (() -> Unit)?,
) {
@@ -69,42 +66,22 @@
buttons = {
AlertDialogFlowRow(
mainAxisSpacing = ButtonsMainAxisSpacing,
- crossAxisSpacing = ButtonsCrossAxisSpacing
+ crossAxisSpacing = ButtonsCrossAxisSpacing,
) {
- dismissButton?.let {
- OutlinedButton(onClick = it.onClick) {
- Text(it.text)
- }
- }
- confirmButton?.let {
- Button(
- onClick = {
- it.onClick()
- },
- ) {
- Text(it.text)
- }
- }
+ dismissButton?.let { OutlinedButton(onClick = it.onClick) { Text(it.text) } }
+ confirmButton?.let { Button(onClick = { it.onClick() }) { Text(it.text) } }
}
},
icon = icon,
modifier = Modifier.width(getDialogWidth()),
- title = title?.let {
- {
- Text(
- it,
- modifier = Modifier.fillMaxWidth(),
- textAlign = TextAlign.Center
- )
- }
- },
- text = text?.let {
- {
- Column(Modifier.verticalScroll(rememberScrollState())) {
- text()
- }
- }
- },
+ title =
+ title?.let {
+ { Text(it, modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center) }
+ },
+ text =
+ text?.let {
+ { CenterRow { Column(Modifier.verticalScroll(rememberScrollState())) { text() } } }
+ },
)
}
@@ -121,18 +98,12 @@
shape = SettingsShape.CornerExtraLarge,
color = MaterialTheme.colorScheme.surfaceContainerHigh,
) {
- Column(
- modifier = Modifier.padding(DialogPadding)
- ) {
+ Column(modifier = Modifier.padding(DialogPadding)) {
icon?.let {
CompositionLocalProvider(
- LocalContentColor provides AlertDialogDefaults.iconContentColor,
+ LocalContentColor provides AlertDialogDefaults.iconContentColor
) {
- Box(
- Modifier
- .padding(IconPadding)
- .align(Alignment.CenterHorizontally)
- ) {
+ Box(Modifier.padding(IconPadding).align(Alignment.CenterHorizontally)) {
icon()
}
}
@@ -144,8 +115,7 @@
) {
Box(
// Align the title to the center when an icon is present.
- Modifier
- .padding(TitlePadding)
+ Modifier.padding(TitlePadding)
.align(
if (icon == null) {
Alignment.Start
@@ -161,11 +131,10 @@
text?.let {
ProvideContentColorTextStyle(
contentColor = AlertDialogDefaults.textContentColor,
- textStyle = MaterialTheme.typography.bodyMedium
+ textStyle = MaterialTheme.typography.bodyMedium,
) {
Box(
- Modifier
- .weight(weight = 1f, fill = false)
+ Modifier.weight(weight = 1f, fill = false)
.padding(TextPadding)
.align(Alignment.Start)
) {
@@ -177,7 +146,7 @@
ProvideContentColorTextStyle(
contentColor = MaterialTheme.colorScheme.primary,
textStyle = MaterialTheme.typography.labelLarge,
- content = buttons
+ content = buttons,
)
}
}
@@ -188,7 +157,7 @@
internal fun AlertDialogFlowRow(
mainAxisSpacing: Dp,
crossAxisSpacing: Dp,
- content: @Composable () -> Unit
+ content: @Composable () -> Unit,
) {
Layout(content) { measurables, constraints ->
val sequences = mutableListOf<List<Placeable>>()
@@ -204,8 +173,9 @@
// Return whether the placeable can be added to the current sequence.
fun canAddToCurrentSequence(placeable: Placeable) =
- currentSequence.isEmpty() || currentMainAxisSize + mainAxisSpacing.roundToPx() +
- placeable.width <= constraints.maxWidth
+ currentSequence.isEmpty() ||
+ currentMainAxisSize + mainAxisSpacing.roundToPx() + placeable.width <=
+ constraints.maxWidth
// Store current sequence information and start a new sequence.
fun startNewSequence() {
@@ -213,8 +183,7 @@
crossAxisSpace += crossAxisSpacing.roundToPx()
}
// Ensures that confirming actions appear above dismissive actions.
- @Suppress("ListIterator")
- sequences.add(0, currentSequence.toList())
+ @Suppress("ListIterator") sequences.add(0, currentSequence.toList())
crossAxisSizes += currentCrossAxisSize
crossAxisPositions += crossAxisSpace
@@ -254,23 +223,23 @@
layout(layoutWidth, layoutHeight) {
sequences.fastForEachIndexed { i, placeables ->
- val childrenMainAxisSizes = IntArray(placeables.size) { j ->
- placeables[j].width +
- if (j < placeables.lastIndex) mainAxisSpacing.roundToPx() else 0
- }
+ val childrenMainAxisSizes =
+ IntArray(placeables.size) { j ->
+ placeables[j].width +
+ if (j < placeables.lastIndex) mainAxisSpacing.roundToPx() else 0
+ }
val arrangement = Arrangement.End
val mainAxisPositions = IntArray(childrenMainAxisSizes.size) { 0 }
with(arrangement) {
arrange(
- mainAxisLayoutSize, childrenMainAxisSizes,
- layoutDirection, mainAxisPositions
+ mainAxisLayoutSize,
+ childrenMainAxisSizes,
+ layoutDirection,
+ mainAxisPositions,
)
}
placeables.fastForEachIndexed { j, placeable ->
- placeable.place(
- x = mainAxisPositions[j],
- y = crossAxisPositions[i]
- )
+ placeable.place(x = mainAxisPositions[j], y = crossAxisPositions[i])
}
}
}
@@ -289,8 +258,8 @@
/**
* ProvideContentColorTextStyle
*
- * A convenience method to provide values to both LocalContentColor and LocalTextStyle in
- * one call. This is less expensive than nesting calls to CompositionLocalProvider.
+ * A convenience method to provide values to both LocalContentColor and LocalTextStyle in one call.
+ * This is less expensive than nesting calls to CompositionLocalProvider.
*
* Text styles will be merged with the current value of LocalTextStyle.
*/
@@ -298,12 +267,12 @@
private fun ProvideContentColorTextStyle(
contentColor: Color,
textStyle: TextStyle,
- content: @Composable () -> Unit
+ content: @Composable () -> Unit,
) {
val mergedStyle = LocalTextStyle.current.merge(textStyle)
CompositionLocalProvider(
LocalContentColor provides contentColor,
LocalTextStyle provides mergedStyle,
- content = content
+ content = content,
)
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt
index 9bbc16d..94d2c21 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt
@@ -62,7 +62,7 @@
modifier = if (isSpaExpressiveEnabled) Modifier
.size(SettingsDimension.actionIconWidth, SettingsDimension.actionIconHeight)
.clip(SettingsShape.CornerExtraLarge)
- .background(MaterialTheme.colorScheme.onSurfaceVariant)
+ .background(MaterialTheme.colorScheme.surfaceContainerHigh)
.padding(SettingsDimension.actionIconPadding) else Modifier
)
}
diff --git a/packages/SettingsLib/res/drawable/ic_media_microphone.xml b/packages/SettingsLib/res/drawable/ic_media_microphone.xml
new file mode 100644
index 0000000..209dea5
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_media_microphone.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="?attr/colorControlNormal"
+ android:viewportHeight="960"
+ android:viewportWidth="960">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M480,560Q430,560 395,525Q360,490 360,440L360,200Q360,150 395,115Q430,80 480,80Q530,80 565,115Q600,150 600,200L600,440Q600,490 565,525Q530,560 480,560ZM480,320Q480,320 480,320Q480,320 480,320L480,320Q480,320 480,320Q480,320 480,320Q480,320 480,320Q480,320 480,320L480,320Q480,320 480,320Q480,320 480,320ZM440,840L440,717Q336,703 268,624Q200,545 200,440L280,440Q280,523 338.5,581.5Q397,640 480,640Q563,640 621.5,581.5Q680,523 680,440L760,440Q760,545 692,624Q624,703 520,717L520,840L440,840ZM480,480Q497,480 508.5,468.5Q520,457 520,440L520,200Q520,183 508.5,171.5Q497,160 480,160Q463,160 451.5,171.5Q440,183 440,200L440,440Q440,457 451.5,468.5Q463,480 480,480Z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index f072de8..de728e2 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Sopas"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Hierdie foon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Hierdie tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofoon (intern)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokluidspreker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Eksterne toestel"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Gekoppelde toestel"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Gedeaktiveer"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Geaktiveer"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Jou toestel moet herselflaai om hierdie verandering toe te pas. Herselflaai nou of kanselleer."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Bedrade oorfone"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofoonsok"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-mikrofoon"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aan"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Af"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Diensverskaffernetwerk verander tans"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 86f21d3..0c9ed5c 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ልክ አሁን"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"ይህ ስልክ"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ይህ ጡባዊ"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"ማይክሮፎን (ውስጣዊ)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"የመትከያ ድምፅ ማውጫ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"የውጭ መሣሪያ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"የተገናኘ መሣሪያ"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ተሰናክሏል"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ነቅቷል"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"የእርስዎን መሣሪያ ይህ ለው ለማመልከት እንደገና መነሣት አለበት። አሁን እንደገና ያስነሡ ወይም ይተዉት።"</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ባለገመድ ጆሮ ማዳመጫ"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"የማይክሮፎን መሰኪያ"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB ማይክሮፎን"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"አብራ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"አጥፋ"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"የአገልግሎት አቅራቢ አውታረ መረብን በመቀየር ላይ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 39219f4..46e4c76 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"للتو"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"هذا الهاتف"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"هذا الجهاز اللوحي"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"ميكروفون (داخلي)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"مكبّر صوت بقاعدة إرساء"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"جهاز خارجي"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"جهاز متّصل"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"غير مفعّل"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"مفعّل"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"يجب إعادة تشغيل جهازك ليتم تطبيق هذا التغيير. يمكنك إعادة التشغيل الآن أو إلغاء التغيير."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"سمّاعة سلكية"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"مقبس الميكروفون"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"ميكروفون بمنفذ USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"مفعّلة"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"إيقاف"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"جارٍ تغيير شبكة مشغِّل شبكة الجوّال."</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index ae27622..82cd91c 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"এই মাত্ৰ"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"এই ফ’নটো"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"এই টেবলেটটো"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"মাইক্ৰ’ফ’ন (অভ্যন্তৰীণ)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ড’ক স্পীকাৰ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"বাহ্যিক ডিভাইচ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"সংযোগ হৈ থকা ডিভাইচ"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"অক্ষম কৰা আছে"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"সক্ষম কৰা আছে"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"এই সলনিটো কার্যকৰী হ’বলৈ আপোনাৰ ডিভাইচটো ৰিবুট কৰিবই লাগিব। এতিয়াই ৰিবুট কৰক অথবা বাতিল কৰক।"</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"তাঁৰযুক্ত হেডফ\'ন"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"মাইকৰ জেক"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"ইউএছবি মাইক"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"অন"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"অফ"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"বাহক নেটৱৰ্কৰ পৰিৱৰ্তন"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 843c1be..4715109 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"İndicə"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Bu telefon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Bu planşet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (daxili)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dok dinamiki"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Xarici cihaz"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Qoşulmuş cihaz"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiv"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu dəyişikliyin tətbiq edilməsi üçün cihaz yenidən başladılmalıdır. İndi yenidən başladın və ya ləğv edin."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Naqilli qulaqlıq"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofon yuvası"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mikrofon"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktiv"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Deaktiv"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator şəbəkəsinin dəyişilməsi"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index f906634..5da1c69 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Upravo"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ovaj telefon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ovaj tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (interni)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik bazne stanice"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Spoljni uređaj"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogućeno"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Morate da restartujete uređaj da bi se ova promena primenila. Restartujte ga odmah ili otkažite."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Utikač za mikrofon"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mikrofon"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključeno"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključeno"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Promena mreže mobilnog operatera"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 613b744..2adcc43 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Толькі што"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Гэты тэлефон"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Гэты планшэт"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Мікрафон (унутраны)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Дынамік док-станцыі"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Знешняя прылада"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Падключаная прылада"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Выключана"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Уключана"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Перазагрузіце прыладу, каб прымяніць гэта змяненне. Перазагрузіце ці скасуйце."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Правадныя навушнікі"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Раздым для мікрафона"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Мікрафон USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Уключана"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Выключана"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Змяненне аператара сеткі"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 767be33..df5051f 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Току-що"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Този телефон"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Този таблет"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (вътрешен)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Високоговорител докинг станция"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Външно устройство"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Свързано устройство"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Деактивирано"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Активирано"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"За да бъде приложена тази промяна, устройството ви трябва да бъде рестартирано. Рестартирайте сега или анулирайте."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Слушалки с кабел"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Жак за микрофон"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Микрофон с USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Включване"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Изключване"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Промяна на мрежата на оператора"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 8419544..e782aa1 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"এখনই"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"এই ফোন"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"এই ট্যাবলেট"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"মাইক্রোফোন (ইন্টার্নাল)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ডক স্পিকার"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"এক্সটার্নাল ডিভাইস"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"কানেক্ট থাকা ডিভাইস"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"বন্ধ করা আছে"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"চালু করা আছে"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"এই পরিবর্তনটি প্রয়োগ করার জন্য আপনার ডিভাইসটি অবশ্যই রিবুট করতে হবে। এখনই রিবুট করুন বা বাতিল করুন।"</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"তার যুক্ত হেডফোন"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"মাইকের জ্যাক"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB মাইক"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"চালু আছে"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"বন্ধ আছে"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"পরিষেবা প্রদানকারীর নেটওয়ার্ক পরিবর্তন করা হচ্ছে"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 12e8c73..bddced5 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Upravo"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ovaj telefon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ovaj tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (interni)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik priključne stanice"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Vanjski uređaj"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogućeno"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Morate ponovo pokrenuti uređaj da se ova promjena primijeni. Ponovo pokrenite odmah ili otkažite."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Priključak za mikrofon"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mikrofon"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključi"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključi"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Promjena mreže mobilnog operatera"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 44780d3..89f8f5a 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Ara mateix"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Aquest telèfon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Aquesta tauleta"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Micròfon (intern)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Base d\'altaveu"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositiu extern"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositiu connectat"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desactivat"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activat"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Has de reiniciar el teu dispositiu perquè s\'apliquin els canvis. Reinicia\'l ara o cancel·la."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculars amb cable"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Connector per al micròfon"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Micròfon USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activa"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactiva"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"S\'està canviant la xarxa de l\'operador de telefonia mòbil"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index cadb170..e775050 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Právě teď"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Tento telefon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tento tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (interní)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Reproduktor doku"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externí zařízení"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Připojené zařízení"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Vypnuto"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Zapnuto"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Aby se tato změna projevila, je třeba zařízení restartovat. Restartujte zařízení nebo zrušte akci."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kabelová sluchátka"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Konektor mikrofonu"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mikrofon"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Zapnout"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Vypnout"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Probíhá změna sítě operátora"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index d3b064c..a85bc29 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Lige nu"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Denne telefon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Denne tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (indbygget)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockhøjttaler"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ekstern enhed"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Forbundet enhed"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiveret"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiveret"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Din enhed skal genstartes for at anvende denne ændring. Genstart nu, eller annuller."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Høretelefoner med ledning"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Stik til mikrofon"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-mikrofon"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Til"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Fra"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Skift af mobilnetværk"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 50bc9cc..ac46bb6 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -582,6 +582,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Gerade eben"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Dieses Smartphone"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Dieses Tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
<!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
@@ -686,7 +688,12 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiviert"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiviert"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Damit diese Änderung übernommen wird, musst du dein Gerät neu starten. Du kannst es jetzt neu starten oder den Vorgang abbrechen."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kabelgebundene Kopfhörer"</string>
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
+ <skip />
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
<!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
<skip />
<!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index ea6b3ba..ce045a9 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Μόλις τώρα"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Αυτό το τηλέφωνο"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Αυτό το tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Μικρόφωνο (εσωτερικό)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Ηχείο βάσης σύνδεσης"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Εξωτερική συσκευή"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Συνδεδεμένη συσκευή"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Ανενεργή"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ενεργή"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Για να εφαρμοστεί αυτή η αλλαγή, θα πρέπει να επανεκκινήσετε τη συσκευή σας. Επανεκκίνηση τώρα ή ακύρωση."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Ενσύρματα ακουστικά"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Υποδοχή μικροφώνου"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Μικρόφωνο USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ενεργό"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ανενεργό"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Αλλαγή δικτύου εταιρείας κινητής τηλεφωνίας"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 03e505a..961f0e7 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"This tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microphone (internal)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mic jack"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mic"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 9fce566..6c2f45e 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"This tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microphone (internal)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External Device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mic jack"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mic"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Carrier network changing"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 03e505a..961f0e7 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"This tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microphone (internal)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mic jack"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mic"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 03e505a..961f0e7 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"This tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microphone (internal)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mic jack"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mic"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 85cf936..a9ed4a4 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"This tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microphone (internal)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External Device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mic jack"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mic"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Carrier network changing"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 3feee4c..8fcb49c 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -582,6 +582,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Recién"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este teléfono"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Esta tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
<!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
@@ -686,7 +688,12 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Inhabilitado"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Habilitado"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Debes reiniciar el dispositivo para que se aplique el cambio. Reinícialo ahora o cancela la acción."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
+ <skip />
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
<!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
<skip />
<!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index d2c7a02..716713a 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"justo ahora"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este teléfono"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Esta tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Micrófono (interno)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altavoz de la base"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Inhabilitado"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Habilitado"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Es necesario reiniciar tu dispositivo para que se apliquen los cambios. Reinicia ahora o cancela la acción."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Conector jack para micrófono"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Micrófono USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activado"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivado"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambiando la red del operador"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 1452a0e..f1975fa 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Äsja"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"See telefon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"See tahvelarvuti"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (sisemine)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doki kõlar"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Väline seade"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ühendatud seade"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Keelatud"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Lubatud"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Selle muudatuse rakendamiseks tuleb seade taaskäivitada. Taaskäivitage kohe või tühistage."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Juhtmega kõrvaklapid"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofoni pistikupesa"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-mikrofon"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Sees"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Väljas"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operaatori võrku muudetakse"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 2d97bbf..fc4157c 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -564,7 +564,7 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmak eta abisuak"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Eman alarmak ezartzeko eta denbora-muga duten ekintzak programatzeko baimena aplikazioari. Hala, aplikazioak atzeko planoan funtzionatuko du, eta litekeena da bateria gehiago kontsumitzea.\n\nBaimen hori ematen ez baduzu, ez dute funtzionatuko aplikazio honen bidez programatutako alarmek eta denbora-muga duten ekintzek."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programazioa, alarma, abisua, erlojua"</string>
- <string name="zen_mode_do_not_disturb_name" msgid="6798711401734798283">"Ez molestatzeko modua"</string>
+ <string name="zen_mode_do_not_disturb_name" msgid="6798711401734798283">"Ez molestatzeko"</string>
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Ez molestatzeko modua"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktibatu"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Aktibatu ez molestatzeko modua"</string>
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Oraintxe"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Telefono hau"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tableta hau"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofonoa (barnekoa)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Oinarri bozgorailuduna"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Kanpoko gailua"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Konektatutako gailua"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desgaituta"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Gaituta"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Aldaketa aplikatzeko, berrabiarazi egin behar da gailua. Berrabiaraz ezazu orain, edo utzi bertan behera."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Entzungailu kableduna"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofonoaren konektorea"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB bidezko mikrofonoa"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktibatu"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desaktibatu"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operadorearen sarea aldatzen"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 11dcc99..db9a744f 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"هماکنون"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"این تلفن"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"این رایانه لوحی"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"میکروفون (داخلی)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"بلندگوی پایه اتصال"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"دستگاه خارجی"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"دستگاه متصل"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"غیرفعال"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"فعال"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"برای اعمال این تغییر، دستگاه باید بازراهاندازی شود. یا اکنون بازراهاندازی کنید یا لغو کنید."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"هدفون سیمی"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"فیش میکروفون"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"میکروفون USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"روشن"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"خاموش"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"تغییر شبکه شرکت مخابراتی"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 4ee5c60..b92616b 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Äsken"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Tämä puhelin"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tämä tabletti"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofoni (sisäinen)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Telinekaiutin"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ulkoinen laite"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Yhdistetty laite"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Ei käytössä"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Käytössä"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Laitteesi on käynnistettävä uudelleen, jotta muutos tulee voimaan. Käynnistä uudelleen nyt tai peru."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Langalliset kuulokkeet"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofoniliitäntä"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-mikrofoni"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Päällä"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ei käytössä"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operaattorin verkko muuttuu"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index d975f3e..bf9adba 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"À l\'instant"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ce téléphone"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Cette tablette"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microphone (interne)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Haut-parleur du socle"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Appareil externe"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Appareil connecté"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Désactivé"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activé"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Votre appareil doit être redémarré pour que ce changement prenne effet. Redémarrez-le maintenant ou annulez la modification."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Écouteurs filaires"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Prise du microphone"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Microphone USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activé"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Désactivé"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Changer de réseau de fournisseur de services"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index c987bc4..1f09856 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -582,6 +582,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"À l\'instant"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ce téléphone"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Cette tablette"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
<!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
@@ -686,7 +688,12 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Désactivé"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activé"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Vous devez redémarrer l\'appareil pour que cette modification soit appliquée. Redémarrez maintenant ou annulez l\'opération."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Casque filaire"</string>
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
+ <skip />
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
<!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
<skip />
<!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
diff --git a/packages/SettingsLib/res/values-gl/arrays.xml b/packages/SettingsLib/res/values-gl/arrays.xml
index e6d098f..8f7a8b6 100644
--- a/packages/SettingsLib/res/values-gl/arrays.xml
+++ b/packages/SettingsLib/res/values-gl/arrays.xml
@@ -26,10 +26,10 @@
<item msgid="6050951078202663628">"Conectando..."</item>
<item msgid="8356618438494652335">"Autenticando…"</item>
<item msgid="2837871868181677206">"Obtendo enderezo IP..."</item>
- <item msgid="4613015005934755724">"Conectada"</item>
+ <item msgid="4613015005934755724">"Conectado"</item>
<item msgid="3763530049995655072">"Suspendida"</item>
<item msgid="7852381437933824454">"Desconectando..."</item>
- <item msgid="5046795712175415059">"Desconectada"</item>
+ <item msgid="5046795712175415059">"Desconectado"</item>
<item msgid="2473654476624070462">"Incorrecta"</item>
<item msgid="9146847076036105115">"Bloqueada"</item>
<item msgid="4543924085816294893">"Evitando conexión deficiente temporalmente"</item>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 0216ad9..98a1401 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -510,7 +510,7 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Cargando sen fíos"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Cargando"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Non se está cargando"</string>
- <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Conectado, pero non cargando"</string>
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Conectado, pero sen cargar"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Cargada"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Carga completa"</string>
<string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Carga en pausa"</string>
@@ -564,7 +564,7 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmas e recordatorios"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permite que esta aplicación defina alarmas e planifique accións que dependan da hora. Con este permiso, a aplicación pode executarse en segundo plano, o que pode provocar un maior consumo de batería.\n\nSe este permiso está desactivado, non funcionarán as alarmas que xa se definisen nin os eventos que dependan da hora planificados por esta aplicación."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"planificar, alarma, recordatorio, reloxo"</string>
- <string name="zen_mode_do_not_disturb_name" msgid="6798711401734798283">"Modo Non molestar"</string>
+ <string name="zen_mode_do_not_disturb_name" msgid="6798711401734798283">"Non molestar"</string>
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Non molestar"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Activar"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Activar modo Non molestar"</string>
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Agora mesmo"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este teléfono"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Esta tableta"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Micrófono (interno)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altofalante da base"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desactivado"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activado"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necesario reiniciar o teu dispositivo para aplicar este cambio. Reiníciao agora ou cancela o cambio."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Conector do micrófono"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Micrófono USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activada"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivada"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambio de rede do operador"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index bc34173..0455dff 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"હમણાં જ"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"આ ફોન"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"આ ટૅબ્લેટ"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"માઇક્રોફોન (આંતરિક)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ડૉક સ્પીકર"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"બહારનું ડિવાઇસ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"કનેક્ટ કરેલું ડિવાઇસ"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"બંધ છે"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ચાલુ છે"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"આ ફેરફારને લાગુ કરવા માટે તમારા ડિવાઇસને રીબૂટ કરવાની જરૂર છે. હમણાં જ રીબૂટ કરો કે રદ કરો."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"વાયરવાળો હૅડફોન"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"માઇક જૅક"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB માઇક"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ચાલુ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"બંધ"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"કૅરીઅર નેટવર્કમાં ફેરફાર થઈ રહ્યો છે"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 25309b3e..6f0fde3 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"अभी-अभी"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"यह फ़ोन"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"यह टैबलेट"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"माइक्रोफ़ोन (इंटरनल)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डॉक स्पीकर"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाहरी डिवाइस"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट किया गया डिवाइस"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"बंद है"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"चालू है"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"बदली गई सेटिंग को लागू करने के लिए, डिवाइस को रीस्टार्ट करना होगा. अपने डिवाइस को रीस्टार्ट करें या रद्द करें."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"वायर वाला हेडफ़ोन"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"माइक्रोफ़ोन जैक"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"यूएसबी माइक्रोफ़ोन"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"चालू है"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"बंद है"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"मोबाइल और इंटरनेट सेवा देने वाली कंपनी का नेटवर्क बदल रहा है"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 516834d..2045fe7 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Upravo sad"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ovaj telefon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ovaj tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (ugrađeni)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik priključne stanice"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Vanjski uređaj"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogućeno"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Uređaj se mora ponovno pokrenuti da bi se ta promjena primijenila. Ponovo pokrenite uređaj odmah ili odustanite."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Utičnica za mikrofon"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mikrofon"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključeno"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključeno"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Promjena mreže mobilnog operatera"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 1d2b715..62f4777 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Az imént"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ez a telefon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ez a táblagép"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (belső)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokkhangszóró"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Külső eszköz"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Csatlakoztatott eszköz"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Letiltva"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Engedélyezve"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Az eszközt újra kell indítani, hogy a módosítás megtörténjen. Indítsa újra most, vagy vesse el a módosítást."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vezetékes fejhallgató"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofon jack csatlakozója"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-mikrofon"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Be"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ki"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Szolgáltatói hálózat váltása"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 85b5548..ba4e204 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Հենց նոր"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Այս հեռախոսը"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Այս պլանշետը"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Խոսափող (ներքին)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Դոկ-կայանով բարձրախոս"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Արտաքին սարք"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Միացված սարք"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Անջատված է"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Միացված է"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Սարքն անհրաժեշտ է վերագործարկել, որպեսզի փոփոխությունը կիրառվի։ Վերագործարկեք հիմա կամ չեղարկեք փոփոխությունը։"</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Լարով ականջակալ"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Խոսափողի հարակցիչ"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB խոսափող"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Միացնել"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Անջատել"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Օպերատորի ցանցի փոփոխություն"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 6660188..89d82f0 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Baru saja"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ponsel ini"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tablet ini"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (internal)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Speaker dok"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Perangkat Eksternal"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Perangkat yang terhubung"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Nonaktif"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktif"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Perangkat Anda harus di-reboot agar perubahan ini diterapkan. Reboot sekarang atau batalkan."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Headphone berkabel"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Colokan mikrofon"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Mikrofon USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktif"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Nonaktif"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Jaringan operator berubah"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 0984892..b5d1831 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Rétt í þessu"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Þessi sími"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Þessi spjaldtölva"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Hljóðnemi (innbyggður)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Hátalaradokka"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ytra tæki"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Tengt tæki"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Slökkt"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Virkt"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Endurræsa þarf tækið til að þessi breyting taki gildi. Endurræstu núna eða hættu við."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Heyrnartól með snúru"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Hljóðnematengi"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-hljóðnemi"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Kveikt"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Slökkt"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Skiptir um farsímakerfi"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index e70c415..60c6391 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -582,6 +582,8 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Adesso"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Questo smartphone"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Questo tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
<!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
@@ -686,7 +688,12 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Non attivo"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Attivo"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Per applicare questa modifica, devi riavviare il dispositivo. Riavvia ora o annulla."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Cuffie con cavo"</string>
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
+ <skip />
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
<!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
<skip />
<!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 662455d..986fcb9 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"הרגע"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"הטלפון הזה"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"הטאבלט הזה"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"מיקרופון (פנימי)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"רמקול של אביזר העגינה"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"מכשיר חיצוני"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"המכשיר המחובר"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"מושבת"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"מופעל"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"צריך להפעיל מחדש את המכשיר כדי להחיל את השינוי. יש להפעיל מחדש עכשיו או לבטל."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"אוזניות חוטיות"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"שקע למיקרופון"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"מיקרופון USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"פועלת"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"מצב כבוי"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"רשת ספק משתנה"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 70fc2d0..bc8dee8 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"たった今"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"このデバイス"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"このタブレット"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"マイク(内蔵)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ホルダー スピーカー"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部デバイス"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"接続済みのデバイス"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"無効"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"有効"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"この変更を適用するには、デバイスの再起動が必要です。今すぐ再起動するか、キャンセルしてください。"</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線ヘッドフォン"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"マイク差込口"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB マイク"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ON"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"OFF"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"携帯通信会社のネットワークを変更します"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 040c046..a6151f3 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ახლახან"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"ეს ტელეფონი"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ამ ტაბლეტზე"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"მიკროფონი (შიდა)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"სამაგრის დინამიკი"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"გარე მოწყობილობა"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"დაკავშირებული მოწყობილობა"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"გათიშული"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ჩართული"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ამ ცვლილების ასამოქმედებლად თქვენი მოწყობილობა უნდა გადაიტვირთოს. გადატვირთეთ ახლავე ან გააუქმეთ."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"სადენიანი ყურსასმენი"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"მიკროფონის ჯეკი"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB მიკროფონი"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ჩართვა"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"გამორთვა"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"ოპერატორის ქსელის შეცვლა"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index f54067c..6789f40 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Дәл қазір"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Осы телефон"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Осы планшет"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (ішкі)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Динамигі бар қондыру станциясы"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Сыртқы құрылғы"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Жалғанған құрылғы"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Өшірулі"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Қосулы"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Бұл өзгеріс күшіне енуі үшін, құрылғыны қайта жүктеу керек. Қазір қайта жүктеңіз не бас тартыңыз."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Сымды құлақаспап"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Микрофон ұяшығы"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB микрофоны"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Қосу"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Өшіру"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Оператор желісін өзгерту"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 807e7e2..933dee7 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"អម្បាញ់មិញ"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"ទូរសព្ទនេះ"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ថេប្លេតនេះ"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"មីក្រូហ្វូន (ខាងក្នុង)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ឧបាល័រជើងទម្រ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ឧបករណ៍ខាងក្រៅ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ឧបករណ៍ដែលបានភ្ជាប់"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"បានបិទ"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"បានបើក"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ត្រូវតែចាប់ផ្ដើមឧបករណ៍របស់អ្នកឡើងវិញ ដើម្បីឱ្យការផ្លាស់ប្ដូរនេះមានប្រសិទ្ធភាព។ ចាប់ផ្ដើមឡើងវិញឥឡូវនេះ ឬបោះបង់។"</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"កាសមានខ្សែ"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"ឌុយមីក្រូហ្វូន"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"មីក្រូហ្វូន USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"បើក"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"បិទ"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"បណ្តាញក្រុមហ៊ុនសេវាទូរសព្ទកំពុងផ្លាស់ប្តូរ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 23e31c2..29417d6 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ಇದೀಗ"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"ಈ ಫೋನ್"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ಈ ಟ್ಯಾಬ್ಲೆಟ್"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"ಮೈಕ್ರೊಫೋನ್ (ಆಂತರಿಕ)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ಡಾಕ್ ಸ್ಪೀಕರ್"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ಬಾಹ್ಯ ಸಾಧನ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ಕನೆಕ್ಟ್ ಮಾಡಿರುವ ಸಾಧನ"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ಈ ಬದಲಾವಣೆ ಅನ್ವಯವಾಗಲು ನಿಮ್ಮ ಸಾಧನವನ್ನು ರೀಬೂಟ್ ಮಾಡಬೇಕು. ಇದೀಗ ರೀಬೂಟ್ ಮಾಡಿ ಅಥವಾ ರದ್ದುಗೊಳಿಸಿ."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ವೈಯರ್ ಹೊಂದಿರುವ ಹೆಡ್ಫೋನ್"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"ಮೈಕ್ ಜ್ಯಾಕ್"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB ಮೈಕ್"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ಆನ್ ಆಗಿದೆ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ಆಫ್"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"ವಾಹಕ ನೆಟ್ವರ್ಕ್ ಬದಲಾಯಿಸುವಿಕೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index cfbddad..4b0cfb4 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"조금 전"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"이 휴대전화"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"이 태블릿"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"마이크(내부)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"도크 스피커"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"외부 기기"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"연결된 기기"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"사용 중지됨"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"사용 설정됨"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"변경사항을 적용하려면 기기를 재부팅해야 합니다. 지금 재부팅하거나 취소하세요."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"유선 헤드폰"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"마이크 잭"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB 마이크"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"사용"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"사용 안 함"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"이동통신사 네트워크 변경"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index c5a3bcc..17b55c4 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Жаңы эле"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ушул телефон"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ушул планшет"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (ички)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Док бекеттин динамиги"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Тышкы түзмөк"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Туташкан түзмөк"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Өчүк"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Күйүк"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Бул өзгөрүү күчүнө кириши үчүн, түзмөктү өчүрүп күйгүзүңүз. Азыр же кийинчерээк өчүрүп күйгүзсөңүз болот."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Зымдуу гарнитура"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Микрофондун оюкчасы"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB микрофон"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Күйгүзүү"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Өчүрүү"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Байланыш оператору өзгөртүлүүдө"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 70fd196..e6e8ef8 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ຕອນນີ້"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"ໂທລະສັບນີ້"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ແທັບເລັດນີ້"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"ໄມໂຄຣໂຟນ (ພາຍໃນ)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ແທ່ນວາງລຳໂພງ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ອຸປະກອນພາຍນອກ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ອຸປະກອນທີ່ເຊື່ອມຕໍ່"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ປິດການນຳໃຊ້ແລ້ວ"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ເປີດການນຳໃຊ້ແລ້ວ"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ທ່ານຕ້ອງປິດເປີດອຸປະກອນຄືນໃໝ່ເພື່ອນຳໃຊ້ການປ່ຽນແປງນີ້. ປິດເປີດໃໝ່ດຽວນີ້ ຫຼື ຍົກເລີກ."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ຫູຟັງແບບມີສາຍ"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"ຊ່ອງສຽງໄມ"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"ໄມ USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ເປີດ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ປິດ"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"ການປ່ຽນເຄືອຂ່າຍຜູ້ໃຫ້ບໍລິການ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 5488437..5945e2a 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Ką tik"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Šis telefonas"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Šis planšetinis kompiuteris"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofonas (vidinis)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doko garsiakalbis"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Išorinis įrenginys"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Prijungtas įrenginys"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Išjungta"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Įgalinta"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Kad pakeitimas būtų pritaikytas, įrenginį reikia paleisti iš naujo. Dabar paleiskite iš naujo arba atšaukite."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Laidinės ausinės"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofono jungtis"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mikrofonas"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Įjungta"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Išjungta"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Keičiamas operatoriaus tinklas"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index faf7b5f..34f6c4c 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Tikko"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Šis tālrunis"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Šis planšetdators"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofons (iebūvētais)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doka skaļrunis"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ārēja ierīce"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pievienotā ierīce"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Atspējots"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Iespējots"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Lai šīs izmaiņas tiktu piemērotas, nepieciešama ierīces atkārtota palaišana. Atkārtoti palaidiet to tūlīt vai atceliet izmaiņas."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vadu austiņas"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofona ligzda"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mikrofons"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ieslēgts"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Izslēgts"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Mobilo sakaru operatora tīkla mainīšana"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 2f215e8..a8eb607 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Пред малку"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Овој телефон"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Овој таблет"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (внатрешен)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Док со звучник"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Надворешен уред"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Поврзан уред"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Оневозможено"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Овозможено"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"За да се примени променава, уредот мора да се рестартира. Рестартирајте сега или откажете."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Жичени слушалки"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Приклучок за микрофон"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-микрофон"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Вклучено"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Исклучено"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Променување на мрежата на операторот"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 859ac3b..753aa32 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ഇപ്പോൾ"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"ഈ ഫോൺ"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ഈ ടാബ്ലെറ്റ്"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"മൈക്രോഫോൺ (ഇന്റേണൽ)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ഡോക്ക് സ്പീക്കർ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ബാഹ്യ ഉപകരണം"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"കണക്റ്റ് ചെയ്ത ഉപകരണം"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"പ്രവർത്തനക്ഷമമാക്കി"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ഈ മാറ്റം ബാധകമാകുന്നതിന് നിങ്ങളുടെ ഉപകരണം റീബൂട്ട് ചെയ്യേണ്ടതുണ്ട്. ഇപ്പോൾ റീബൂട്ട് ചെയ്യുകയോ റദ്ദാക്കുകയോ ചെയ്യുക."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"വയേർഡ് ഹെഡ്ഫോൺ"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"മൈക്ക് ജാക്ക്"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB മൈക്ക്"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ഓണാണ്"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ഓഫാണ്"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"കാരിയർ നെറ്റ്വർക്ക് മാറ്റൽ"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 7615dcc..bc953d3 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Дөнгөж сая"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Энэ утас"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Энэ таблет"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (дотоод)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Суурилуулагчийн чанга яригч"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Гадаад төхөөрөмж"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Холбогдсон төхөөрөмж"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Идэвхгүй болгосон"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Идэвхжүүлсэн"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Энэ өөрчлөлтийг хэрэгжүүлэхийн тулд таны төхөөрөмжийг дахин асаах ёстой. Одоо дахин асаах эсвэл цуцлана уу."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Утастай чихэвч"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Микрофоны чихэвчний оролт"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB микрофон"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Асаах"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Унтраах"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Оператор компанийн сүлжээг өөрчилж байна"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index fb90ce3..483936a 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"आत्ताच"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"हा फोन"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"हा टॅबलेट"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"मायक्रोफोन (अंतर्गत)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डॉक स्पीकर"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाह्य डिव्हाइस"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट केलेले डिव्हाइस"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"बंद केले आहे"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"सुरू केले आहे"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"हा बदल लागू करण्यासाठी तुमचे डिव्हाइस रीबूट करणे आवश्यक आहे. आता रीबूट करा किंवा रद्द करा."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"वायर असलेला हेडफोन"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"माइक जॅक"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB माइक"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"सुरू करा"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"बंद करा"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"वाहक नेटवर्क बदलत आहे"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index acd8487..dbe745d 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Sebentar tadi"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Telefon ini"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tablet ini"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (dalaman)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Pembesar suara dok"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Peranti Luar"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Peranti yang disambungkan"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Dilumpuhkan"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Didayakan"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Peranti anda mesti dibut semula supaya perubahan ini berlaku. But semula sekarang atau batalkan."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fon kepala berwayar"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Bicu mikrofon"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Mikrofon USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Hidup"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Mati"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Rangkaian pembawa berubah"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 2640c3a..063fc9c 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ယခုလေးတင်"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"ဤဖုန်း"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ဤတက်ဘလက်"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"မိုက်ခရိုဖုန်း (စက်တွင်း)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"အထိုင် စပီကာ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ပြင်ပစက်"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ချိတ်ဆက်ကိရိယာ"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ပိတ်ထားသည်"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ဖွင့်ထားသည်"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ဤအပြောင်းအလဲ ထည့်သွင်းရန် သင့်စက်ကို ပြန်လည်စတင်ရမည်။ ယခု ပြန်လည်စတင်ပါ သို့မဟုတ် ပယ်ဖျက်ပါ။"</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ကြိုးတပ်နားကြပ်"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"မိုက်ဂျက်ပင်"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB မိုက်"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ဖွင့်"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ပိတ်"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"ဝန်ဆောင်မှုပေးသူ ကွန်ရက် ပြောင်းလဲနေသည်။"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 4a53090..9036c8c 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Nå nettopp"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Denne telefonen"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Dette nettbrettet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (intern)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokkhøyttaler"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ekstern enhet"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Tilkoblet enhet"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Slått av"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Slått på"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Enheten din må startes på nytt for at denne endringen skal tre i kraft. Start på nytt nå eller avbryt."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"hodetelefoner med kabel"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofonkontakt"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-mikrofon"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"På"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Av"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Bytting av operatørnettverk"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index a04028f..09240f0 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"अहिले भर्खरै"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"यो फोन"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"यो ट्याब्लेट"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"माइक्रोफोन (आन्तरिक)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डक स्पिकर"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाह्य डिभाइस"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट गरिएको डिभाइस"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"असक्षम पारिएको छ"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"सक्षम पारिएको छ"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"यो परिवर्तन लागू गर्न तपाईंको यन्त्र अनिवार्य रूपमा रिबुट गर्नु पर्छ। अहिले रिबुट गर्नुहोस् वा रद्द गर्नुहोस्।"</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"तारसहितको हेडफोन"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"माइकको ज्याक"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB माइक"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"अन छ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"अफ छ"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"सेवा प्रदायकको नेटवर्क परिवर्तन गर्ने आइकन"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index c3998c5..0117acf 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -577,15 +577,16 @@
<string name="alarm_template_far" msgid="6382760514842998629">"op <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="zen_mode_duration_settings_title" msgid="1553451650289651489">"Duur"</string>
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Altijd vragen"</string>
- <string name="zen_mode_forever" msgid="3339224497605461291">"Totdat je uitzet"</string>
+ <string name="zen_mode_forever" msgid="3339224497605461291">"Totdat je ze uitzet"</string>
<string name="zen_mode_starred_contacts_empty_name" msgid="933552939706125937">"(Geen naam)"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Zojuist"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Deze telefoon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Deze tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microfoon (intern)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockspeaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Extern apparaat"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Verbonden apparaat"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Uit"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aan"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Je apparaat moet opnieuw worden opgestart om deze wijziging toe te passen. Start nu opnieuw op of annuleer de wijziging."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Bedrade koptelefoon"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Microfoonaansluiting"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-microfoon"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aan"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Uit"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Netwerk van provider wordt gewijzigd"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 676a426..1b2e421 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ଏହିକ୍ଷଣି"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"ଏହି ଫୋନ"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ଏହି ଟାବଲେଟ"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"ମାଇକ୍ରୋଫୋନ (ଇଣ୍ଟର୍ନଲ)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ଡକ ସ୍ପିକର"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ଏକ୍ସଟର୍ନଲ ଡିଭାଇସ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"କନେକ୍ଟ କରାଯାଇଥିବା ଡିଭାଇସ"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ଅକ୍ଷମ କରାଯାଇଛି"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ସକ୍ଷମ କରାଯାଇଛି"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ଏହି ପରିବର୍ତ୍ତନ ଲାଗୁ କରିବା ପାଇଁ ଆପଣଙ୍କ ଡିଭାଇସକୁ ନିଶ୍ଚିତ ରୂପେ ରିବୁଟ୍ କରାଯିବା ଆବଶ୍ୟକ। ବର୍ତ୍ତମାନ ରିବୁଟ୍ କରନ୍ତୁ କିମ୍ବା ବାତିଲ କରନ୍ତୁ।"</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ତାରଯୁକ୍ତ ହେଡଫୋନ୍"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"ମାଇକ ଜେକ"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB ମାଇକ"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ଚାଲୁ ଅଛି"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ବନ୍ଦ ଅଛି"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"କେରିଅର୍ ନେଟ୍ୱର୍କ ବଦଳୁଛି"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 4ef2308c..c668e12 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ਹੁਣੇ ਹੀ"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"ਇਹ ਫ਼ੋਨ"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ਇਹ ਟੈਬਲੈੱਟ"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ (ਅੰਦਰੂਨੀ)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ਡੌਕ ਸਪੀਕਰ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ਬਾਹਰੀ ਡੀਵਾਈਸ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ਕਨੈਕਟ ਕੀਤਾ ਡੀਵਾਈਸ"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ਇਸ ਤਬਦੀਲੀ ਨੂੰ ਲਾਗੂ ਕਰਨ ਲਈ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨੂੰ ਰੀਬੂਟ ਕਰਨਾ ਲਾਜ਼ਮੀ ਹੈ। ਹੁਣੇ ਰੀਬੂਟ ਕਰੋ ਜਾਂ ਰੱਦ ਕਰੋ।"</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ਤਾਰ ਵਾਲੇ ਹੈੱਡਫ਼ੋਨ"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"ਮਾਈਕ ਜੈਕ"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB ਮਾਈਕ"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ਚਾਲੂ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ਬੰਦ"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"ਕੈਰੀਅਰ ਨੈੱਟਵਰਕ ਦੀ ਬਦਲੀ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 3693c38..7e90b78 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Przed chwilą"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ten telefon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ten tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (wewnętrzny)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Głośnik ze stacją dokującą"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Urządzenie zewnętrzne"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Połączone urządzenie"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Wyłączono"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Włączono"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Wprowadzenie zmiany wymaga ponownego uruchomienia urządzenia. Uruchom ponownie teraz lub anuluj."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Słuchawki przewodowe"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Gniazdo mikrofonu"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Mikrofon USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Włączono"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Wyłączono"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Zmiana sieci operatora"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 75ffcd1..e10ad07 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Agora"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este telefone"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Este tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microfone (interno)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Alto-falante da base"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desativado"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativado"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reinicializar o dispositivo para que a mudança seja aplicada. Faça isso agora ou cancele."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fones de ouvido com fio"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Entrada para microfone"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Microfone USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ativado"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desativado"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Alteração de rede da operadora"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 535261b..92ab714 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Agora mesmo"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este telemóvel"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Este tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microfone (interno)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altifalante estação carregamento"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo associado"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desativada"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativada"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reiniciar o dispositivo para aplicar esta alteração. Reinicie agora ou cancele."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auscultadores com fios"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Entrada para microfone"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Microfone USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ligado"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desligado"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Rede do operador em mudança."</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 75ffcd1..e10ad07 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Agora"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este telefone"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Este tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microfone (interno)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Alto-falante da base"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desativado"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativado"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reinicializar o dispositivo para que a mudança seja aplicada. Faça isso agora ou cancele."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fones de ouvido com fio"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Entrada para microfone"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Microfone USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ativado"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desativado"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Alteração de rede da operadora"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 242127e..e710634 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Chiar acum"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Acest telefon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Această tabletă"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microfon (intern)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Difuzorul dispozitivului de andocare"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispozitiv extern"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispozitiv conectat"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Dezactivat"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activat"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pentru ca modificarea să se aplice, trebuie să repornești dispozitivul. Repornește-l acum sau anulează."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Căști cu fir"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mufă pentru microfon"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Microfon USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activat"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Dezactivat"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Se schimbă rețeaua operatorului"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 2ac0128..009e071 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Только что"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Этот смартфон"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Этот планшет"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (встроенный)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Колонка с док-станцией"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Внешнее устройство"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Подключенное устройство"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Отключено"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Включено"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Чтобы изменение вступило в силу, необходимо перезапустить устройство. Вы можете сделать это сейчас или позже."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Проводные наушники"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Микрофонный разъем"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-микрофон"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Вкл."</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Выкл."</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Сменить сеть"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index f8565c4..27154f6 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"මේ දැන්"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"මෙම දුරකථනය"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"මෙම ටැබ්ලටය"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"මයික්රෆෝනය (අභ්යන්තර)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ඩොක් ස්පීකරය"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"බාහිර උපාංගය"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"සම්බන්ධ කළ උපාංගය"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"අබල කළා"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"සබලයි"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"මෙම වෙනස යෙදීමට ඔබේ උපාංගය නැවත පණ ගැන්විය යුතුය. දැන් නැවත පණ ගන්වන්න හෝ අවලංගු කරන්න."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"රැහැන්ගත කළ හෙඩ්ෆෝන්"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"මයික් ජැක්කුව"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB මයික්"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ක්රියාත්මකයි"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ක්රියාවිරහිතයි"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"වාහක ජාලය වෙනස් වෙමින්"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 00bb994..ddb35d6 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Teraz"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Tento telefón"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tento tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofón (vnútorný)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Reproduktor doku"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externé zariadenie"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pripojené zariadenie"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Vypnuté"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Zapnuté"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Zmena sa prejaví až po reštarte zariadenia. Môžete ho teraz reštartovať alebo akciu zrušiť."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Slúchadlá s káblom"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Konektor mikrofónu"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Mikrofón USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Zapnúť"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Vypnúť"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Mení sa sieť operátora"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 5bce9fa..4ca5c48 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Pravkar"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ta telefon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ta tablični računalnik"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (notranji)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvočnik nosilca"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Zunanja naprava"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezana naprava"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogočeno"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogočeno"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Napravo je treba znova zagnati, da bo ta sprememba uveljavljena. Znova zaženite zdaj ali prekličite."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žične slušalke"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Vtič za mikrofon"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Mikrofon USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Vklop"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Izklop"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Spreminjanje omrežja operaterja"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 59472e3..d99f2c8 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Pikërisht tani"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ky telefon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ky tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofoni (i brendshëm)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altoparlanti i stacionit"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Pajisja e jashtme"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pajisja e lidhur"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Joaktiv"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pajisja jote duhet të riniset që ky ndryshim të zbatohet. Rinise tani ose anuloje."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kufje me tela"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Fisha e mikrofonit"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Mikrofoni me USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktive"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Joaktive"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Rrjeti i operatorit celular po ndryshohet"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 57e2a0a..cc7c69d 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Управо"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Овај телефон"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Овај таблет"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (интерни)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Звучник базне станице"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Спољни уређај"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Повезани уређај"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Онемогућено"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Омогућено"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Морате да рестартујете уређај да би се ова промена применила. Рестартујте га одмах или откажите."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Жичане слушалице"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Утикач за микрофон"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB микрофон"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Укључено"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Искључено"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Промена мреже мобилног оператера"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index a3eaee1..6b76f87 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Nyss"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Den här telefonen"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Den här surfplattan"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (inbyggd)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockningsstationens högtalare"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Extern enhet"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ansluten enhet"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Inaktiverat"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiverat"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Enheten måste startas om för att ändringen ska börja gälla. Starta om nu eller avbryt."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Hörlurar med sladd"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofonuttag"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-mikrofon"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"På"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Av"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Byter leverantörsnätverk"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 9979a9d..f113e62 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Sasa hivi"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Simu hii"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Kishikwambi hiki"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Maikrofoni (ya ndani)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Spika ya kituo"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Kifaa cha Nje"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Kifaa kilichounganishwa"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Imezimwa"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Imewashwa"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Ni lazima uwashe tena kifaa chako ili mabadiliko haya yatekelezwe. Washa tena sasa au ughairi."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vipokea sauti vya waya"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Pini ya maikrofoni"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Maikrofoni ya USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Umewashwa"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Umezimwa"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Mabadiliko katika mtandao wa mtoa huduma"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 18a3186..beca738 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"சற்றுமுன்"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"இந்த மொபைல்"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"இந்த டேப்லெட்"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"மைக்ரோஃபோன் (அகம்)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"டாக் ஸ்பீக்கர்"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"வெளிப்புறச் சாதனம்"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"இணைக்கப்பட்டுள்ள சாதனம்"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"முடக்கப்பட்டது"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"இயக்கப்பட்டது"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"இந்த மாற்றங்கள் செயல்படுத்தப்பட உங்கள் சாதனத்தை மறுபடி தொடங்க வேண்டும். இப்போதே மறுபடி தொடங்கவும் அல்லது ரத்துசெய்யவும்."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"வயருள்ள ஹெட்ஃபோன்"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"மைக் ஜாக்"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB மைக்"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ஆன்"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ஆஃப்"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"மொபைல் நிறுவன நெட்வொர்க்கை மாற்றும்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index f883796..5fb829d 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ఇప్పుడే"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"ఈ ఫోన్"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ఈ టాబ్లెట్"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"మైక్రోఫోన్ (అంతర్గతం)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"డాక్ స్పీకర్"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ఎక్స్టర్నల్ పరికరం"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"కనెక్ట్ చేసిన పరికరం"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"డిజేబుల్ చేయబడింది"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ఎనేబుల్ చేయబడింది"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ఈ మార్పును వర్తింపజేయాలంటే మీరు మీ పరికరాన్ని తప్పనిసరిగా రీబూట్ చేయాలి. ఇప్పుడే రీబూట్ చేయండి లేదా రద్దు చేయండి."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"వైర్ ఉన్న హెడ్ఫోన్"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"మైక్ జాక్"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB మైక్"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ఆన్లో ఉంది"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ఆఫ్లో ఉంది"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"క్యారియర్ నెట్వర్క్ మారుతోంది"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index e56656b..aa23a44 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"เมื่อสักครู่"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"โทรศัพท์เครื่องนี้"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"แท็บเล็ตเครื่องนี้"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"ไมโครโฟน (ภายใน)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"แท่นชาร์จที่มีลำโพง"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"อุปกรณ์ภายนอก"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"อุปกรณ์ที่เชื่อมต่อ"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ปิดใช้"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"เปิดใช้"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"คุณต้องรีบูตอุปกรณ์เพื่อให้การเปลี่ยนแปลงนี้มีผล รีบูตเลยหรือยกเลิก"</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"หูฟังแบบมีสาย"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"ช่องเสียบไมค์"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"ไมค์ USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"เปิด"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ปิด"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"การเปลี่ยนเครือข่ายผู้ให้บริการ"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 3e9f2387..5a1d4d7 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Ngayon lang"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ang teleponong ito"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ang tablet na ito"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikropono (internal)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Speaker ng dock"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External na Device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Nakakonektang device"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Naka-disable"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Na-enable"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Dapat i-reboot ang iyong device para mailapat ang pagbabagong ito. Mag-reboot ngayon o kanselahin."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired na headphone"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Jack ng mikropono"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB na mikropono"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Naka-on"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Naka-off"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Nagpapalit ng carrier network"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 22c0ab1..d7ad6b1 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Az önce"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Bu telefon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Bu tablet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (dahili)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Yuva hoparlörü"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Harici Cihaz"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Bağlı cihaz"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Devre dışı"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Etkin"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu değişikliğin geçerli olması için cihazınızın yeniden başlatılması gerekir. Şimdi yeniden başlatın veya iptal edin."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kablolu kulaklık"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofon jakı"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mikrofon"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Açık"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Kapalı"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operatör ağı değiştiriliyor"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 50ebd24..2de4c09 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -577,15 +577,16 @@
<string name="alarm_template_far" msgid="6382760514842998629">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="zen_mode_duration_settings_title" msgid="1553451650289651489">"Тривалість"</string>
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Запитувати щоразу"</string>
- <string name="zen_mode_forever" msgid="3339224497605461291">"Доки не вимкнути"</string>
+ <string name="zen_mode_forever" msgid="3339224497605461291">"Доки ви не вимкнете"</string>
<string name="zen_mode_starred_contacts_empty_name" msgid="933552939706125937">"(Без імені)"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Щойно"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Цей телефон"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Цей планшет"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Мікрофон (внутрішній)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Динамік док-станції"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Зовнішній пристрій"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Підключений пристрій"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Вимкнено"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Увімкнено"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Щоб застосувати ці зміни, потрібний перезапуск. Перезапустіть пристрій або скасуйте зміни."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Дротові навушники"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Гніздо для мікрофона"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB-мікрофон"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Увімкнено"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Вимкнено"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Змінення мережі оператора"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index d6dd2c8..e2fbfab 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"ابھی ابھی"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"یہ فون"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"یہ ٹیبلیٹ"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"مائیکروفون (داخلی)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ڈاک اسپیکر"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"بیرونی آلہ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"منسلک آلہ"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"غیر فعال"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"فعال"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"اس تبدیلی کو لاگو کرنے کے ليے آپ کے آلہ کو ریبوٹ کرنا ضروری ہے۔ ابھی ریبوٹ کریں یا منسوخ کریں۔"</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"وائرڈ ہیڈ فون"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"مائیک جیک"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB مائیک"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"آن"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"آف"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"کیریئر نیٹ ورک کی تبدیلی"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 1e3d64f3..40d1d10 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Hozir"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Shu telefon"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Shu planshet"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (ichki)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dok-stansiyali karnay"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Tashqi qurilma"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ulangan qurilma"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Oʻchiq"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Yoniq"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Oʻzgarishlar kuchga kirishi uchun qurilmani oʻchirib yoqing. Buni hozir yoki keyinroq bajarishingiz mumkin."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Simli quloqlik"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofon ulagichi"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB mik"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Yoniq"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Oʻchiq"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Mobil tarmoqni o‘zgartirish"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 95092ff..874aa18 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Vừa xong"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Điện thoại này"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Máy tính bảng này"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Micrô (bên trong)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Loa có gắn đế"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Thiết bị bên ngoài"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Thiết bị đã kết nối"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Đã tắt"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Đã bật"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bạn phải khởi động lại thiết bị để áp dụng sự thay đổi này. Hãy khởi động lại ngay hoặc hủy."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Tai nghe có dây"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Giắc cắm micrô"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Micrô có cổng USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Đang bật"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Đang tắt"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Thay đổi mạng của nhà mạng"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index fb9e7b1..8edc656 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"刚刚"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"这部手机"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"这部平板电脑"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"麦克风(内部)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"基座音箱"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部设备"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"连接的设备"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"已停用"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已启用"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"设备必须重新启动才能应用此更改。您可以立即重新启动或取消。"</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有线耳机"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"麦克风插孔"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB 麦克风"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"开启"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"关闭"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"运营商网络正在更改"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 9c6da5f..533a53f 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"剛剛"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"此手機"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"此平板電腦"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"麥克風 (內置)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"插座喇叭"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部裝置"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"已連接的裝置"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"已停用"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已啟用"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"你的裝置必須重新開機,才能套用此變更。請立即重新開機或取消。"</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線耳機"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"麥克風插孔"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB 麥克風"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"開啟"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"關閉"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"流動網絡供應商網絡正在變更"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 501b088..692b6e1 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"剛剛"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"這支手機"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"這台平板電腦"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"麥克風 (內部)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"座架喇叭"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部裝置"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"已連結的裝置"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"已停用"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已啟用"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"裝置必須重新啟動才能套用這項變更。請立即重新啟動或取消變更。"</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線耳機"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"麥克風插孔"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB 麥克風"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"開啟"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"關閉"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"電信業者網路正在進行變更"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 4f875de..4f0acbd 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -582,10 +582,11 @@
<string name="time_unit_just_now" msgid="3006134267292728099">"Khona manje"</string>
<string name="media_transfer_this_device_name" msgid="2357329267148436433">"Le foni"</string>
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Le thebhulethi"</string>
+ <!-- no translation found for media_transfer_this_device_name_desktop (7912386128141470452) -->
+ <skip />
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
- <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
- <skip />
+ <string name="media_transfer_internal_mic" msgid="797333824290228595">"Imakrofoni (okwangaphakathi)"</string>
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Isipikha sentuba"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Idivayisi Yangaphandle"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Idivayisi exhunyiwe"</string>
@@ -686,11 +687,14 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Ikhutshaziwe"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Inikwe amandla"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Kufanele idivayisi yakho iqaliswe ukuze lolu shintsho lusebenze. Qalisa manje noma khansela."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Ama-headphone anentambo"</string>
- <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <!-- no translation found for media_transfer_wired_headphone_name (8698668536022665254) -->
<skip />
- <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <!-- no translation found for media_transfer_headphone_name (1131962659136578852) -->
<skip />
+ <!-- no translation found for media_transfer_usb_speaker_name (4736537022543593896) -->
+ <skip />
+ <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Umgodi we-earphone ye-mic"</string>
+ <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"I-mic ye-USB"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Vuliwe"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Valiwe"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Inethiwekhi yenkampani yenethiwekhi iyashintsha"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 0b094a2..34e33c0 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1639,7 +1639,7 @@
<string name="cached_apps_freezer_reboot_dialog_text">Your device must be rebooted for this change to apply. Reboot now or cancel.</string>
<!-- Name of the 3.5mm and usb audio device. [CHAR LIMIT=50] -->
- <string name="media_transfer_wired_usb_device_name">Wired headphone</string>
+ <string name="media_transfer_wired_headphone_name">Wired headphone</string>
<!-- Name of the 3.5mm headphone, used in desktop devices. [CHAR LIMIT=50] -->
<string name="media_transfer_headphone_name">Headphone</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 6f2567b..a3f9e51 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -80,7 +80,9 @@
"com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_STATE_CHANGE";
public static final String EXTRA_LE_AUDIO_SHARING_STATE = "BLUETOOTH_LE_AUDIO_SHARING_STATE";
public static final String EXTRA_BLUETOOTH_DEVICE = "BLUETOOTH_DEVICE";
+ public static final String EXTRA_BT_DEVICE_TO_AUTO_ADD_SOURCE = "BT_DEVICE_TO_AUTO_ADD_SOURCE";
public static final String EXTRA_START_LE_AUDIO_SHARING = "START_LE_AUDIO_SHARING";
+ public static final String EXTRA_PAIR_AND_JOIN_SHARING = "PAIR_AND_JOIN_SHARING";
public static final int BROADCAST_STATE_UNKNOWN = 0;
public static final int BROADCAST_STATE_ON = 1;
public static final int BROADCAST_STATE_OFF = 2;
@@ -1224,7 +1226,7 @@
Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_STATE_CHANGE);
intent.putExtra(EXTRA_LE_AUDIO_SHARING_STATE, state);
intent.setPackage(mContext.getPackageName());
- Log.e(TAG, "notifyBroadcastStateChange for state = " + state);
+ Log.d(TAG, "notifyBroadcastStateChange for state = " + state);
mContext.sendBroadcast(intent);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
index 148e164..c9f9d1b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
@@ -151,7 +151,19 @@
Log.d(TAG, "The BluetoothLeBroadcastAssistant is null");
return;
}
- mService.addSource(sink, metadata, isGroupOp);
+ try {
+ mService.addSource(sink, metadata, isGroupOp);
+ } catch (IllegalStateException e) {
+ // BT will check callback registration before add source.
+ // If it throw callback exception when bt is disabled, then the failure is intended,
+ // just catch it here.
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null && adapter.isEnabled()) {
+ throw e;
+ } else {
+ Log.d(TAG, "Catch addSource failure when bt is disabled: " + e);
+ }
+ }
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/MultiTogglePreference.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/MultiTogglePreference.java
index 01bb6f0..7ee7180 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/MultiTogglePreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/MultiTogglePreference.java
@@ -33,6 +33,7 @@
private final String mTitle;
private final ImmutableList<ToggleInfo> mToggleInfos;
private final int mState;
+ private final boolean mIsActive;
private final boolean mIsAllowedChangingState;
private final Bundle mExtras;
@@ -40,6 +41,7 @@
@NonNull String title,
List<ToggleInfo> toggleInfos,
int state,
+ boolean isActive,
boolean allowChangingState,
Bundle extras) {
super(DeviceSettingType.DEVICE_SETTING_TYPE_MULTI_TOGGLE);
@@ -47,6 +49,7 @@
mTitle = title;
mToggleInfos = ImmutableList.copyOf(toggleInfos);
mState = state;
+ mIsActive = isActive;
mIsAllowedChangingState = allowChangingState;
mExtras = extras;
}
@@ -67,9 +70,11 @@
List<ToggleInfo> toggleInfos = new ArrayList<>();
in.readTypedList(toggleInfos, ToggleInfo.CREATOR);
int state = in.readInt();
+ boolean isActive = in.readBoolean();
boolean allowChangingState = in.readBoolean();
Bundle extras = in.readBundle(Bundle.class.getClassLoader());
- return new MultiTogglePreference(title, toggleInfos, state, allowChangingState, extras);
+ return new MultiTogglePreference(
+ title, toggleInfos, state, isActive, allowChangingState, extras);
}
public static final Creator<MultiTogglePreference> CREATOR =
@@ -99,6 +104,7 @@
dest.writeString(mTitle);
dest.writeTypedList(mToggleInfos, flags);
dest.writeInt(mState);
+ dest.writeBoolean(mIsActive);
dest.writeBoolean(mIsAllowedChangingState);
dest.writeBundle(mExtras);
}
@@ -108,6 +114,7 @@
private String mTitle;
private ImmutableList.Builder<ToggleInfo> mToggleInfos = new ImmutableList.Builder<>();
private int mState;
+ private boolean mIsActive;
private boolean mAllowChangingState;
private Bundle mExtras = Bundle.EMPTY;
@@ -148,6 +155,19 @@
}
/**
+ * Sets whether the current state is considered as an "active" state. If it's set to true,
+ * the toggle will be highlighted in UI.
+ *
+ * @param isActive The active state.
+ * @return Returns the Builder object.
+ */
+ @NonNull
+ public Builder setIsActive(boolean isActive) {
+ mIsActive = isActive;
+ return this;
+ }
+
+ /**
* Sets whether state can be changed by user.
*
* @param allowChangingState Whether user is allowed to change state.
@@ -178,7 +198,7 @@
@NonNull
public MultiTogglePreference build() {
return new MultiTogglePreference(
- mTitle, mToggleInfos.build(), mState, mAllowChangingState, mExtras);
+ mTitle, mToggleInfos.build(), mState, mIsActive, mAllowChangingState, mExtras);
}
}
@@ -202,6 +222,16 @@
}
/**
+ * Whether the current state is considered as an active state. If it's set to true, the toggle
+ * will be highlighted in UI.
+ *
+ * @return Returns the active state.
+ */
+ public boolean isActive() {
+ return mIsActive;
+ }
+
+ /**
* Gets the toggle list in the preference.
*
* @return the toggle list.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
index 29664f6..851b614 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
@@ -159,7 +159,7 @@
title = pref.title,
toggles = pref.toggleInfos.map { it.toModel() },
isAllowedChangingState = pref.isAllowedChangingState,
- isActive = true,
+ isActive = pref.isActive,
state = DeviceSettingStateModel.MultiTogglePreferenceState(pref.state),
updateState = { newState ->
coroutineScope.launch(backgroundCoroutineContext) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingServiceConnection.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingServiceConnection.kt
index 7eae5b2..3d8ff86 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingServiceConnection.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingServiceConnection.kt
@@ -56,11 +56,13 @@
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
+import kotlinx.coroutines.plus
import kotlinx.coroutines.withContext
@OptIn(ExperimentalCoroutinesApi::class)
@@ -101,8 +103,7 @@
} else if (allStatus.all { it is ServiceConnectionStatus.Connected }) {
allStatus
.filterIsInstance<
- ServiceConnectionStatus.Connected<
- IDeviceSettingsProviderService>
+ ServiceConnectionStatus.Connected<IDeviceSettingsProviderService>
>()
.all { it.service.serviceStatus?.enabled == true }
} else {
@@ -232,7 +233,7 @@
IDeviceSettingsProviderService.Stub::asInterface,
)
.stateIn(
- coroutineScope,
+ coroutineScope.plus(backgroundCoroutineContext),
SharingStarted.WhileSubscribed(),
ServiceConnectionStatus.Connecting,
)
@@ -263,21 +264,30 @@
transform: ((IBinder) -> T),
): Flow<ServiceConnectionStatus<T>> {
return callbackFlow {
- val serviceConnection =
- object : ServiceConnection {
- override fun onServiceConnected(name: ComponentName, service: IBinder) {
- launch { send(ServiceConnectionStatus.Connected(transform(service))) }
- }
+ val serviceConnection =
+ object : ServiceConnection {
+ override fun onServiceConnected(name: ComponentName, service: IBinder) {
+ launch { send(ServiceConnectionStatus.Connected(transform(service))) }
+ }
- override fun onServiceDisconnected(name: ComponentName?) {
- launch { send(ServiceConnectionStatus.Connecting) }
+ override fun onServiceDisconnected(name: ComponentName?) {
+ launch { send(ServiceConnectionStatus.Connecting) }
+ }
}
+ if (
+ !context.bindService(
+ intent,
+ Context.BIND_AUTO_CREATE,
+ { launch { it.run() } },
+ serviceConnection,
+ )
+ ) {
+ Log.w(TAG, "Fail to bind service $intent")
+ launch { send(ServiceConnectionStatus.Failed) }
}
- if (!context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)) {
- launch { send(ServiceConnectionStatus.Failed) }
+ awaitClose { context.unbindService(serviceConnection) }
}
- awaitClose { context.unbindService(serviceConnection) }
- }
+ .flowOn(backgroundCoroutineContext)
}
private suspend fun tryGetEndpointFromMetadata(cachedDevice: CachedBluetoothDevice): EndPoint? =
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java
index 766cd43..dae69e6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java
@@ -80,6 +80,10 @@
context, id, audioDeviceInfoType, maxVolume, currentVolume, isVolumeFixed);
}
+ public @AudioDeviceType int getAudioDeviceInfoType() {
+ return mAudioDeviceInfoType;
+ }
+
public static boolean isSupportedInputDevice(@AudioDeviceType int audioDeviceInfoType) {
return switch (audioDeviceInfoType) {
case TYPE_BUILTIN_MIC,
@@ -128,8 +132,7 @@
@VisibleForTesting
int getDrawableResId() {
- // TODO(b/357122624): check with UX to obtain the icon for desktop devices.
- return R.drawable.ic_media_tablet;
+ return R.drawable.ic_media_microphone;
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
index 874e030..0c50166 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
@@ -15,13 +15,20 @@
*/
package com.android.settingslib.media;
+import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_SELECTED;
+
import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceCallback;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
+import android.media.MediaRecorder;
import android.os.Handler;
+import android.util.Slog;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
@@ -35,12 +42,18 @@
private static final String TAG = "InputRouteManager";
+ @VisibleForTesting
+ static final AudioAttributes INPUT_ATTRIBUTES =
+ new AudioAttributes.Builder().setCapturePreset(MediaRecorder.AudioSource.MIC).build();
+
private final Context mContext;
private final AudioManager mAudioManager;
@VisibleForTesting final List<MediaDevice> mInputMediaDevices = new CopyOnWriteArrayList<>();
+ private MediaDevice mSelectedInputDevice;
+
private final Collection<InputDeviceCallback> mCallbacks = new CopyOnWriteArrayList<>();
@VisibleForTesting
@@ -76,8 +89,27 @@
mCallbacks.remove(callback);
}
+ public @Nullable MediaDevice getSelectedInputDevice() {
+ return mSelectedInputDevice;
+ }
+
private void dispatchInputDeviceListUpdate() {
- // TODO (b/360175574): Get selected input device.
+ // Get selected input device.
+ List<AudioDeviceAttributes> attributesOfSelectedInputDevices =
+ mAudioManager.getDevicesForAttributes(INPUT_ATTRIBUTES);
+ int selectedInputDeviceAttributesType;
+ if (attributesOfSelectedInputDevices.isEmpty()) {
+ Slog.e(TAG, "Unexpected empty list of input devices. Using built-in mic.");
+ selectedInputDeviceAttributesType = AudioDeviceInfo.TYPE_BUILTIN_MIC;
+ } else {
+ if (attributesOfSelectedInputDevices.size() > 1) {
+ Slog.w(
+ TAG,
+ "AudioManager.getDevicesForAttributes returned more than one element."
+ + " Using the first one.");
+ }
+ selectedInputDeviceAttributesType = attributesOfSelectedInputDevices.get(0).getType();
+ }
// Get all input devices.
AudioDeviceInfo[] audioDeviceInfos =
@@ -93,6 +125,10 @@
getCurrentInputGain(),
isInputGainFixed());
if (mediaDevice != null) {
+ if (info.getType() == selectedInputDeviceAttributesType) {
+ mediaDevice.setState(STATE_SELECTED);
+ mSelectedInputDevice = mediaDevice;
+ }
mInputMediaDevices.add(mediaDevice);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index 116de56..0b8fb22ce 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -90,7 +90,7 @@
name =
inputRoutingEnabledAndIsDesktop()
? context.getString(R.string.media_transfer_headphone_name)
- : context.getString(R.string.media_transfer_wired_usb_device_name);
+ : context.getString(R.string.media_transfer_wired_headphone_name);
break;
case TYPE_USB_DEVICE:
case TYPE_USB_HEADSET:
@@ -98,7 +98,7 @@
name =
inputRoutingEnabledAndIsDesktop()
? context.getString(R.string.media_transfer_usb_speaker_name)
- : context.getString(R.string.media_transfer_wired_usb_device_name);
+ : context.getString(R.string.media_transfer_wired_headphone_name);
break;
case TYPE_DOCK:
name = context.getString(R.string.media_transfer_dock_speaker_device_name);
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java b/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java
index 251cd36..9a9a960 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java
@@ -87,7 +87,7 @@
* Returns the conversation info drawable
*/
public Drawable getBaseIconDrawable(ShortcutInfo shortcutInfo) {
- return mLauncherApps.getShortcutIconDrawable(shortcutInfo, mFillResIconDpi);
+ return mLauncherApps.getShortcutIconDrawable(shortcutInfo, mFullResIconDpi);
}
/**
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/MultiTogglePreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/MultiTogglePreferenceTest.java
index 62fcb5e..1c7b5bc 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/MultiTogglePreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/MultiTogglePreferenceTest.java
@@ -120,6 +120,7 @@
.addToggleInfo(TOGGLE_INFO_1)
.addToggleInfo(TOGGLE_INFO_2)
.setState(123)
+ .setIsActive(true)
.setAllowChangingState(true)
.setExtras(buildBundle("key1", "value1"))
.build();
@@ -130,6 +131,7 @@
assertThat(fromParcel.getToggleInfos().stream().map(ToggleInfo::getLabel).toList())
.containsExactly("label1", "label2");
assertThat(fromParcel.getState()).isEqualTo(preference.getState());
+ assertThat(fromParcel.isActive()).isEqualTo(preference.isActive());
assertThat(fromParcel.isAllowedChangingState())
.isEqualTo(preference.isAllowedChangingState());
assertThat(fromParcel.getExtras().getString("key1"))
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt
index 81b5634..0cb6bc1 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepositoryTest.kt
@@ -102,9 +102,9 @@
`when`(settingProviderService2.queryLocalInterface(anyString()))
.thenReturn(settingProviderService2)
- `when`(context.bindService(any(), any(), anyInt())).then { input ->
+ `when`(context.bindService(any(), anyInt(), any(), any())).then { input ->
val intent = input.getArgument<Intent?>(0)
- val connection = input.getArgument<ServiceConnection>(1)
+ val connection = input.getArgument<ServiceConnection>(3)
when (intent?.action) {
CONFIG_SERVICE_INTENT_ACTION ->
@@ -210,7 +210,7 @@
fun getDeviceSettingsConfig_bindingServiceFail_returnNull() {
testScope.runTest {
`when`(configService.getDeviceSettingsConfig(any())).thenReturn(DEVICE_SETTING_CONFIG)
- doReturn(false).`when`(context).bindService(any(), any(), anyInt())
+ doReturn(false).`when`(context).bindService(any(), anyInt(), any(), any())
val config = underTest.getDeviceSettingsConfig(cachedDevice)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java
index bc1ea6c..088d554 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java
@@ -18,9 +18,6 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
import android.content.Context;
import android.media.AudioDeviceInfo;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -64,7 +61,7 @@
CURRENT_VOLUME,
IS_VOLUME_FIXED);
assertThat(builtinMediaDevice).isNotNull();
- assertThat(builtinMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_media_tablet);
+ assertThat(builtinMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_media_microphone);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java
index 2501ae6..8a18d07 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java
@@ -16,6 +16,8 @@
package com.android.settingslib.media;
+import static com.android.settingslib.media.InputRouteManager.INPUT_ATTRIBUTES;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
@@ -23,6 +25,7 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
@@ -36,6 +39,10 @@
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowRouter2Manager.class})
public class InputRouteManagerTest {
@@ -124,6 +131,97 @@
}
@Test
+ public void getSelectedInputDevice_returnOneFromAudioManager() {
+ final AudioDeviceInfo info1 = mock(AudioDeviceInfo.class);
+ when(info1.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
+ when(info1.getId()).thenReturn(INPUT_WIRED_HEADSET_ID);
+
+ final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class);
+ when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC);
+ when(info2.getId()).thenReturn(BUILTIN_MIC_ID);
+
+ final AudioManager audioManager = mock(AudioManager.class);
+ AudioDeviceInfo[] devices = {info1, info2};
+ when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices);
+
+ // Mock audioManager.getDevicesForAttributes returns exactly one audioDeviceAttributes.
+ AudioDeviceAttributes audioDeviceAttributes = new AudioDeviceAttributes(info1);
+ when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES))
+ .thenReturn(Collections.singletonList(audioDeviceAttributes));
+
+ InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
+ inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices);
+
+ // The selected input device has the same type as the one returned from AudioManager.
+ InputMediaDevice selectedInputDevice =
+ (InputMediaDevice) inputRouteManager.getSelectedInputDevice();
+ assertThat(selectedInputDevice.getAudioDeviceInfoType())
+ .isEqualTo(AudioDeviceInfo.TYPE_WIRED_HEADSET);
+ }
+
+ @Test
+ public void getSelectedInputDevice_returnMoreThanOneFromAudioManager() {
+ final AudioDeviceInfo info1 = mock(AudioDeviceInfo.class);
+ when(info1.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
+ when(info1.getId()).thenReturn(INPUT_WIRED_HEADSET_ID);
+
+ final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class);
+ when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC);
+ when(info2.getId()).thenReturn(BUILTIN_MIC_ID);
+
+ final AudioManager audioManager = mock(AudioManager.class);
+ AudioDeviceInfo[] devices = {info1, info2};
+ when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices);
+
+ // Mock audioManager.getDevicesForAttributes returns more than one audioDeviceAttributes.
+ AudioDeviceAttributes audioDeviceAttributes1 = new AudioDeviceAttributes(info1);
+ AudioDeviceAttributes audioDeviceAttributes2 = new AudioDeviceAttributes(info2);
+ List<AudioDeviceAttributes> attributesOfSelectedInputDevices = new ArrayList<>();
+ attributesOfSelectedInputDevices.add(audioDeviceAttributes1);
+ attributesOfSelectedInputDevices.add(audioDeviceAttributes2);
+ when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES))
+ .thenReturn(attributesOfSelectedInputDevices);
+
+ InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
+ inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices);
+
+ // The selected input device has the same type as the first one returned from AudioManager.
+ InputMediaDevice selectedInputDevice =
+ (InputMediaDevice) inputRouteManager.getSelectedInputDevice();
+ assertThat(selectedInputDevice.getAudioDeviceInfoType())
+ .isEqualTo(AudioDeviceInfo.TYPE_WIRED_HEADSET);
+ }
+
+ @Test
+ public void getSelectedInputDevice_returnEmptyFromAudioManager() {
+ final AudioDeviceInfo info1 = mock(AudioDeviceInfo.class);
+ when(info1.getType()).thenReturn(AudioDeviceInfo.TYPE_WIRED_HEADSET);
+ when(info1.getId()).thenReturn(INPUT_WIRED_HEADSET_ID);
+
+ final AudioDeviceInfo info2 = mock(AudioDeviceInfo.class);
+ when(info2.getType()).thenReturn(AudioDeviceInfo.TYPE_BUILTIN_MIC);
+ when(info2.getId()).thenReturn(BUILTIN_MIC_ID);
+
+ final AudioManager audioManager = mock(AudioManager.class);
+ AudioDeviceInfo[] devices = {info1, info2};
+ when(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(devices);
+
+ // Mock audioManager.getDevicesForAttributes returns empty list of audioDeviceAttributes.
+ List<AudioDeviceAttributes> attributesOfSelectedInputDevices = new ArrayList<>();
+ when(audioManager.getDevicesForAttributes(INPUT_ATTRIBUTES))
+ .thenReturn(attributesOfSelectedInputDevices);
+
+ InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager);
+ inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices);
+
+ // The selected input device has default type AudioDeviceInfo.TYPE_BUILTIN_MIC.
+ InputMediaDevice selectedInputDevice =
+ (InputMediaDevice) inputRouteManager.getSelectedInputDevice();
+ assertThat(selectedInputDevice.getAudioDeviceInfoType())
+ .isEqualTo(AudioDeviceInfo.TYPE_BUILTIN_MIC);
+ }
+
+ @Test
public void getMaxInputGain_returnMaxInputGain() {
assertThat(mInputRouteManager.getMaxInputGain()).isEqualTo(15);
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
index 23cfc01..da5f428 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
@@ -106,12 +106,12 @@
when(mInfo.getName()).thenReturn(deviceName);
assertThat(mPhoneMediaDevice.getName())
- .isEqualTo(mContext.getString(R.string.media_transfer_wired_usb_device_name));
+ .isEqualTo(mContext.getString(R.string.media_transfer_wired_headphone_name));
when(mInfo.getType()).thenReturn(TYPE_USB_DEVICE);
assertThat(mPhoneMediaDevice.getName())
- .isEqualTo(mContext.getString(R.string.media_transfer_wired_usb_device_name));
+ .isEqualTo(mContext.getString(R.string.media_transfer_wired_headphone_name));
when(mInfo.getType()).thenReturn(TYPE_BUILTIN_SPEAKER);
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 40a8199..d710939 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -86,6 +86,7 @@
Settings.Secure.DOUBLE_TAP_TO_WAKE,
Settings.Secure.WAKE_GESTURE_ENABLED,
Settings.Secure.LONG_PRESS_TIMEOUT,
+ Settings.Secure.KEY_REPEAT_ENABLED,
Settings.Secure.KEY_REPEAT_TIMEOUT_MS,
Settings.Secure.KEY_REPEAT_DELAY_MS,
Settings.Secure.CAMERA_GESTURE_DISABLED,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 3b9c683..fa16a44 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -133,6 +133,7 @@
VALIDATORS.put(Secure.DOUBLE_TAP_TO_WAKE, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.WAKE_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.LONG_PRESS_TIMEOUT, NON_NEGATIVE_INTEGER_VALIDATOR);
+ VALIDATORS.put(Secure.KEY_REPEAT_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.KEY_REPEAT_TIMEOUT_MS, NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.KEY_REPEAT_DELAY_MS, NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.CAMERA_GESTURE_DISABLED, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index ba59ce8..f64c305 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -545,6 +545,10 @@
reportDeviceConfigAccess(prefix);
return result;
}
+ case Settings.CALL_METHOD_LIST_NAMESPACES_CONFIG -> {
+ Bundle result = packageNamespacesForCallResult(getAllConfigFlagNamespaces());
+ return result;
+ }
case Settings.CALL_METHOD_REGISTER_MONITOR_CALLBACK_CONFIG -> {
RemoteCallback callback = args.getParcelable(
Settings.CALL_METHOD_MONITOR_CALLBACK_KEY);
@@ -1337,6 +1341,23 @@
}
@NonNull
+ private HashSet<String> getAllConfigFlagNamespaces() {
+ Set<String> flagNames = getAllConfigFlags(null).keySet();
+ HashSet<String> namespaces = new HashSet();
+ for (String name : flagNames) {
+ int slashIndex = name.indexOf("/");
+ boolean validSlashIndex = slashIndex != -1
+ && slashIndex != 0
+ && slashIndex != name.length();
+ if (validSlashIndex) {
+ String namespace = name.substring(0, slashIndex);
+ namespaces.add(namespace);
+ }
+ }
+ return namespaces;
+ }
+
+ @NonNull
private HashMap<String, String> getAllConfigFlags(@Nullable String prefix) {
if (DEBUG) {
Slog.v(LOG_TAG, "getAllConfigFlags() for " + prefix);
@@ -1995,8 +2016,6 @@
if (!isValidMediaUri(name, value)) {
return false;
}
- // Invalidate any relevant cache files
- cacheFile.delete();
}
final boolean success;
@@ -2034,6 +2053,11 @@
return false;
}
+ if (cacheFile != null) {
+ // Invalidate any relevant cache files
+ cacheFile.delete();
+ }
+
if ((operation == MUTATION_OPERATION_INSERT || operation == MUTATION_OPERATION_UPDATE)
&& cacheFile != null && value != null) {
final Uri ringtoneUri = Uri.parse(value);
@@ -2561,6 +2585,12 @@
return result;
}
+ private Bundle packageNamespacesForCallResult(@NonNull HashSet<String> namespaces) {
+ Bundle result = new Bundle();
+ result.putSerializable(Settings.NameValueTable.VALUE, namespaces);
+ return result;
+ }
+
private void setMonitorCallback(RemoteCallback callback) {
if (callback == null) {
return;
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index cd16af7..bd7067b 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -860,6 +860,7 @@
resource_dirs: [],
kotlincflags: ["-Xjvm-default=all"],
optimize: {
+ optimize: false,
shrink_resources: false,
optimized_shrink_resources: false,
proguard_flags_files: ["proguard.flags"],
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index f3a28ca..c49ffb4 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -538,6 +538,13 @@
}
flag {
+ name: "status_bar_connected_displays"
+ namespace: "systemui"
+ description: "Shows the status bar on connected displays"
+ bug: "362720336"
+}
+
+flag {
name: "status_bar_switch_to_spn_from_data_spn"
namespace: "systemui"
description: "Fix usage of the SPN broadcast extras"
@@ -548,6 +555,13 @@
}
flag {
+ name: "status_bar_simple_fragment"
+ namespace: "systemui"
+ description: "Feature flag for refactoring the collapsed status bar fragment"
+ bug: "364360986"
+}
+
+flag {
name: "new_volume_panel"
namespace: "systemui"
description: "Switches to the new volume panel (without Slices)."
@@ -1049,6 +1063,13 @@
}
flag {
+ name: "communal_widget_resizing"
+ namespace: "systemui"
+ description: "Allow resizing of widgets on glanceable hub"
+ bug: "368053818"
+}
+
+flag {
name: "app_clips_backlinks"
namespace: "systemui"
description: "Enables Backlinks improvement feature in App Clips"
@@ -1401,3 +1422,13 @@
description: "Allow non-touchscreen devices to bypass falsing"
bug: "319809270"
}
+
+flag {
+ name: "media_projection_dialog_behind_lockscreen"
+ namespace: "systemui"
+ description: "Ensure MediaProjection Dialog appears behind the lockscreen"
+ bug: "351409536"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogTransitionAnimator.kt
index 907c39d..f5d01d7 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogTransitionAnimator.kt
@@ -944,26 +944,9 @@
}
override fun onTransitionAnimationEnd(isExpandingFullyAbove: Boolean) {
- // onLaunchAnimationEnd is called by an Animator at the end of the animation,
- // on a Choreographer animation tick. The following calls will move the animated
- // content from the dialog overlay back to its original position, and this
- // change must be reflected in the next frame given that we then sync the next
- // frame of both the content and dialog ViewRoots. However, in case that content
- // is rendered by Compose, whose compositions are also scheduled on a
- // Choreographer frame, any state change made *right now* won't be reflected in
- // the next frame given that a Choreographer frame can't schedule another and
- // have it happen in the same frame. So we post the forwarded calls to
- // [Controller.onLaunchAnimationEnd], leaving this Choreographer frame, ensuring
- // that the move of the content back to its original window will be reflected in
- // the next frame right after [onLaunchAnimationEnd] is called.
- //
- // TODO(b/330672236): Move this to TransitionAnimator.
- dialog.context.mainExecutor.execute {
- startController.onTransitionAnimationEnd(isExpandingFullyAbove)
- endController.onTransitionAnimationEnd(isExpandingFullyAbove)
-
- onLaunchAnimationEnd()
- }
+ startController.onTransitionAnimationEnd(isExpandingFullyAbove)
+ endController.onTransitionAnimationEnd(isExpandingFullyAbove)
+ onLaunchAnimationEnd()
}
override fun onTransitionAnimationProgress(
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
index fc4cf1d..859fc4e0 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
@@ -379,13 +379,26 @@
Log.d(TAG, "Animation ended")
}
- // TODO(b/330672236): Post this to the main thread instead so that it does not
- // flicker with Flexiglass enabled.
- controller.onTransitionAnimationEnd(isExpandingFullyAbove)
- transitionContainerOverlay.remove(windowBackgroundLayer)
+ // onAnimationEnd is called at the end of the animation, on a Choreographer
+ // animation tick. During dialog launches, the following calls will move the
+ // animated content from the dialog overlay back to its original position, and
+ // this change must be reflected in the next frame given that we then sync the
+ // next frame of both the content and dialog ViewRoots. During SysUI activity
+ // launches, we will instantly collapse the shade at the end of the transition.
+ // However, if those are rendered by Compose, whose compositions are also
+ // scheduled on a Choreographer frame, any state change made *right now* won't
+ // be reflected in the next frame given that a Choreographer frame can't
+ // schedule another and have it happen in the same frame. So we post the
+ // forwarded calls to [Controller.onLaunchAnimationEnd] in the main executor,
+ // leaving this Choreographer frame, ensuring that any state change applied by
+ // onTransitionAnimationEnd() will be reflected in the same frame.
+ mainExecutor.execute {
+ controller.onTransitionAnimationEnd(isExpandingFullyAbove)
+ transitionContainerOverlay.remove(windowBackgroundLayer)
- if (moveBackgroundLayerWhenAppVisibilityChanges && controller.isLaunching) {
- openingWindowSyncViewOverlay?.remove(windowBackgroundLayer)
+ if (moveBackgroundLayerWhenAppVisibilityChanges && controller.isLaunching) {
+ openingWindowSyncViewOverlay?.remove(windowBackgroundLayer)
+ }
}
}
}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/windowsizeclass/WindowSizeClass.kt b/packages/SystemUI/compose/core/src/com/android/compose/windowsizeclass/WindowSizeClass.kt
index c01396a..4674d6e 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/windowsizeclass/WindowSizeClass.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/windowsizeclass/WindowSizeClass.kt
@@ -16,16 +16,15 @@
package com.android.compose.windowsizeclass
-import android.view.WindowManager
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.toComposeRect
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
+import androidx.window.layout.WindowMetricsCalculator
val LocalWindowSizeClass =
staticCompositionLocalOf<WindowSizeClass> {
@@ -42,10 +41,7 @@
LocalConfiguration.current
val density = LocalDensity.current
val context = LocalContext.current
- val metrics =
- remember(context) {
- context.getSystemService(WindowManager::class.java)!!.currentWindowMetrics
- }
+ val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(context)
val size = with(density) { metrics.bounds.toComposeRect().size.toDpSize() }
return WindowSizeClass.calculateFromSize(size)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
index 5f7b1ad..f4d9e82 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
@@ -35,7 +35,6 @@
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.res.R
import com.android.systemui.util.animation.MeasurementInput
-import kotlinx.coroutines.ExperimentalCoroutinesApi
object MediaCarousel {
object Elements {
@@ -47,7 +46,6 @@
}
}
-@ExperimentalCoroutinesApi
@Composable
fun SceneScope.MediaCarousel(
isVisible: Boolean,
@@ -79,7 +77,7 @@
offsetProvider?.invoke() ?: IntOffset.Zero
)
}
- }
+ },
)
.layout { measurable, constraints ->
val placeable = measurable.measure(constraints)
@@ -89,7 +87,7 @@
MeasurementInput(placeable.width, placeable.height)
carouselController.setSceneContainerSize(
placeable.width,
- placeable.height
+ placeable.height,
)
layout(placeable.width, placeable.height) {
@@ -106,7 +104,7 @@
}
},
update = { it.setView(carouselController.mediaFrame) },
- onRelease = { it.removeAllViews() }
+ onRelease = { it.removeAllViews() },
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 0c1c165..d91958a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -392,7 +392,7 @@
{ mediaOffset.roundToPx() },
)
}
- Box(modifier = Modifier.padding(horizontal = shadeHorizontalPadding)) {
+ Column(modifier = Modifier.padding(horizontal = shadeHorizontalPadding)) {
if (mediaInRow) {
Layout(content = content, measurePolicy = landscapeQsMediaMeasurePolicy)
} else {
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 f8d0588..8e6cb3f 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
@@ -22,6 +22,7 @@
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
@@ -34,6 +35,7 @@
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ContentScope
+import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.battery.BatteryMeterViewController
@@ -41,6 +43,7 @@
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.rememberViewModel
+import com.android.systemui.qs.composefragment.ui.GridAnchor
import com.android.systemui.qs.panels.ui.compose.EditMode
import com.android.systemui.qs.panels.ui.compose.TileGrid
import com.android.systemui.qs.ui.viewmodel.QuickSettingsContainerViewModel
@@ -79,16 +82,11 @@
}
@Composable
- override fun ContentScope.Content(
- modifier: Modifier,
- ) {
+ override fun ContentScope.Content(modifier: Modifier) {
val viewModel =
rememberViewModel("QuickSettingsShadeOverlay") { contentViewModelFactory.create() }
- OverlayShade(
- modifier = modifier,
- onScrimClicked = viewModel::onScrimClicked,
- ) {
+ OverlayShade(modifier = modifier, onScrimClicked = viewModel::onScrimClicked) {
Column {
ExpandedShadeHeader(
viewModelFactory = viewModel.shadeHeaderViewModelFactory,
@@ -98,40 +96,36 @@
modifier = Modifier.padding(QuickSettingsShade.Dimensions.Padding),
)
- ShadeBody(
- viewModel = viewModel.quickSettingsContainerViewModel,
- )
+ ShadeBody(viewModel = viewModel.quickSettingsContainerViewModel)
}
}
}
}
@Composable
-fun ShadeBody(
- viewModel: QuickSettingsContainerViewModel,
-) {
+fun SceneScope.ShadeBody(viewModel: QuickSettingsContainerViewModel) {
val isEditing by viewModel.editModeViewModel.isEditing.collectAsStateWithLifecycle()
AnimatedContent(
targetState = isEditing,
- transitionSpec = { fadeIn(tween(500)) togetherWith fadeOut(tween(500)) }
+ transitionSpec = { fadeIn(tween(500)) togetherWith fadeOut(tween(500)) },
) { editing ->
if (editing) {
EditMode(
viewModel = viewModel.editModeViewModel,
- modifier = Modifier.fillMaxWidth().padding(QuickSettingsShade.Dimensions.Padding)
+ modifier = Modifier.fillMaxWidth().padding(QuickSettingsShade.Dimensions.Padding),
)
} else {
QuickSettingsLayout(
viewModel = viewModel,
- modifier = Modifier.sysuiResTag("quick_settings_panel")
+ modifier = Modifier.sysuiResTag("quick_settings_panel"),
)
}
}
}
@Composable
-private fun QuickSettingsLayout(
+private fun SceneScope.QuickSettingsLayout(
viewModel: QuickSettingsContainerViewModel,
modifier: Modifier = Modifier,
) {
@@ -143,15 +137,18 @@
BrightnessSliderContainer(
viewModel = viewModel.brightnessSliderViewModel,
modifier =
- Modifier.fillMaxWidth()
- .height(QuickSettingsShade.Dimensions.BrightnessSliderHeight),
+ Modifier.fillMaxWidth().height(QuickSettingsShade.Dimensions.BrightnessSliderHeight),
)
- TileGrid(
- viewModel = viewModel.tileGridViewModel,
- modifier =
- Modifier.fillMaxWidth().heightIn(max = QuickSettingsShade.Dimensions.GridMaxHeight),
- viewModel.editModeViewModel::startEditing,
- )
+ Box {
+ GridAnchor()
+ TileGrid(
+ viewModel = viewModel.tileGridViewModel,
+ modifier =
+ Modifier.fillMaxWidth()
+ .heightIn(max = QuickSettingsShade.Dimensions.GridMaxHeight),
+ viewModel.editModeViewModel::startEditing,
+ )
+ }
}
}
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 6c4edf4..4162891 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
@@ -152,14 +152,17 @@
/** Creates a union of [paddingValues] by using the max padding of each edge. */
@Composable
private fun combinePaddings(vararg paddingValues: PaddingValues): PaddingValues {
- val layoutDirection = LocalLayoutDirection.current
-
- return PaddingValues(
- start = paddingValues.maxOfOrNull { it.calculateStartPadding(layoutDirection) } ?: 0.dp,
- top = paddingValues.maxOfOrNull { it.calculateTopPadding() } ?: 0.dp,
- end = paddingValues.maxOfOrNull { it.calculateEndPadding(layoutDirection) } ?: 0.dp,
- bottom = paddingValues.maxOfOrNull { it.calculateBottomPadding() } ?: 0.dp,
- )
+ return if (paddingValues.isEmpty()) {
+ PaddingValues(0.dp)
+ } else {
+ val layoutDirection = LocalLayoutDirection.current
+ PaddingValues(
+ start = paddingValues.maxOf { it.calculateStartPadding(layoutDirection) },
+ top = paddingValues.maxOf { it.calculateTopPadding() },
+ end = paddingValues.maxOf { it.calculateEndPadding(layoutDirection) },
+ bottom = paddingValues.maxOf { it.calculateBottomPadding() },
+ )
+ }
}
object OverlayShade {
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 d86890b..437a4b3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -17,6 +17,7 @@
package com.android.systemui.biometrics;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
@@ -1437,4 +1438,38 @@
// THEN vibrate is used
verify(mVibrator).performHapticFeedback(any(), eq(UdfpsController.LONG_PRESS));
}
+
+ @Test
+ public void onAcquiredCalbacks() {
+ runWithAllParams(
+ this::ultrasonicCallbackOnAcquired);
+ }
+
+ public void ultrasonicCallbackOnAcquired(TestParams testParams) throws RemoteException{
+ if (testParams.sensorProps.sensorType
+ == FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC) {
+ reset(mUdfpsView);
+
+ UdfpsController.Callback callbackMock = mock(UdfpsController.Callback.class);
+ mUdfpsController.addCallback(callbackMock);
+
+ // GIVEN UDFPS overlay is showing
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD,
+ mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ verify(mFingerprintManager).setUdfpsOverlayController(
+ mUdfpsOverlayControllerCaptor.capture());
+ mUdfpsOverlayControllerCaptor.getValue().onAcquired(0, FINGERPRINT_ACQUIRED_START);
+ mFgExecutor.runAllReady();
+
+ verify(callbackMock).onFingerDown();
+
+ mUdfpsOverlayControllerCaptor.getValue().onAcquired(0, FINGERPRINT_ACQUIRED_GOOD);
+ mFgExecutor.runAllReady();
+
+ verify(callbackMock).onFingerUp();
+ }
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index 492543f..af3ddfc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -310,6 +310,41 @@
.isEqualTo(displayId)
}
+ @Test
+ fun afterSuccessfulAuthentication_focusIsNotRequested() =
+ testScope.runTest {
+ val authResult by collectLastValue(authenticationInteractor.onAuthenticationResult)
+ val textInputFocusRequested by collectLastValue(underTest.isTextFieldFocusRequested)
+ lockDeviceAndOpenPasswordBouncer()
+
+ // remove focus from text field
+ underTest.onTextFieldFocusChanged(false)
+ runCurrent()
+
+ // focus should be requested
+ assertThat(textInputFocusRequested).isTrue()
+
+ // simulate text field getting focus
+ underTest.onTextFieldFocusChanged(true)
+ runCurrent()
+
+ // focus should not be requested anymore
+ assertThat(textInputFocusRequested).isFalse()
+
+ // authenticate successfully.
+ underTest.onPasswordInputChanged("password")
+ underTest.onAuthenticateKeyPressed()
+ runCurrent()
+
+ assertThat(authResult).isTrue()
+
+ // remove focus from text field
+ underTest.onTextFieldFocusChanged(false)
+ runCurrent()
+ // focus should not be requested again
+ assertThat(textInputFocusRequested).isFalse()
+ }
+
private fun TestScope.switchToScene(toScene: SceneKey) {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val bouncerHidden = currentScene == Scenes.Bouncer && toScene != Scenes.Bouncer
@@ -327,10 +362,7 @@
switchToScene(Scenes.Bouncer)
}
- private suspend fun TestScope.setLockout(
- isLockedOut: Boolean,
- failedAttemptCount: Int = 5,
- ) {
+ private suspend fun TestScope.setLockout(isLockedOut: Boolean, failedAttemptCount: Int = 5) {
if (isLockedOut) {
repeat(failedAttemptCount) {
kosmos.fakeAuthenticationRepository.reportAuthenticationAttempt(false)
@@ -350,7 +382,7 @@
kosmos.fakeUserRepository.selectedUser.value =
SelectedUserModel(
userInfo = userInfo,
- selectionStatus = SelectionStatus.SELECTION_COMPLETE
+ selectionStatus = SelectionStatus.SELECTION_COMPLETE,
)
advanceTimeBy(PasswordBouncerViewModel.DELAY_TO_FETCH_IMES)
}
@@ -374,7 +406,7 @@
subtypes =
List(auxiliarySubtypes + nonAuxiliarySubtypes) {
InputMethodModel.Subtype(subtypeId = it, isAuxiliary = it < auxiliarySubtypes)
- }
+ },
)
}
@@ -383,9 +415,6 @@
private const val WRONG_PASSWORD = "Wrong password"
private val USER_INFOS =
- listOf(
- UserInfo(100, "First user", 0),
- UserInfo(101, "Second user", 0),
- )
+ listOf(UserInfo(100, "First user", 0), UserInfo(101, "Second user", 0))
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
index 956c129..2028d288 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
@@ -25,6 +25,8 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.view.MotionEvent;
import android.view.accessibility.AccessibilityManager;
@@ -33,6 +35,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.testing.FakeMetricsLogger;
+import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -201,6 +204,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_NON_TOUCHSCREEN_DEVICES_BYPASS_FALSING)
public void testTrackpadGesture() {
assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isTrue();
when(mFalsingDataProvider.isFromTrackpad()).thenReturn(true);
@@ -208,6 +212,14 @@
}
@Test
+ @EnableFlags(Flags.FLAG_NON_TOUCHSCREEN_DEVICES_BYPASS_FALSING)
+ public void testTrackpadGesture_touchScreenSource_false() {
+ assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isTrue();
+ when(mFalsingDataProvider.isTouchScreenSource()).thenReturn(false);
+ assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isFalse();
+ }
+
+ @Test
public void testAddAndRemoveFalsingBeliefListener() {
verify(mHistoryTracker, never()).addBeliefListener(any());
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/FalsingDataProviderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
index df4b048..5a4799c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
@@ -312,6 +312,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_NON_TOUCHSCREEN_DEVICES_BYPASS_FALSING)
public void test_IsFromTrackpad() {
MotionEvent motionEventOrigin = appendTrackpadDownEvent(0, 0);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index 70529cc..ee65fbd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -21,6 +21,8 @@
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.internal.logging.uiEventLogger
+import com.android.internal.logging.uiEventLoggerFake
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.Flags.FLAG_COMMUNAL_SCENE_KTF_REFACTOR
import com.android.systemui.SysuiTestCase
@@ -28,6 +30,7 @@
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
+import com.android.systemui.communal.shared.log.CommunalUiEvent
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.coroutines.collectLastValue
@@ -35,7 +38,6 @@
import com.android.systemui.dock.fakeDockManager
import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
import com.android.systemui.flags.fakeFeatureFlagsClassic
-import com.android.systemui.flags.featureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
@@ -93,6 +95,7 @@
bgScope = applicationCoroutineScope,
mainDispatcher = testDispatcher,
centralSurfacesOpt = centralSurfacesOptional,
+ uiEventLogger = uiEventLoggerFake,
)
.apply { start() }
@@ -119,7 +122,7 @@
fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.PRIMARY_BOUNCER,
to = KeyguardState.GONE,
- testScope = this
+ testScope = this,
)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
@@ -140,7 +143,7 @@
fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.PRIMARY_BOUNCER,
to = KeyguardState.GONE,
- testScope = this
+ testScope = this,
)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
@@ -161,7 +164,7 @@
fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.PRIMARY_BOUNCER,
to = KeyguardState.GONE,
- testScope = this
+ testScope = this,
)
assertThat(scene).isEqualTo(CommunalScenes.Blank)
@@ -181,7 +184,7 @@
fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.ALTERNATE_BOUNCER,
to = KeyguardState.GONE,
- testScope = this
+ testScope = this,
)
// Scene change will be handled in EditWidgetsActivity not here
assertThat(scene).isEqualTo(CommunalScenes.Communal)
@@ -200,7 +203,7 @@
fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GONE,
to = KeyguardState.LOCKSCREEN,
- testScope = this
+ testScope = this,
)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
}
@@ -220,7 +223,7 @@
fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.OCCLUDED,
- testScope = this
+ testScope = this,
)
assertThat(scene).isEqualTo(CommunalScenes.Blank)
}
@@ -240,7 +243,7 @@
fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.OCCLUDED,
- testScope = this
+ testScope = this,
)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
}
@@ -258,7 +261,7 @@
fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.LOCKSCREEN,
- testScope = this
+ testScope = this,
)
assertThat(scene).isEqualTo(CommunalScenes.Blank)
}
@@ -276,7 +279,7 @@
fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.OFF,
- testScope = this
+ testScope = this,
)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
@@ -298,7 +301,7 @@
fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.OFF,
- testScope = this
+ testScope = this,
)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
advanceTimeBy(CommunalSceneStartable.AWAKE_DEBOUNCE_DELAY / 2)
@@ -307,7 +310,7 @@
fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.OFF,
to = KeyguardState.GLANCEABLE_HUB,
- testScope = this
+ testScope = this,
)
advanceTimeBy(CommunalSceneStartable.AWAKE_DEBOUNCE_DELAY)
@@ -327,7 +330,7 @@
fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.LOCKSCREEN,
- testScope = this
+ testScope = this,
)
updateDocked(true)
@@ -349,7 +352,7 @@
fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.LOCKSCREEN,
- testScope = this
+ testScope = this,
)
updateDocked(true)
@@ -361,7 +364,7 @@
fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.DREAMING,
- testScope = this
+ testScope = this,
)
advanceTimeBy(CommunalSceneStartable.DOCK_DEBOUNCE_DELAY)
assertThat(scene).isEqualTo(CommunalScenes.Blank)
@@ -511,6 +514,9 @@
advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
assertThat(scene).isEqualTo(CommunalScenes.Blank)
+ assertThat(uiEventLoggerFake.logs.first().eventId)
+ .isEqualTo(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT.id)
+ assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
}
}
@@ -526,7 +532,7 @@
fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.DOZING,
to = KeyguardState.GLANCEABLE_HUB,
- testScope = this
+ testScope = this,
)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractorTest.kt
index b3ffc71..d6734e8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractorTest.kt
@@ -19,6 +19,7 @@
import android.app.ActivityManager.RunningTaskInfo
import android.app.usage.UsageEvents
import android.content.pm.UserInfo
+import android.service.dream.dreamManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -28,6 +29,7 @@
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction
import com.android.systemui.plugins.activityStarter
import com.android.systemui.settings.fakeUserTracker
import com.android.systemui.shared.system.taskStackChangeListeners
@@ -48,6 +50,7 @@
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.times
@@ -90,6 +93,27 @@
}
@Test
+ fun testNewTaskStartsWhileOnHub_stopsDream() =
+ testScope.runTest {
+ transition(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GLANCEABLE_HUB)
+ backgroundScope.launch { underTest.waitForActivityStartAndDismissKeyguard() }
+ runCurrent()
+
+ verify(activityStarter, never()).dismissKeyguardThenExecute(any(), anyOrNull(), any())
+ moveTaskToFront()
+
+ argumentCaptor<OnDismissAction>().apply {
+ verify(activityStarter).dismissKeyguardThenExecute(capture(), anyOrNull(), any())
+
+ firstValue.onDismiss()
+ runCurrent()
+
+ // Dream is stopped once keyguard is dismissed.
+ verify(kosmos.dreamManager).stopDream()
+ }
+ }
+
+ @Test
fun testNewTaskStartsAfterExitingHub_doesNotTriggerUnlock() =
testScope.runTest {
transition(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GLANCEABLE_HUB)
@@ -209,7 +233,7 @@
ownerName = "test",
),
),
- testScope
+ testScope,
)
runCurrent()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
index 361e768..8f9e238 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
@@ -17,11 +17,13 @@
package com.android.systemui.keyboard.data.repository
-import android.hardware.input.InputManager
+import android.hardware.input.FakeInputManager
+import android.hardware.input.InputManager.InputDeviceListener
import android.hardware.input.InputManager.KeyboardBacklightListener
import android.hardware.input.KeyboardBacklightState
+import android.hardware.input.fakeInputManager
import android.testing.TestableLooper
-import android.view.InputDevice
+import android.view.InputDevice.SOURCE_KEYBOARD
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -30,10 +32,7 @@
import com.android.systemui.coroutines.collectValues
import com.android.systemui.inputdevice.data.repository.InputDeviceRepository
import com.android.systemui.keyboard.data.model.Keyboard
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.nullable
-import com.android.systemui.util.mockito.whenever
+import com.android.systemui.testKosmos
import com.android.systemui.utils.os.FakeHandler
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineDispatcher
@@ -50,9 +49,10 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Captor
-import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.anyOrNull
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -60,10 +60,9 @@
@RunWith(AndroidJUnit4::class)
class KeyboardRepositoryTest : SysuiTestCase() {
- @Captor
- private lateinit var deviceListenerCaptor: ArgumentCaptor<InputManager.InputDeviceListener>
+ @Captor private lateinit var deviceListenerCaptor: ArgumentCaptor<InputDeviceListener>
@Captor private lateinit var backlightListenerCaptor: ArgumentCaptor<KeyboardBacklightListener>
- @Mock private lateinit var inputManager: InputManager
+ private lateinit var fakeInputManager: FakeInputManager
private lateinit var underTest: KeyboardRepository
private lateinit var dispatcher: CoroutineDispatcher
@@ -73,16 +72,14 @@
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf())
- whenever(inputManager.getInputDevice(any())).then { invocation ->
- val id = invocation.arguments.first()
- INPUT_DEVICES_MAP[id]
- }
+ fakeInputManager = testKosmos().fakeInputManager
dispatcher = StandardTestDispatcher()
testScope = TestScope(dispatcher)
val handler = FakeHandler(TestableLooper.get(this).looper)
- inputDeviceRepo = InputDeviceRepository(handler, testScope.backgroundScope, inputManager)
- underTest = KeyboardRepositoryImpl(dispatcher, inputManager, inputDeviceRepo)
+ inputDeviceRepo =
+ InputDeviceRepository(handler, testScope.backgroundScope, fakeInputManager.inputManager)
+ underTest =
+ KeyboardRepositoryImpl(dispatcher, fakeInputManager.inputManager, inputDeviceRepo)
}
@Test
@@ -95,7 +92,7 @@
@Test
fun emitsConnected_ifKeyboardAlreadyConnectedAtTheStart() =
testScope.runTest {
- whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(PHYSICAL_FULL_KEYBOARD_ID))
+ fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID)
val initialValue = underTest.isAnyKeyboardConnected.first()
assertThat(initialValue).isTrue()
}
@@ -103,74 +100,77 @@
@Test
fun emitsConnected_whenNewPhysicalKeyboardConnects() =
testScope.runTest {
- val deviceListener = captureDeviceListener()
+ captureDeviceListener()
val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected)
- deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID)
+ fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID)
assertThat(isKeyboardConnected).isTrue()
}
@Test
- fun emitsDisconnected_whenDeviceWithIdDoesNotExist() =
+ fun emitsDisconnected_whenDeviceNotFound() =
testScope.runTest {
- val deviceListener = captureDeviceListener()
+ captureDeviceListener()
val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected)
-
- deviceListener.onInputDeviceAdded(NULL_DEVICE_ID)
+ fakeInputManager.addDevice(NULL_DEVICE_ID, SOURCE_KEYBOARD, isNotFound = true)
assertThat(isKeyboardConnected).isFalse()
}
@Test
fun emitsDisconnected_whenKeyboardDisconnects() =
testScope.runTest {
- val deviceListener = captureDeviceListener()
+ captureDeviceListener()
val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected)
- deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID)
+ fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID)
assertThat(isKeyboardConnected).isTrue()
- deviceListener.onInputDeviceRemoved(PHYSICAL_FULL_KEYBOARD_ID)
+ fakeInputManager.removeDevice(PHYSICAL_FULL_KEYBOARD_ID)
assertThat(isKeyboardConnected).isFalse()
}
- private suspend fun captureDeviceListener(): InputManager.InputDeviceListener {
+ private suspend fun captureDeviceListener() {
underTest.isAnyKeyboardConnected.first()
- verify(inputManager).registerInputDeviceListener(deviceListenerCaptor.capture(), nullable())
- return deviceListenerCaptor.value
+ verify(fakeInputManager.inputManager)
+ .registerInputDeviceListener(deviceListenerCaptor.capture(), anyOrNull())
+ fakeInputManager.registerInputDeviceListener(deviceListenerCaptor.value)
}
@Test
fun emitsDisconnected_whenVirtualOrNotFullKeyboardConnects() =
testScope.runTest {
- val deviceListener = captureDeviceListener()
+ captureDeviceListener()
val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected)
- deviceListener.onInputDeviceAdded(PHYSICAL_NOT_FULL_KEYBOARD_ID)
+ fakeInputManager.addPhysicalKeyboard(
+ PHYSICAL_NOT_FULL_KEYBOARD_ID,
+ isFullKeyboard = false
+ )
assertThat(isKeyboardConnected).isFalse()
- deviceListener.onInputDeviceAdded(VIRTUAL_FULL_KEYBOARD_ID)
+ fakeInputManager.addDevice(VIRTUAL_FULL_KEYBOARD_ID, SOURCE_KEYBOARD)
assertThat(isKeyboardConnected).isFalse()
}
@Test
fun emitsDisconnected_whenKeyboardDisconnectsAndWasAlreadyConnectedAtTheStart() =
testScope.runTest {
- val deviceListener = captureDeviceListener()
+ captureDeviceListener()
val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected)
- deviceListener.onInputDeviceRemoved(PHYSICAL_FULL_KEYBOARD_ID)
+ fakeInputManager.removeDevice(PHYSICAL_FULL_KEYBOARD_ID)
assertThat(isKeyboardConnected).isFalse()
}
@Test
fun emitsConnected_whenAnotherDeviceDisconnects() =
testScope.runTest {
- val deviceListener = captureDeviceListener()
+ captureDeviceListener()
val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected)
- deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID)
- deviceListener.onInputDeviceRemoved(VIRTUAL_FULL_KEYBOARD_ID)
+ fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID)
+ fakeInputManager.removeDevice(VIRTUAL_FULL_KEYBOARD_ID)
assertThat(isKeyboardConnected).isTrue()
}
@@ -178,12 +178,12 @@
@Test
fun emitsConnected_whenOnePhysicalKeyboardDisconnectsButAnotherRemainsConnected() =
testScope.runTest {
- val deviceListener = captureDeviceListener()
+ captureDeviceListener()
val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected)
- deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID)
- deviceListener.onInputDeviceAdded(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID)
- deviceListener.onInputDeviceRemoved(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID)
+ fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID)
+ fakeInputManager.addPhysicalKeyboard(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID)
+ fakeInputManager.removeDevice(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID)
assertThat(isKeyboardConnected).isTrue()
}
@@ -195,7 +195,7 @@
// subscribed to and listener is actually registered in inputManager
val backlight by collectLastValueImmediately(underTest.backlight)
- verify(inputManager)
+ verify(fakeInputManager.inputManager)
.registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture())
backlightListenerCaptor.value.onBacklightChanged(current = 1, max = 5)
@@ -217,7 +217,7 @@
fun keyboardBacklightValuesNotPassed_fromBacklightListener_whenNotTriggeredByKeyPress() {
testScope.runTest {
val backlight by collectLastValueImmediately(underTest.backlight)
- verify(inputManager)
+ verify(fakeInputManager.inputManager)
.registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture())
backlightListenerCaptor.value.onBacklightChanged(
@@ -233,7 +233,7 @@
fun passesKeyboardBacklightValues_fromBacklightListener_whenTriggeredByKeyPress() {
testScope.runTest {
val backlight by collectLastValueImmediately(underTest.backlight)
- verify(inputManager)
+ verify(fakeInputManager.inputManager)
.registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture())
backlightListenerCaptor.value.onBacklightChanged(
@@ -248,14 +248,11 @@
@Test
fun passessAllKeyboards_thatWereAlreadyConnectedOnInitialization() {
testScope.runTest {
- whenever(inputManager.inputDeviceIds)
- .thenReturn(
- intArrayOf(
- PHYSICAL_FULL_KEYBOARD_ID,
- ANOTHER_PHYSICAL_FULL_KEYBOARD_ID,
- VIRTUAL_FULL_KEYBOARD_ID // not a physical keyboard - that's why result is 2
- )
- )
+ fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID)
+ fakeInputManager.addPhysicalKeyboard(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID)
+ // not a physical keyboard - that's why result is 2
+ fakeInputManager.addDevice(VIRTUAL_FULL_KEYBOARD_ID, SOURCE_KEYBOARD)
+
val keyboards by collectValues(underTest.newlyConnectedKeyboard)
assertThat(keyboards).hasSize(2)
@@ -265,9 +262,9 @@
@Test
fun passesNewlyConnectedKeyboard() {
testScope.runTest {
- val deviceListener = captureDeviceListener()
+ captureDeviceListener()
- deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID)
+ fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID, VENDOR_ID, PRODUCT_ID)
assertThat(underTest.newlyConnectedKeyboard.first())
.isEqualTo(Keyboard(VENDOR_ID, PRODUCT_ID))
@@ -277,13 +274,12 @@
@Test
fun emitsOnlyNewlyConnectedKeyboards() {
testScope.runTest {
- whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(PHYSICAL_FULL_KEYBOARD_ID))
+ fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID)
underTest.newlyConnectedKeyboard.first()
- verify(inputManager)
- .registerInputDeviceListener(deviceListenerCaptor.capture(), nullable())
- val deviceListener = deviceListenerCaptor.value
- deviceListener.onInputDeviceAdded(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID)
+ captureDeviceListener()
+
+ fakeInputManager.addPhysicalKeyboard(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID)
val keyboards by collectValues(underTest.newlyConnectedKeyboard)
assertThat(keyboards).hasSize(1)
@@ -293,14 +289,11 @@
@Test
fun stillEmitsNewKeyboardEvenIfFlowWasSubscribedAfterOtherFlows() {
testScope.runTest {
- whenever(inputManager.inputDeviceIds)
- .thenReturn(
- intArrayOf(
- PHYSICAL_FULL_KEYBOARD_ID,
- ANOTHER_PHYSICAL_FULL_KEYBOARD_ID,
- VIRTUAL_FULL_KEYBOARD_ID // not a physical keyboard - that's why result is 2
- )
- )
+ fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID)
+ fakeInputManager.addPhysicalKeyboard(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID)
+ // not a physical keyboard - that's why result is 2
+ fakeInputManager.addDevice(VIRTUAL_FULL_KEYBOARD_ID, SOURCE_KEYBOARD)
+
collectLastValueImmediately(underTest.isAnyKeyboardConnected)
// let's pretend second flow is subscribed after some delay
@@ -314,12 +307,12 @@
@Test
fun emitsKeyboardWhenItWasReconnected() {
testScope.runTest {
- val deviceListener = captureDeviceListener()
+ captureDeviceListener()
val keyboards by collectValues(underTest.newlyConnectedKeyboard)
- deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID)
- deviceListener.onInputDeviceRemoved(PHYSICAL_FULL_KEYBOARD_ID)
- deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID)
+ fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID)
+ fakeInputManager.removeDevice(PHYSICAL_FULL_KEYBOARD_ID)
+ fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID)
assertThat(keyboards).hasSize(2)
}
@@ -339,30 +332,13 @@
private companion object {
private const val PHYSICAL_FULL_KEYBOARD_ID = 1
- private const val VIRTUAL_FULL_KEYBOARD_ID = 2
+ private const val VIRTUAL_FULL_KEYBOARD_ID = -2 // Virtual keyboards has id with minus value
private const val PHYSICAL_NOT_FULL_KEYBOARD_ID = 3
private const val ANOTHER_PHYSICAL_FULL_KEYBOARD_ID = 4
- private const val NULL_DEVICE_ID = 5
+ private const val NULL_DEVICE_ID = -5
private const val VENDOR_ID = 99
private const val PRODUCT_ID = 101
-
- private val INPUT_DEVICES_MAP: Map<Int, InputDevice> =
- mapOf(
- PHYSICAL_FULL_KEYBOARD_ID to inputDevice(virtual = false, fullKeyboard = true),
- VIRTUAL_FULL_KEYBOARD_ID to inputDevice(virtual = true, fullKeyboard = true),
- PHYSICAL_NOT_FULL_KEYBOARD_ID to inputDevice(virtual = false, fullKeyboard = false),
- ANOTHER_PHYSICAL_FULL_KEYBOARD_ID to
- inputDevice(virtual = false, fullKeyboard = true)
- )
-
- private fun inputDevice(virtual: Boolean, fullKeyboard: Boolean): InputDevice =
- mock<InputDevice>().also {
- whenever(it.isVirtual).thenReturn(virtual)
- whenever(it.isFullKeyboard).thenReturn(fullKeyboard)
- whenever(it.vendorId).thenReturn(VENDOR_ID)
- whenever(it.productId).thenReturn(PRODUCT_ID)
- }
}
private class TestBacklightState(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
index c18deb1..fac9312 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
@@ -14,22 +14,6 @@
* limitations under the License.
*/
-/*
- * 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.keyguard.domain.interactor
import android.os.PowerManager
@@ -47,7 +31,6 @@
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
import com.android.systemui.communal.shared.model.CommunalScenes
-import com.android.systemui.communal.shared.model.CommunalTransitionKeys
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
@@ -129,7 +112,7 @@
transitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.DOZING,
- testScope
+ testScope,
)
kosmos.fakeKeyguardRepository.setBiometricUnlockState(BiometricUnlockMode.NONE)
reset(transitionRepository)
@@ -145,10 +128,7 @@
// Under default conditions, we should transition to LOCKSCREEN when waking up.
assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.LOCKSCREEN,
- )
+ .startedTransition(from = KeyguardState.DOZING, to = KeyguardState.LOCKSCREEN)
}
@Test
@@ -166,10 +146,7 @@
// If dreaming is possible and communal is available, then we should transition to
// GLANCEABLE_HUB when waking up due to power button press.
assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.GLANCEABLE_HUB,
- )
+ .startedTransition(from = KeyguardState.DOZING, to = KeyguardState.GLANCEABLE_HUB)
}
@Test
@@ -186,8 +163,7 @@
// If dreaming is possible and communal is available, then we should transition to
// GLANCEABLE_HUB when waking up due to power button press.
- verify(kosmos.fakeCommunalSceneRepository)
- .changeScene(CommunalScenes.Communal, CommunalTransitionKeys.Immediately)
+ verify(kosmos.fakeCommunalSceneRepository).snapToScene(CommunalScenes.Communal)
}
@Test
@@ -204,10 +180,7 @@
// If dreaming is NOT possible but communal is available, then we should transition to
// LOCKSCREEN when waking up due to power button press.
assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.LOCKSCREEN,
- )
+ .startedTransition(from = KeyguardState.DOZING, to = KeyguardState.LOCKSCREEN)
}
@Test
@@ -224,10 +197,7 @@
// If dreaming is possible but communal is NOT available, then we should transition to
// LOCKSCREEN when waking up due to power button press.
assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.LOCKSCREEN,
- )
+ .startedTransition(from = KeyguardState.DOZING, to = KeyguardState.LOCKSCREEN)
}
@Test
@@ -245,10 +215,7 @@
// Under default conditions, we should transition to LOCKSCREEN when waking up.
assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.GLANCEABLE_HUB,
- )
+ .startedTransition(from = KeyguardState.DOZING, to = KeyguardState.GLANCEABLE_HUB)
}
@Test
@@ -261,10 +228,7 @@
// Waking with a SHOW_WHEN_LOCKED activity on top should transition to OCCLUDED.
assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.OCCLUDED,
- )
+ .startedTransition(from = KeyguardState.DOZING, to = KeyguardState.OCCLUDED)
}
@Test
@@ -282,10 +246,7 @@
// Waking with a SHOW_WHEN_LOCKED activity on top should transition to OCCLUDED.
assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.OCCLUDED,
- )
+ .startedTransition(from = KeyguardState.DOZING, to = KeyguardState.OCCLUDED)
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
index 41cc953..ba68917 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
@@ -81,6 +81,7 @@
powerInteractor = kosmos.powerInteractor,
alternateBouncerInteractor = kosmos.alternateBouncerInteractor,
shadeInteractor = { kosmos.shadeInteractor },
+ keyguardInteractor = { kosmos.keyguardInteractor },
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaControlInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaControlInteractorTest.kt
index d594f3a..62d0625 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaControlInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaControlInteractorTest.kt
@@ -121,7 +121,7 @@
MediaData(
userId = USER_ID,
instanceId = InstanceId.fakeInstanceId(2),
- artist = ARTIST
+ artist = ARTIST,
)
mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData)
@@ -145,10 +145,17 @@
val clickIntent = mock<PendingIntent> { whenever(it.isActivity).thenReturn(true) }
val expandable = mock<Expandable>()
+ val activityController = mock<ActivityTransitionAnimator.Controller>()
+ whenever(expandable.activityTransitionController(any())).thenReturn(activityController)
underTest.startClickIntent(expandable, clickIntent, SMARTSPACE_CARD_CLICK_EVENT, 1)
- verify(clickIntent).send(any<Bundle>())
+ verify(activityStarter)
+ .startPendingIntentMaybeDismissingKeyguard(
+ eq(clickIntent),
+ eq(null),
+ eq(activityController),
+ )
}
@Test
@@ -174,7 +181,7 @@
mediaData.appUid,
surface = SURFACE,
cardinality = 2,
- rank = 1
+ rank = 1,
)
verify(activityStarter)
.postStartActivityDismissingKeyguard(eq(clickIntent), eq(activityController))
@@ -232,7 +239,7 @@
eq(true),
eq(dialogTransitionController),
eq(null),
- eq(null)
+ eq(null),
)
}
@@ -248,7 +255,7 @@
.createBroadcastDialogWithController(
eq(APP_NAME),
eq(PACKAGE_NAME),
- eq(dialogTransitionController)
+ eq(dialogTransitionController),
)
}
@@ -279,7 +286,7 @@
anyInt(),
anyInt(),
anyInt(),
- anyBoolean()
+ anyBoolean(),
)
verify(listener).onMediaDataRemoved(eq(KEY), eq(true))
}
@@ -307,7 +314,7 @@
mediaData.appUid,
surface = SURFACE,
cardinality = 2,
- rank = 1
+ rank = 1,
)
verify(listener).onMediaDataRemoved(eq(KEY), eq(true))
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt
index 9558e5d..0122028 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt
@@ -24,26 +24,25 @@
import android.media.session.PlaybackState
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.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
-import com.android.systemui.media.controls.domain.pipeline.MediaDataFilterImpl
import com.android.systemui.media.controls.domain.pipeline.mediaDataFilter
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.shared.model.MediaDeviceData
import com.android.systemui.media.controls.util.mediaInstanceId
import com.android.systemui.statusbar.notificationLockscreenUserManager
import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.any
import org.mockito.Mockito
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.whenever
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -52,30 +51,31 @@
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
- private val mediaDataFilter: MediaDataFilterImpl = kosmos.mediaDataFilter
+ private val mediaDataFilter = kosmos.mediaDataFilter
private val notificationLockscreenUserManager = kosmos.notificationLockscreenUserManager
private val packageManager = kosmos.packageManager
private val drawable = context.getDrawable(R.drawable.ic_media_play)
- private val instanceId: InstanceId = kosmos.mediaInstanceId
-
+ private val instanceId = kosmos.mediaInstanceId
private val underTest: MediaControlViewModel = kosmos.mediaControlViewModel
+ @Before
+ fun setUp() {
+ whenever(packageManager.getApplicationIcon(Mockito.anyString())).thenReturn(drawable)
+ whenever(packageManager.getApplicationIcon(any(ApplicationInfo::class.java)))
+ .thenReturn(drawable)
+ whenever(packageManager.getApplicationInfo(eq(PACKAGE_NAME), ArgumentMatchers.anyInt()))
+ .thenReturn(ApplicationInfo())
+ whenever(packageManager.getApplicationLabel(any())).thenReturn(PACKAGE_NAME)
+ whenever(notificationLockscreenUserManager.isCurrentProfile(USER_ID)).thenReturn(true)
+ whenever(notificationLockscreenUserManager.isProfileAvailable(USER_ID)).thenReturn(true)
+ context.setMockPackageManager(packageManager)
+ }
+
@Test
fun addMediaControl_mediaControlViewModelIsLoaded() =
testScope.runTest {
- whenever(packageManager.getApplicationIcon(Mockito.anyString())).thenReturn(drawable)
- whenever(packageManager.getApplicationIcon(any(ApplicationInfo::class.java)))
- .thenReturn(drawable)
- whenever(packageManager.getApplicationInfo(eq(PACKAGE_NAME), ArgumentMatchers.anyInt()))
- .thenReturn(ApplicationInfo())
- whenever(packageManager.getApplicationLabel(any())).thenReturn(PACKAGE_NAME)
- whenever(notificationLockscreenUserManager.isCurrentProfile(USER_ID)).thenReturn(true)
- whenever(notificationLockscreenUserManager.isProfileAvailable(USER_ID)).thenReturn(true)
val playerModel by collectLastValue(underTest.player)
-
- context.setMockPackageManager(packageManager)
-
- val mediaData = initMediaData()
+ val mediaData = initMediaData(ARTIST, TITLE)
mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData)
@@ -88,7 +88,51 @@
assertThat(playerModel?.playTurbulenceNoise).isFalse()
}
- private fun initMediaData(): MediaData {
+ @Test
+ fun emitDuplicateMediaControls_mediaControlIsNotBound() =
+ testScope.runTest {
+ val playerModel by collectLastValue(underTest.player)
+ val mediaData = initMediaData(ARTIST, TITLE)
+
+ mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData)
+
+ assertThat(playerModel).isNotNull()
+ assertThat(playerModel?.titleName).isEqualTo(TITLE)
+ assertThat(playerModel?.artistName).isEqualTo(ARTIST)
+ assertThat(underTest.isNewPlayer(playerModel!!)).isTrue()
+
+ mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData)
+
+ assertThat(playerModel).isNotNull()
+ assertThat(playerModel?.titleName).isEqualTo(TITLE)
+ assertThat(playerModel?.artistName).isEqualTo(ARTIST)
+ assertThat(underTest.isNewPlayer(playerModel!!)).isFalse()
+ }
+
+ @Test
+ fun emitDifferentMediaControls_mediaControlIsBound() =
+ testScope.runTest {
+ val playerModel by collectLastValue(underTest.player)
+ var mediaData = initMediaData(ARTIST, TITLE)
+
+ mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData)
+
+ assertThat(playerModel).isNotNull()
+ assertThat(playerModel?.titleName).isEqualTo(TITLE)
+ assertThat(playerModel?.artistName).isEqualTo(ARTIST)
+ assertThat(underTest.isNewPlayer(playerModel!!)).isTrue()
+
+ mediaData = initMediaData(ARTIST_2, TITLE_2)
+
+ mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData)
+
+ assertThat(playerModel).isNotNull()
+ assertThat(playerModel?.titleName).isEqualTo(TITLE_2)
+ assertThat(playerModel?.artistName).isEqualTo(ARTIST_2)
+ assertThat(underTest.isNewPlayer(playerModel!!)).isTrue()
+ }
+
+ private fun initMediaData(artist: String, title: String): MediaData {
val device = MediaDeviceData(true, null, DEVICE_NAME, null, showBroadcastButton = true)
// Create media session
@@ -111,12 +155,12 @@
return MediaData(
userId = USER_ID,
- artist = ARTIST,
- song = TITLE,
+ artist = artist,
+ song = title,
packageName = PACKAGE,
token = session.sessionToken,
device = device,
- instanceId = instanceId
+ instanceId = instanceId,
)
}
@@ -127,6 +171,8 @@
private const val PACKAGE = "PKG"
private const val ARTIST = "ARTIST"
private const val TITLE = "TITLE"
+ private const val ARTIST_2 = "ARTIST_2"
+ private const val TITLE_2 = "TITLE_2"
private const val DEVICE_NAME = "DEVICE_NAME"
private const val SESSION_KEY = "SESSION_KEY"
private const val SESSION_ARTIST = "SESSION_ARTIST"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/NavigationBarInflaterViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarInflaterViewTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/NavigationBarInflaterViewTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarInflaterViewTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/NavigationBarTransitionsTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTransitionsTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/NavigationBarTransitionsTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTransitionsTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/buttons/KeyButtonViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/buttons/KeyButtonViewTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/buttons/KeyButtonViewTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/buttons/KeyButtonViewTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/buttons/NavigationBarContextTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/buttons/NavigationBarContextTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/buttons/NavigationBarContextTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/buttons/NavigationBarContextTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/buttons/NearestTouchFrameTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/buttons/NearestTouchFrameTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/navigationbar/views/buttons/NearestTouchFrameTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/buttons/NearestTouchFrameTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/FakeNoteTaskBubbleController.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/FakeNoteTaskBubbleController.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/notetask/FakeNoteTaskBubbleController.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/FakeNoteTaskBubbleController.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskBubblesServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskBubblesServiceTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskBubblesServiceTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskBubblesServiceTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskEventLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskEventLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskEventLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskEventLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoResolverTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskInfoResolverTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoResolverTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskInfoResolverTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/NotificationHelperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/people/NotificationHelperTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/people/NotificationHelperTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/people/NotificationHelperTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleBackupFollowUpJobTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/people/PeopleBackupFollowUpJobTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/people/PeopleBackupFollowUpJobTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/people/PeopleBackupFollowUpJobTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTestable.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/people/PeopleProviderTestable.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTestable.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/people/PeopleProviderTestable.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/SharedPreferencesHelperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/people/SharedPreferencesHelperTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/people/SharedPreferencesHelperTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/people/SharedPreferencesHelperTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleBackupHelperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/people/widget/PeopleBackupHelperTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleBackupHelperTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/people/widget/PeopleBackupHelperTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyChipBuilderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/privacy/PrivacyChipBuilderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyChipBuilderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/privacy/PrivacyChipBuilderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/privacy/PrivacyDialogTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/privacy/PrivacyDialogTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/process/condition/SystemProcessConditionTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/process/condition/SystemProcessConditionTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/process/condition/SystemProcessConditionTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/process/condition/SystemProcessConditionTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/LeftRightArrowPressedListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/LeftRightArrowPressedListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/LeftRightArrowPressedListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/LeftRightArrowPressedListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/PagedTileLayoutTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/PagedTileLayoutTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/PagedTileLayoutTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/PagedTileLayoutTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSContainerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSContainerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/QSContainerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSContainerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDisableFlagsLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSDisableFlagsLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/QSDisableFlagsLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSDisableFlagsLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseSceneContainerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseSceneContainerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseSceneContainerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseSceneContainerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelSwitchToParentTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelSwitchToParentTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelSwitchToParentTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelSwitchToParentTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QuickQSPanelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QuickQSPanelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileStateToProtoTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/TileStateToProtoTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/TileStateToProtoTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/TileStateToProtoTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/TouchAnimatorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/TouchAnimatorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/UserSettingObserverTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/UserSettingObserverTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/UserSettingObserverTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/UserSettingObserverTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt
index 7203b61..6f20e70 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt
@@ -78,8 +78,6 @@
Dispatchers.resetMain()
}
- // For now the state changes at 0.5f expansion. This will change once we implement animation
- // (and this test will fail)
@Test
fun qsExpansionValueChanges_correctExpansionState() =
with(kosmos) {
@@ -87,18 +85,27 @@
val expansionState by collectLastValue(underTest.expansionState)
underTest.qsExpansionValue = 0f
- assertThat(expansionState)
- .isEqualTo(QSFragmentComposeViewModel.QSExpansionState.QQS)
+ assertThat(expansionState!!.progress).isEqualTo(0f)
underTest.qsExpansionValue = 0.3f
- assertThat(expansionState)
- .isEqualTo(QSFragmentComposeViewModel.QSExpansionState.QQS)
-
- underTest.qsExpansionValue = 0.7f
- assertThat(expansionState).isEqualTo(QSFragmentComposeViewModel.QSExpansionState.QS)
+ assertThat(expansionState!!.progress).isEqualTo(0.3f)
underTest.qsExpansionValue = 1f
- assertThat(expansionState).isEqualTo(QSFragmentComposeViewModel.QSExpansionState.QS)
+ assertThat(expansionState!!.progress).isEqualTo(1f)
+ }
+ }
+
+ @Test
+ fun qsExpansionValueChanges_clamped() =
+ with(kosmos) {
+ testScope.testWithinLifecycle {
+ val expansionState by collectLastValue(underTest.expansionState)
+
+ underTest.qsExpansionValue = -1f
+ assertThat(expansionState!!.progress).isEqualTo(0f)
+
+ underTest.qsExpansionValue = 2f
+ assertThat(expansionState!!.progress).isEqualTo(1f)
}
}
@@ -110,7 +117,7 @@
testableContext.orCreateTestableResources.addOverride(
R.bool.config_use_large_screen_shade_header,
- true
+ true,
)
fakeConfigurationRepository.onConfigurationChange()
@@ -126,7 +133,7 @@
testableContext.orCreateTestableResources.addOverride(
R.bool.config_use_large_screen_shade_header,
- false
+ false,
)
fakeConfigurationRepository.onConfigurationChange()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterDelegateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/customize/TileAdapterDelegateTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterDelegateTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/customize/TileAdapterDelegateTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/customize/TileAdapterTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/customize/TileAdapterTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/CustomTileTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/CustomTileTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileColorPickerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/TileColorPickerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/external/TileColorPickerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/TileColorPickerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt
new file mode 100644
index 0000000..fa72d74
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt
@@ -0,0 +1,131 @@
+/*
+ * 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.qs.panels.ui.compose.selection
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MutableSelectionStateTest : SysuiTestCase() {
+ private val underTest = MutableSelectionState()
+
+ @Test
+ fun selectTile_isCorrectlySelected() {
+ assertThat(underTest.isSelected(TEST_SPEC)).isFalse()
+
+ underTest.select(TEST_SPEC)
+ assertThat(underTest.isSelected(TEST_SPEC)).isTrue()
+
+ underTest.unSelect()
+ assertThat(underTest.isSelected(TEST_SPEC)).isFalse()
+
+ val newSpec = TileSpec.create("newSpec")
+ underTest.select(TEST_SPEC)
+ underTest.select(newSpec)
+ assertThat(underTest.isSelected(TEST_SPEC)).isFalse()
+ assertThat(underTest.isSelected(newSpec)).isTrue()
+ }
+
+ @Test
+ fun startResize_createsResizingState() {
+ assertThat(underTest.resizingState).isNull()
+
+ // Resizing starts but no tile is selected
+ underTest.onResizingDragStart(TileWidths(0, 0, 1)) {}
+ assertThat(underTest.resizingState).isNull()
+
+ // Resizing starts with a selected tile
+ underTest.select(TEST_SPEC)
+ underTest.onResizingDragStart(TileWidths(0, 0, 1)) {}
+
+ assertThat(underTest.resizingState).isNotNull()
+ }
+
+ @Test
+ fun endResize_clearsResizingState() {
+ val spec = TileSpec.create("testSpec")
+
+ // Resizing starts with a selected tile
+ underTest.select(spec)
+ underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) {}
+ assertThat(underTest.resizingState).isNotNull()
+
+ underTest.onResizingDragEnd()
+ assertThat(underTest.resizingState).isNull()
+ }
+
+ @Test
+ fun unselect_clearsResizingState() {
+ // Resizing starts with a selected tile
+ underTest.select(TEST_SPEC)
+ underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) {}
+ assertThat(underTest.resizingState).isNotNull()
+
+ underTest.unSelect()
+ assertThat(underTest.resizingState).isNull()
+ }
+
+ @Test
+ fun onResizingDrag_updatesResizingState() {
+ // Resizing starts with a selected tile
+ underTest.select(TEST_SPEC)
+ underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) {}
+ assertThat(underTest.resizingState).isNotNull()
+
+ underTest.onResizingDrag(5f)
+ assertThat(underTest.resizingState?.width).isEqualTo(5)
+
+ underTest.onResizingDrag(2f)
+ assertThat(underTest.resizingState?.width).isEqualTo(7)
+
+ underTest.onResizingDrag(-6f)
+ assertThat(underTest.resizingState?.width).isEqualTo(1)
+ }
+
+ @Test
+ fun onResizingDrag_receivesResizeCallback() {
+ var resized = false
+ val onResize: () -> Unit = { resized = !resized }
+
+ // Resizing starts with a selected tile
+ underTest.select(TEST_SPEC)
+ underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10), onResize)
+ assertThat(underTest.resizingState).isNotNull()
+
+ // Drag under the threshold
+ underTest.onResizingDrag(1f)
+ assertThat(resized).isFalse()
+
+ // Drag over the threshold
+ underTest.onResizingDrag(5f)
+ assertThat(resized).isTrue()
+
+ // Drag back under the threshold
+ underTest.onResizingDrag(-5f)
+ assertThat(resized).isFalse()
+ }
+
+ companion object {
+ private val TEST_SPEC = TileSpec.create("testSpec")
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingStateTest.kt
new file mode 100644
index 0000000..6e66783
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingStateTest.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.qs.panels.ui.compose.selection
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ResizingStateTest : SysuiTestCase() {
+
+ @Test
+ fun drag_updatesStateCorrectly() {
+ var resized = false
+ val underTest =
+ ResizingState(TileWidths(base = 0, min = 0, max = 10)) { resized = !resized }
+
+ assertThat(underTest.width).isEqualTo(0)
+
+ underTest.onDrag(2f)
+ assertThat(underTest.width).isEqualTo(2)
+
+ underTest.onDrag(1f)
+ assertThat(underTest.width).isEqualTo(3)
+ assertThat(resized).isTrue()
+
+ underTest.onDrag(-1f)
+ assertThat(underTest.width).isEqualTo(2)
+ assertThat(resized).isFalse()
+ }
+
+ @Test
+ fun dragOutOfBounds_isClampedCorrectly() {
+ val underTest = ResizingState(TileWidths(base = 0, min = 0, max = 10)) {}
+
+ assertThat(underTest.width).isEqualTo(0)
+
+ underTest.onDrag(100f)
+ assertThat(underTest.width).isEqualTo(10)
+
+ underTest.onDrag(-200f)
+ assertThat(underTest.width).isEqualTo(0)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/ResourceIconTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/ResourceIconTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/ResourceIconTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/ResourceIconTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CastTileTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CastTileTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/LocationTileTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/LocationTileTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/NfcTileTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/NfcTileTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/OneHandedModeTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/OneHandedModeTileTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/OneHandedModeTileTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/OneHandedModeTileTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/WifiStateWorkerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/WifiStateWorkerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/WifiStateWorkerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/WifiStateWorkerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recordissue/CustomTraceStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/CustomTraceStateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/recordissue/CustomTraceStateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/CustomTraceStateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recordissue/IssueRecordingServiceCommandHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/IssueRecordingServiceCommandHandlerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/recordissue/IssueRecordingServiceCommandHandlerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/IssueRecordingServiceCommandHandlerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recordissue/IssueRecordingStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/IssueRecordingStateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/recordissue/IssueRecordingStateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/IssueRecordingStateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 40fb769..614d51e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -39,6 +39,7 @@
import android.app.IActivityManager;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.graphics.Rect;
import android.platform.test.flag.junit.FlagsParameterization;
import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
@@ -53,6 +54,7 @@
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.communal.domain.interactor.CommunalInteractor;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.EnableSceneContainer;
import com.android.systemui.flags.SceneContainerFlagParameterizationKt;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.kosmos.KosmosJavaAdapter;
@@ -466,6 +468,32 @@
assertThat(lp.preferredMinDisplayRefreshRate).isEqualTo(0);
}
+ @Test
+ @EnableSceneContainer
+ public void configChanged_boundsUpdate() {
+ when(mNotificationShadeWindowView.getWidth()).thenReturn(1600);
+ when(mNotificationShadeWindowView.getHeight()).thenReturn(800);
+ when(mNotificationShadeWindowView.getVisibility()).thenReturn(View.INVISIBLE);
+ Configuration newConfig = new Configuration();
+ // swap width and height in new bounds to simulate auto-rotate
+ newConfig.windowConfiguration.setBounds(new Rect(0, 0, 800, 1600));
+ mNotificationShadeWindowController.onConfigChanged(newConfig);
+ verify(mWindowManager, atLeastOnce()).updateViewLayout(any(), any());
+ }
+
+ @Test
+ @EnableSceneContainer
+ public void configChanged_boundsDontUpdate() {
+ when(mNotificationShadeWindowView.getWidth()).thenReturn(1600);
+ when(mNotificationShadeWindowView.getHeight()).thenReturn(800);
+ when(mNotificationShadeWindowView.getVisibility()).thenReturn(View.INVISIBLE);
+ Configuration newConfig = new Configuration();
+ // same bounds as view's current bounds
+ newConfig.windowConfiguration.setBounds(new Rect(0, 0, 1600, 800));
+ mNotificationShadeWindowController.onConfigChanged(newConfig);
+ verify(mWindowManager, never()).updateViewLayout(any(), any());
+ }
+
private void setKeyguardShowing() {
mNotificationShadeWindowController.setKeyguardShowing(true);
mNotificationShadeWindowController.setKeyguardGoingAway(false);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
index 3053672..2c8cc1a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
@@ -47,6 +47,7 @@
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.settings.GlobalSettings
import com.android.systemui.util.time.SystemClock
+import com.google.common.truth.Truth.assertThat
import junit.framework.Assert
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
@@ -247,32 +248,35 @@
@Test
@EnableFlags(NotificationThrottleHun.FLAG_NAME)
- fun testShowNotification_reorderNotAllowed_notPulsing_seenInShadeTrue() {
- whenever(mVSProvider.isReorderingAllowed).thenReturn(false)
- val hmp = createHeadsUpManagerPhone()
-
- val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
- val row = mock<ExpandableNotificationRow>()
- whenever(row.showingPulsing()).thenReturn(false)
- notifEntry.row = row
-
- hmp.showNotification(notifEntry)
- Assert.assertTrue(notifEntry.isSeenInShade)
- }
-
- @Test
- @EnableFlags(NotificationThrottleHun.FLAG_NAME)
- fun testShowNotification_reorderAllowed_notPulsing_seenInShadeFalse() {
+ fun testShowNotification_removeWhenReorderingAllowedTrue() {
whenever(mVSProvider.isReorderingAllowed).thenReturn(true)
val hmp = createHeadsUpManagerPhone()
val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
- val row = mock<ExpandableNotificationRow>()
- whenever(row.showingPulsing()).thenReturn(false)
- notifEntry.row = row
-
hmp.showNotification(notifEntry)
- Assert.assertFalse(notifEntry.isSeenInShade)
+ assertThat(hmp.mEntriesToRemoveWhenReorderingAllowed.contains(notifEntry)).isTrue();
+ }
+
+ @Test
+ @EnableFlags(NotificationThrottleHun.FLAG_NAME)
+ fun testShowNotification_reorderNotAllowed_seenInShadeTrue() {
+ whenever(mVSProvider.isReorderingAllowed).thenReturn(false)
+ val hmp = createHeadsUpManagerPhone()
+
+ val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
+ hmp.showNotification(notifEntry)
+ assertThat(notifEntry.isSeenInShade).isTrue();
+ }
+
+ @Test
+ @EnableFlags(NotificationThrottleHun.FLAG_NAME)
+ fun testShowNotification_reorderAllowed_seenInShadeFalse() {
+ whenever(mVSProvider.isReorderingAllowed).thenReturn(true)
+ val hmp = createHeadsUpManagerPhone()
+
+ val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
+ hmp.showNotification(notifEntry)
+ assertThat(notifEntry.isSeenInShade).isFalse();
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
index 21a45ec..9dcbe1b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
@@ -616,6 +616,71 @@
}
@Test
+ fun angleDecreaseAfterCancelAnimation_emitsStartClosingEvent() {
+ setFoldState(folded = true)
+ sendHingeAngleEvent(0)
+ foldUpdates.clear()
+
+ setFoldState(folded = false)
+ rotationListener.value.onRotationChanged(1)
+ sendHingeAngleEvent(180)
+ screenOnStatusProvider.notifyScreenTurningOn()
+ screenOnStatusProvider.notifyScreenTurnedOn()
+
+ // Start folding
+ (180 downTo 60).forEach {
+ sendHingeAngleEvent(it)
+ }
+ // Stopped folding and simulate timeout in this posture
+ simulateTimeout()
+
+ assertThat(foldUpdates)
+ .containsExactly(
+ FOLD_UPDATE_START_OPENING, // unfolded
+ FOLD_UPDATE_FINISH_HALF_OPEN, // force-finished the animation because of rotation
+ FOLD_UPDATE_START_CLOSING, // start closing the device
+ FOLD_UPDATE_FINISH_HALF_OPEN, // finished closing and timed-out in this state
+ )
+
+ }
+
+ @Test
+ fun angleIncreaseDecreaseAfterHalfUnfold_emitsStartClosingEvent() {
+ setFoldState(folded = true)
+ sendHingeAngleEvent(0)
+ foldUpdates.clear()
+
+ setFoldState(folded = false)
+ sendHingeAngleEvent(90)
+ screenOnStatusProvider.notifyScreenTurningOn()
+ screenOnStatusProvider.notifyScreenTurnedOn()
+
+ // Stopped folding and simulate timeout in this posture
+ simulateTimeout()
+
+ // Unfold further
+ (90 until 180).forEach {
+ sendHingeAngleEvent(it)
+ }
+ // Start folding
+ (180 downTo 90).forEach {
+ sendHingeAngleEvent(it)
+ }
+
+ // Stopped folding and simulate timeout in this posture
+ simulateTimeout()
+
+ assertThat(foldUpdates)
+ .containsExactly(
+ FOLD_UPDATE_START_OPENING, // unfolded
+ FOLD_UPDATE_FINISH_HALF_OPEN, // force-finished the animation because of rotation
+ FOLD_UPDATE_START_CLOSING, // start closing the device
+ FOLD_UPDATE_FINISH_HALF_OPEN, // finished closing and timed-out in this state
+ )
+
+ }
+
+ @Test
fun onUnfold_onSmallScreen_emitsStartOpening() {
// the new display state might arrive later, so it shouldn't be used to decide to send the
// start opening event, but only for the closing.
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
index 84f7a51..6c8db91 100644
--- a/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
@@ -28,8 +28,4 @@
<!-- Overload default clock widget parameters -->
<dimen name="widget_big_font_size">100dp</dimen>
<dimen name="widget_label_font_size">18sp</dimen>
-
- <!-- New keyboard shortcut helper -->
- <dimen name="shortcut_helper_width">704dp</dimen>
- <dimen name="shortcut_helper_height">1208dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/layout/activity_keyboard_shortcut_helper.xml b/packages/SystemUI/res/layout/activity_keyboard_shortcut_helper.xml
deleted file mode 100644
index a15532f..0000000
--- a/packages/SystemUI/res/layout/activity_keyboard_shortcut_helper.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/shortcut_helper_sheet_container"
- android:layout_gravity="center_horizontal|bottom"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <FrameLayout
- android:id="@+id/shortcut_helper_sheet"
- style="@style/ShortcutHelperBottomSheet"
- android:layout_width="@dimen/shortcut_helper_width"
- android:layout_height="@dimen/shortcut_helper_height"
- android:orientation="vertical"
- app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
-
- <!-- Drag handle for accessibility -->
- <com.google.android.material.bottomsheet.BottomSheetDragHandleView
- android:id="@+id/drag_handle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <androidx.compose.ui.platform.ComposeView
- android:id="@+id/shortcut_helper_compose_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- </FrameLayout>
-</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 32bcca1..1f4dea9 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -63,10 +63,12 @@
<!-- Container that is wrapped around the views on the start half of the status bar.
Its width will change with the number of visible children and sub-children.
It is useful when we want to know the visible bounds of the content. -->
+ <!-- IMPORTANT: The height of this view *must* be match_parent so that the activity
+ chips don't get cropped when they appear. See b/302160300 and b/366988057. -->
<FrameLayout
android:id="@+id/status_bar_start_side_content"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_gravity="center_vertical|start"
android:clipChildren="false">
@@ -75,6 +77,8 @@
<!-- The alpha of the start side is controlled by PhoneStatusBarTransitions, and the
individual views are controlled by StatusBarManager disable flags DISABLE_CLOCK
and DISABLE_NOTIFICATION_ICONS, respectively -->
+ <!-- IMPORTANT: The height of this view *must* be match_parent so that the activity
+ chips don't get cropped when they appear. See b/302160300 and b/366988057. -->
<LinearLayout
android:id="@+id/status_bar_start_side_except_heads_up"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 900c11e..3fe4214 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Luidsprekers en skerms"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Voorgestelde toestelle"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Stop jou gedeelde sessie om media na ’n ander toestel toe te skuif"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Stop"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Hoe uitsaai werk"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 6a68dd9..77da382 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ድምፅ ማውጫዎች እና ማሳያዎች"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"የተጠቆሙ መሣሪያዎች"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"ሚዲያን ወደ ሌላ መሣሪያ ለማንቀሳቀስ የተጋራውን ክፍለ ጊዜዎን ያቁሙ"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"አቁም"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ማሰራጨት እንዴት እንደሚሠራ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 1273221..64b0f0b 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"%%<xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"مكبّرات الصوت والشاشات"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"الأجهزة المقترَحة"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"أوقِف الجلسة المشتركة لنقل الوسائط إلى جهاز آخر."</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"إيقاف"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"كيفية عمل البث"</string>
@@ -1456,7 +1460,7 @@
<skip />
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"إمكانية الاتصال"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"تسهيل الاستخدام"</string>
- <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"برامج الخدمات"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"خدمات عامة"</string>
<string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"الخصوصية"</string>
<string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"مقدَّمة من التطبيقات"</string>
<string name="qs_edit_mode_category_display" msgid="4749511439121053942">"العرض"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 76431a0..6e3ba23 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"স্পীকাৰ আৰু ডিছপ্লে’"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"পৰামৰ্শ হিচাপে পোৱা ডিভাইচ"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"মিডিয়া অন্য ডিভাইচলৈ স্থানান্তৰ কৰিবলৈ আপোনাৰ শ্বেয়াৰ কৰা ছেশ্বনটো বন্ধ কৰক"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"বন্ধ কৰক"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"সম্প্ৰচাৰ কৰাটোৱে কেনেকৈ কাম কৰে"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"যোগ দিয়ক"</string>
<string name="manage_users" msgid="1823875311934643849">"পৰিচালনা কৰক"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"এই জাননীটোৱে বিভাজিত স্ক্ৰীনলৈ টানি আনি এৰাৰ সুবিধাটো সমৰ্থন নকৰে"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"অৱস্থান সক্ৰিয় হৈ আছে"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ৱাই-ফাই উপলব্ধ নহয়"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"অগ্ৰাধিকাৰ ম’ড"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"এলাৰ্ম ছেট কৰা হ’ল"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"লক স্ক্ৰীন কাষ্টমাইজ কৰক"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"লক স্ক্ৰীন কাষ্টমাইজ কৰিবলৈ আনলক কৰক"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ৱাই-ফাই উপলব্ধ নহয়"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"অৱস্থান সক্ৰিয় হৈ আছে"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"কেমেৰা অৱৰোধ কৰা আছে"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"কেমেৰা আৰু মাইক্ৰ’ফ’ন অৱৰোধ কৰা আছে"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"মাইক্ৰ’ফ’ন অৱৰোধ কৰা আছে"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"টাচ্চপেডৰ নিৰ্দেশ, কীব’ৰ্ডৰ শ্বৰ্টকাট আৰু অধিকৰ বিষয়ে জানক"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"উভতি যাওক নিৰ্দেশ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"গৃহ স্ক্ৰীনলৈ যোৱাৰ নিৰ্দেশ"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"শেহতীয়া এপ্সমূহ চাওক"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"হ’ল"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"উভতি যাওক"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"উভতি যাবলৈ, টাচ্চপেডৰ যিকোনো স্থানত তিনিটা আঙুলি ব্যৱহাৰ কৰি বাওঁ বা সোঁফালে ছোৱাইপ কৰক।\n\nইয়াৰ বাবে আপুনি কীব’ৰ্ড শ্বৰ্টকাট কাৰ্য + ESC ব্যৱহাৰ কৰিবও পাৰে।"</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"যিকোনো সময়তে আপোনাৰ গৃহ স্ক্ৰীনলৈ যাবলৈ, আপোনাৰ স্ক্ৰীনখনৰ একেবাৰে তলৰ পৰা ওপৰলৈ তিনিটা আঙুলিৰে ছোৱাইপ কৰক।"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"সুন্দৰ!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"আপুনি গৃহ স্ক্ৰীনলৈ উভতি যোৱাৰ নিৰ্দেশটো সম্পূৰ্ণ কৰিলে।"</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"শেহতীয়া এপ্সমূহ চাওক"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"আপোনাৰ টাচ্চপেডত তিনিটা আঙুলি ব্যৱহাৰ কৰি ওপৰলৈ ছোৱাইপ কৰি কিছু সময় ধৰি ৰাখক।"</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"বঢ়িয়া!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"আপুনি শেহতীয়া এপ্ চোৱাৰ নিৰ্দেশনাটো সম্পূৰ্ণ কৰিছে।"</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"কাৰ্য কী"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"আপোনাৰ এপ্সমূহ এক্সেছ কৰিবলৈ আপোনাৰ কীব’ৰ্ডৰ কাৰ্য কীটোত টিপক।"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"অভিনন্দন!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"তিনিটা আঙুলি ব্যৱহাৰ কৰি ওপৰলৈ ছোৱাইপ কৰি ধৰি ৰাখক। অধিক নিৰ্দেশ শিকিবলৈ টিপক।"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"আটাইবোৰ এপ্ চাবলৈ আপোনাৰ কীব’ৰ্ড ব্যৱহাৰ কৰক"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"যিকোনো সময়তে কাৰ্য কীটোত টিপক। অধিক নিৰ্দেশ শিকিবলৈ টিপক।"</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"এক্সট্ৰা ডিম এতিয়া উজ্জ্বলতা শ্লাইডাৰৰ অংশ"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"আপুনি এতিয়া উজ্জ্বলতাৰ স্তৰ আৰু অধিক হ্ৰাস কৰি স্ক্ৰীনখন এক্সট্ৰা ডিম কৰিব পাৰে।\n\nযিহেতু এতিয়া এই সুবিধাটো উজ্জ্বলতাৰ শ্লাইডাৰৰ অংশ, এক্সট্ৰা ডিমৰ শ্বৰ্টকাট আঁতৰাই থকা হৈছে।"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"এক্সট্ৰা ডিমৰ শ্বৰ্টকাট আঁতৰাওক"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"এক্সট্ৰা ডিম শ্বৰ্টকাট আঁতৰোৱা হৈছে"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"সংযোগ"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"সাধ্য সুবিধা"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"সহায়ক সঁজুলি"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 7c33d3b..33f1e74 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Dinamiklər & Displeylər"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Təklif olunan Cihazlar"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Medianı başqa cihaza köçürmək üçün paylaşılan sessiyanı dayandırın"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Dayandırın"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Yayım necə işləyir"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"Əlavə edin"</string>
<string name="manage_users" msgid="1823875311934643849">"İstifadəçiləri idarə edin"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Bu bildiriş bölünmüş ekrana sürüşdürməyi dəstəkləmir"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"Məkan aktivdir"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi əlçatan deyil"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritet rejimi"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Siqnal ayarlanıb"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Kilid ekranını fərdiləşdirin"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Kilid ekranını fərdiləşdirmək üçün kiliddən çıxarın"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi əlçatan deyil"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Məkan aktivdir"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera bloklanıb"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera və mikrofon bloklanıb"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon bloklanıb"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Taçped jestləri, klaviatura qısayolları və s. haqqında öyrənin"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Geri jesti"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Əsas ekran jesti"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Son tətbiqlərə baxın"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hazırdır"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Geri qayıdın"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Geri getmək üçün taçpeddə istənilən yerdə üç barmaqla sola və ya sağa çəkin.\n\nBunun üçün Action + ESC klaviatura qısayolundan da istifadə edə bilərsiniz."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"İstənilən vaxt ana ekrana keçmək üçün ekranın aşağısından üç barmağınızla yuxarı çəkin."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Əla!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Əsas ekrana keçid jestini tamamladınız."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Son tətbiqlərə baxın"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Taçpeddə üç barmaq ilə yuxarı çəkib saxlayın."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Əla!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Son tətbiqlərə baxmaq jestini tamamladınız."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Fəaliyyət açarı"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Tətbiqlərə daxil olmaq üçün klaviaturada fəaliyyət açarını basın."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Təbriklər!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Üç barmaq ilə yuxarı çəkib saxlayın. Daha çox jest öyrənmək üçün toxunun."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Bütün tətbiqlərə baxmaq üçün klaviatura istifadə edin"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"İstənilən vaxt fəaliyyət açarını basın. Daha çox jest öyrənmək üçün toxunun."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Əlavə qaraltma artıq parlaqlıq slayderinin bir hissəsidir"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"İndi ekranın yuxarısında parlaqlıq səviyyəsini daha da aşağı salaraq ekranı əlavə qaralda bilərsiniz.\n\nBu funksiya artıq parlaqlıq slayderinin bir hissəsi olduğundan əlavə qaraltma qısayolları silinir."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Əlavə qaraltma qısayollarını silin"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Əlavə qaraltma qısayolları silindi"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Bağlantı"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Xüsusi imkanlar"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Kommunal xidmətlər"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index bc6037a..4c25b4b 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Zvučnici i ekrani"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Predloženi uređaji"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Zaustavite deljenu sesiju da biste premestili medijski sadržaj na drugi uređaj"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Zaustavi"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako funkcioniše emitovanje"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 1f0c127..4a79cee 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Дынамікі і дысплэі"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Прылады, якія падтрымліваюцца"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Каб перамясціць медыяфайлы на іншую прыладу, спыніце абагулены сеанс"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Спыніць"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Як адбываецца трансляцыя"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index affe260..148bc1d 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Високоговорители и екрани"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Предложени устройства"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Спиране на споделената ви сесия с цел преместване на мултимедията на друго устройство"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Спиране"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Как работи предаването"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 497730c..e7fde16 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"স্পিকার ও ডিসপ্লে"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"সাজেস্ট করা ডিভাইস"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"অন্য ডিভাইসে মিডিয়া সরাতে আপনার শেয়ার করা সেশন বন্ধ করুন"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"বন্ধ করুন"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ব্রডকাস্ট কীভাবে কাজ করে"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"যোগ করুন"</string>
<string name="manage_users" msgid="1823875311934643849">"ব্যবহারকারীদের ম্যানেজ করুন"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"\'স্প্লিটস্ক্রিন\' মোডে এই বিজ্ঞপ্তি টেনে আনা যাবে না"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"লোকেশন অ্যাক্টিভ আছে"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ওয়াই-ফাই উপলভ্য নেই"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"প্রায়োরিটি মোড"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"অ্যালার্ম সেট করা হয়েছে"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"লক স্ক্রিন কাস্টমাইজ করুন"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"লক স্ক্রিন কাস্টমাইজ করতে আনলক করুন"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ওয়াই-ফাই উপলভ্য নয়"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"লোকেশন অ্যাক্টিভ আছে"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ক্যামেরার অ্যাক্সেস ব্লক করা আছে"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ক্যামেরা এবং মাইক্রোফোনের অ্যাক্সেস ব্লক করা আছে"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"মাইক্রোফোনের অ্যাক্সেস ব্লক করা আছে"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"টাচপ্যাড জেসচার, কীবোর্ড শর্টকাট এবং আরও অনেক কিছু সম্পর্কে জানুন"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ফিরে যাওয়ার জেসচার"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"হোমপেজে যাওয়ার জেসচার"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"সম্প্রতি ব্যবহার করা হয়েছে এমন অ্যাপ দেখুন"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"হয়ে গেছে"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ফিরে যান"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ফিরে যেতে, টাচপ্যাডে যেকোনও জায়গায় তিনটি আঙুল দিয়ে বাঁদিক বা ডানদিকে সোয়াইপ করুন।\n\nএছাড়া, এটির জন্য আপনি কীবোর্ড শর্টকাট অ্যাকশন + ESC বোতাম প্রেস করতে পারবেন।"</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"যেকোনও সময়ে আপনার হোম স্ক্রিনে যেতে, আপনার স্ক্রিনের একদম নিচের থেকে তিনটি আঙুল দিয়ে উপরের দিকে সোয়াইপ করুন।"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"সাবাস!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"জেসচার ব্যবহার করে কীভাবে হোমে ফিরে যাওয়া যায় সেই সম্পর্কে আপনি জেনেছেন।"</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"সম্প্রতি ব্যবহার করা হয়েছে এমন অ্যাপ দেখুন"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"আপনার টাচপ্যাডে তিনটি আঙুল ব্যবহার করে উপরের দিকে সোয়াইপ করে ধরে রাখুন।"</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"অসাধারণ!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"সম্প্রতি ব্যবহার করা হয়েছে এমন অ্যাপের জেসচার দেখা সম্পূর্ণ করেছেন।"</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"অ্যাকশন কী"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"আপনার অ্যাপ অ্যাক্সেস করতে, কীবোর্ডে অ্যাকশন কী প্রেস করুন"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"অভিনন্দন!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"তিনটি আঙুল ব্যবহার করে উপরের দিকে সোয়াইপ করে ধরে রাখুন। আরও জেসচার সম্পর্কে জানতে ট্যাপ করুন।"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"সব অ্যাপ দেখতে আপনার কীবোর্ড ব্যবহার করুন"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"যেকোনও সময় অ্যাকশন কী প্রেস করুন। আরও জেসচার সম্পর্কে জানতে ট্যাপ করুন।"</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"\'অতিরিক্ত কম ব্রাইটনেস\' ফিচার এখন ব্রাইটনেস স্লাইডারের একটি অংশ"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"আপনি ব্রাইটনেস লেভেল কমিয়েও, স্ক্রিন অতিরিক্ত কম ব্রাইট করতে পারবেন।\n\nএই ফিচার এখন ব্রাইটনেস স্লাইডারের অংশ, তাই \'অতিরিক্ত কম ব্রাইটনেস\' ফিচারের শর্টকাট সরানো হচ্ছে।"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"\'অতিরিক্ত কম ব্রাইটনেস\' ফিচারের শর্টকাট সরান"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"\'অতিরিক্ত কম ব্রাইটনেস\' ফিচারের শর্টকাট সরানো হয়েছে"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"কানেক্টিভিটি"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"অ্যাক্সেসিবিলিটি"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"উপযোগিতা"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 509bf6f..b687ccd 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Zvučnici i ekrani"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Predloženi uređaji"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Zaustavite dijeljenu sesiju da premjestite medij na drugi uređaj"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Zaustavi"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako funkcionira emitiranje"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 8c9c597..5b764a8 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Altaveus i pantalles"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositius suggerits"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Atura la sessió compartida per moure contingut multimèdia a un altre dispositiu"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Atura"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Com funciona l\'emissió"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 6d2328e..f609e2a 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -318,11 +318,11 @@
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vstup"</string>
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Naslouchátka"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Zapínání…"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatické otáčení"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. otáčení"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatické otáčení obrazovky"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Poloha"</string>
- <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Spořič obrazovky"</string>
- <string name="quick_settings_camera_label" msgid="5612076679385269339">"Přístup k fotoaparátu"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Spořič"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Fotoaparát"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Přístup k mikrofonu"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dostupné"</string>
<string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blokováno"</string>
@@ -442,7 +442,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"Vypnuto"</string>
<string name="zen_mode_set_up" msgid="7457957033034460064">"Nastavit"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Spravovat v nastavení"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Žádné aktivní režimy}=1{Režim {mode} je aktivní}few{# režimy jsou aktivní}many{# režimu je aktivních}other{# režimů je aktivních}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Žádné aktivní}=1{Režim {mode} je aktivní}few{# režimy jsou aktivní}many{# režimu je aktivních}other{# režimů je aktivních}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"Nebudou vás rušit zvuky ani vibrace s výjimkou budíků, upozornění, událostí a volajících, které zadáte. Nadále uslyšíte veškerý obsah, který si sami pustíte (např. hudba, videa nebo hry)."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"Nebudou vás rušit zvuky ani vibrace s výjimkou budíků. Nadále uslyšíte veškerý obsah, který si sami pustíte (např. hudba, videa nebo hry)."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"Přizpůsobit"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Reproduktory a displeje"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Navrhovaná zařízení"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Ukončí sdílenou relaci a bude možné přesunout médium do jiného zařízení"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Zastavit"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jak vysílání funguje"</string>
@@ -1234,7 +1238,7 @@
<string name="person_available" msgid="2318599327472755472">"Dostupné"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problém s načtením měřiče baterie"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Klepnutím zobrazíte další informace"</string>
- <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Budík nenastaven"</string>
+ <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Žádný"</string>
<string name="accessibility_bouncer" msgid="5896923685673320070">"zadejte zámek obrazovky"</string>
<string name="accessibility_side_fingerprint_indicator_label" msgid="1673807833352363712">"Dotkněte se snímače otisků prstů. Vypínač je kratší tlačítko na boku telefonu."</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Snímač otisků prstů"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 261cf33..5d429af 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Højttalere og skærme"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Foreslåede enheder"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Stop din delte session for at flytte medier til en anden enhed"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Stop"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Sådan fungerer udsendelser"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index f0e1871..7d5fed9 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -576,8 +576,8 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Jetzt starten"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Keine Benachrichtigungen"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Keine neuen Benachrichtigungen"</string>
- <string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"Verringern von Lautstärke und Vibration bei Benachrichtigungen ist an"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Wenn du in kurzer Zeit zu viele Benachrichtigungen erhältst, wird automatisch für bis zu 2 Minuten die Lautstärke des Geräts verringert und Benachrichtigungen werden reduziert."</string>
+ <string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"„Benachrichtigungen reduzieren” ist aktiviert"</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Wenn du zu viele Benachrichtigungen auf einmal erhältst, wird die Lautstärke automatisch bis zu 2 min lang verringert und Benachrichtigungen werden minimiert."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Deaktivieren"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Für ältere Benachrichtigungen entsperren"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Dieses Gerät wird von deinen Eltern verwaltet"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Lautsprecher & Displays"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Vorgeschlagene Geräte"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Beende die Freigabesitzung zur Übertragung von Medien auf das andere Gerät"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Beenden"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Funktionsweise von Nachrichten an alle"</string>
@@ -1454,18 +1458,11 @@
<skip />
<!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Konnektivität"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Bedienungshilfen"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Dienstprogramme"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Datenschutz"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Von Apps bereitgestellt"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Display"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unbekannt"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 16082cb..ab65136 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -576,7 +576,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Έναρξη τώρα"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Δεν υπάρχουν ειδοποιήσεις"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Δεν υπάρχουν νέες ειδοποιήσεις"</string>
- <string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"Η περίοδος cooldown ειδοποιήσεων είναι ενεργή"</string>
+ <string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"Η ρύθμιση cooldown ειδοποιήσεων είναι ενεργή"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Αυτόματη μείωση έντασης ήχου συσκευής και ειδοποιήσεων για έως 2 λεπτά όταν λαμβάνετε πολλές ειδοποιήσεις ταυτόχρονα."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Απενεργοποίηση"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Ξεκλειδώστε για εμφάνιση παλαιότ. ειδοπ."</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Ηχεία και οθόνες"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Προτεινόμενες συσκευές"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Διακόψτε την κοινόχρηστη περίοδο λειτουργίας για να μεταφέρετε μέσα σε άλλη συσκευή"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Διακοπή"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Πώς λειτουργεί η μετάδοση"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index e0bf0d6..3f1a40c 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers and displays"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested devices"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Stop your shared session to move media to another device"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Stop"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 6f626e9..4ed330e 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers & Displays"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested Devices"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Stop your shared session to move media to another device"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Stop"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index e0bf0d6..3f1a40c 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers and displays"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested devices"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Stop your shared session to move media to another device"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Stop"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index e0bf0d6..3f1a40c 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers and displays"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested devices"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Stop your shared session to move media to another device"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Stop"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 936b64d..fea4ebf 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers & Displays"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Suggested Devices"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Stop your shared session to move media to another device"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Stop"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"How broadcasting works"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 96af732..faf6ff8 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Bocinas y pantallas"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivos sugeridos"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Detiene la sesión de uso compartido para transferir contenido multimedia a otro dispositivo"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Detener"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cómo funciona la transmisión"</string>
@@ -1454,18 +1458,11 @@
<skip />
<!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Conectividad"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accesibilidad"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilidades"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privacidad"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Proporcionado por apps"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Pantalla"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconocido"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index fb8ceec..df9af2a 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Altavoces y pantallas"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivos sugeridos"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Detén tu sesión compartida para transferir el contenido multimedia a otro dispositivo"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Detener"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cómo funciona la emisión"</string>
@@ -1454,18 +1458,11 @@
<skip />
<!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Conectividad"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accesibilidad"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilidades"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privacidad"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Proporcionado por aplicaciones"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Pantalla"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconocido"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 430fcf0..5c2e4db 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Kõlarid ja ekraanid"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Soovitatud seadmed"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Peatage jagatud seanss, et meedia teise seadmesse teisaldada"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Peata"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kuidas ülekandmine toimib?"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"Lisa"</string>
<string name="manage_users" msgid="1823875311934643849">"Kasutajate haldamine"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"See märguanne ei toeta jagatud ekraanikuvale lohistamist."</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"Aktiivne koht"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi pole saadaval"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Režiim Prioriteetne"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm on määratud"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Kohanda lukustuskuva"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Lukustuskuva kohandamiseks avage"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"WiFi pole saadaval"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Aktiivne koht"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kaamera on blokeeritud"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kaamera ja mikrofon on blokeeritud"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon on blokeeritud"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Õppige puuteplaadi liigutusi, klaviatuuri otseteid ja palju muud"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Tagasiliikumisliigutus"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Avakuvale liikumise liigutus"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Hiljutiste rakenduste vaatamine"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Valmis"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Tagasi"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Tagasiliikumiseks pühkige puuteplaadil kolme sõrmega vasakule või paremale.\n\nSamuti saate selle jaoks kasutada klaviatuuri otseteed toiminguklahv + paoklahv."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Mis tahes ajal avakuvale liikumiseks pühkige kolme sõrmega ekraanikuva allosast üles."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Hästi tehtud!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Tegite avakuvale minemise liigutuse."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Hiljutiste rakenduste vaatamine"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Pühkige üles ja hoidke kolme sõrmega puuteplaadil."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Väga hea!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Lõpetasite hiljutiste rakenduste vaatamise liigutuse."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Toiminguklahv"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Rakendustele juurdepääsemiseks vajutage klaviatuuril toiminguklahvi."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Õnnitleme!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Pühkige kolme sõrmega üles ja hoidke sõrmi plaadil. Puudutage žestide kohta lisateabe saamiseks."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Klaviatuuri kasutamine kõigi rakenduste kuvamiseks"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Vajutage soovitud ajal toiminguklahvi. Puudutage žestide kohta lisateabe saamiseks."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Funktsioon „Eriti tume“ on nüüd osa ereduse liugurist"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Nüüd saate muuta ekraani eriti tumedaks, vähendades ereduse taset veelgi rohkem.\n\nKuna see funktsioon kuulub nüüd ereduse liugurisse, eemaldatakse funktsiooni „Eriti tume“ otseteed."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Eemalda funktsiooni „Eriti tume“ otseteed"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Funktsiooni „Eriti tume“ otseteed eemaldati"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Ühenduvus"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Juurdepääsetavus"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utiliidid"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index ef6990c..5221ceb 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -442,7 +442,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"Desaktibatuta"</string>
<string name="zen_mode_set_up" msgid="7457957033034460064">"Konfiguratu"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Kudeatu ezarpenetan"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Ez dago modurik aktibo}=1{{mode} aktibo dago}other{# modu aktibo daude}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Ez dago modurik aktibo}=1{\"{mode}\" aktibo dago}other{# modu aktibo daude}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"Gailuak ez du egingo ez soinurik ez dardararik, baina alarmak, gertaera eta abisuen tonuak, eta aukeratzen dituzun deitzaileen dei-tonuak joko ditu. Bestalde, zuk erreproduzitutako guztia entzungo duzu, besteak beste, musika, bideoak eta jokoak."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"Gailuak ez du egingo ez soinurik ez dardararik, baina alarmak joko ditu. Hala ere, zuk erreproduzitutako guztia entzun ahal izango duzu, besteak beste, musika, bideoak eta jokoak."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"Pertsonalizatu"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"%% <xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Bozgorailuak eta pantailak"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Iradokitako gailuak"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Gelditu partekatutako saioa multimedia-edukia beste gailu batera eramateko"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Gelditu"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Nola funtzionatzen dute iragarpenek?"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"Gehitu"</string>
<string name="manage_users" msgid="1823875311934643849">"Kudeatu erabiltzaileak"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Jakinarazpen hau ezin da arrastatu pantaila zatitura"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"Kokapena aktibatuta dago"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wifi-konexioa ez dago erabilgarri"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Lehentasun modua"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma ezarrita dago"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Pertsonalizatu pantaila blokeatua"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Desblokeatu eta pertsonalizatu pantaila blokeatua"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi-konexioa ez dago erabilgarri"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Kokapena aktibatuta dago"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera blokeatuta dago"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera eta mikrofonoa blokeatuta daude"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonoa blokeatuta dago"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Ikasi ukipen-paneleko keinuak, lasterbideak eta abar"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Atzera egiteko keinua"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Orri nagusira joateko keinua"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ikusi azkenaldiko aplikazioak"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Eginda"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Egin atzera"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Atzera egiteko, pasatu 3 hatz ezkerrera edo eskuinera ukipen-panelean.\n\nEkintza + Ihes lasterbidea ere erabil dezakezu horretarako."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Orri nagusira joateko, pasatu 3 hatz pantailaren behealdetik gora."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Ederki!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Ikasi duzu hasierako pantailara joateko keinua."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ikusi azkenaldiko aplikazioak"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Pasatu 3 hatz gora eta eduki sakatuta ukipen-panelean."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bikain!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Osatu duzu azkenaldiko aplikazioak ikusteko keinua."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Ekintza-tekla"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Aplikazioak atzitzeko, sakatu teklatuko ekintza-tekla."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Zorionak!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Pasatu 3 hatz gora eta eduki sakatuta. Sakatu keinu gehiago ikasteko."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Erabili teklatua aplikazio guztiak ikusteko"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Sakatu ekintza-tekla edonoiz. Sakatu keinu gehiago ikasteko."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Orain, argitasunaren graduatzailean agertzen da Are ilunago"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Orain, pantaila are ilunago jar dezakezu, argitasun-maila are gehiago jaitsita.\n\nOrain eginbide hori argitasunaren graduatzailean agertzen denez, Are ilunago eginbidearen lasterbideak kendu egingo dira."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Kendu Are ilunago eginbidearen lasterbideak"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Kendu dira Are ilunago eginbidearen lasterbideak"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Konexioa"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Erabilerraztasuna"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Zerbitzu-aplikazioak"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 7239b9b7..0696752 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"بلندگوها و نمایشگرها"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"دستگاههای پیشنهادی"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"جلسه مشترک برای انتقال رسانه به دستگاهی دیگر متوقف میشود"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"توقف"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"همهفرتستی چطور کار میکند"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index d0133c7..527d3c9 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Kaiuttimet ja näytöt"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Ehdotetut laitteet"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Lopeta jaettu istunto, jotta voit siirtyä mediaan toisella laitteella"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Lopeta"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Miten lähetys toimii"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 95d7707..f7753ec 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -577,7 +577,7 @@
<string name="empty_shade_text" msgid="8935967157319717412">"Aucune notification"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Aucune nouvelle notification"</string>
<string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"L\'atténuation des notifications est activée"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Le volume de votre appareil est réduit pendant deux minutes si vous recevez trop de notifications."</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Les alertes et le volume de l\'appareil sont réduits automatiquement pendant 2 minutes maximum quand vous recevez trop de notifications à la fois."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Désactiver"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Déverr. pour voir les anciennes notif."</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Cet appareil est géré par ton parent"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Haut-parleurs et écrans"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Appareils suggérés"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Arrêtez votre session partagée pour déplacer des contenus multimédias vers un autre appareil"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Arrêter"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Fonctionnement de la diffusion"</string>
@@ -1454,18 +1458,11 @@
<skip />
<!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connectivité"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibilité"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilitaires"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Confidentialité"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Fournies par des applis"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Affichage"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Inconnu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index ee0f987..8b5214e 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Enceintes et écrans"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Appareils suggérés"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Arrêter votre session partagée pour déplacer des contenus multimédias vers un autre appareil"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Arrêter"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Fonctionnement des annonces"</string>
@@ -1454,18 +1458,11 @@
<skip />
<!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connectivité"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibilité"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilitaires"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Confidentialité"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Fournis par des applis"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Écran"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Inconnu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 9214095..799e577 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -577,7 +577,7 @@
<string name="empty_shade_text" msgid="8935967157319717412">"Non hai notificacións"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Non hai notificacións novas"</string>
<string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"A opción Amainar notificacións está activada"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Cando recibas moitas notificacións, o volume e as alertas reduciranse automaticamente durante ata dous minutos."</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Ao recibir moitas notificacións, o volume e as alertas redúcense automaticamente ata dous minutos."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Desactivar"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloquea para ver máis notificacións"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"O teu pai ou nai xestiona este dispositivo"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Altofalantes e pantallas"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivos suxeridos"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Detén a sesión de uso compartido para mover contido multimedia a outro dispositivo"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Deter"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funcionan as difusións?"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"Engadir"</string>
<string name="manage_users" msgid="1823875311934643849">"Usuarios"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Esta notificación non pode arrastrarse á pantalla dividida"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"Localización activa"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"A wifi non está dispoñible"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo de prioridade"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma definida"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Personalizar pantalla de bloqueo"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Para personalizar a pantalla de bloqueo, primeiro desbloquea o dispositivo"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi non dispoñible"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Localización activa"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"A cámara está bloqueada"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"A cámara e o micrófono están bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"O micrófono está bloqueado"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprende a usar os xestos do panel táctil, atallos de teclado e moito máis"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Xesto para volver"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Xesto para ir ao inicio"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Consultar aplicacións recentes"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Feito"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Volver"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para retroceder, pasa tres dedos cara á esquerda ou cara á dereita en calquera parte do panel táctil.\n\nTamén podes usar o atallo de teclado Acción + Escape."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para ir á pantalla de inicio, pasa tres dedos cara arriba desde a parte inferior da pantalla."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Excelente!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Completaches o xesto de ir ao inicio."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Consultar aplicacións recentes"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Pasa tres dedos cara arriba e mantenos premidos no panel táctil."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Moi ben!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Completaches o titorial do xesto de consultar aplicacións recentes."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de acción"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para acceder ás aplicacións, preme a tecla de acción do teclado."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Parabéns!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Pasa tres dedos cara arriba e mantenos premidos. Toca para obter máis información sobre os xestos."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Usa o teclado para ver todas as aplicacións"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Preme a tecla de acción cando queiras. Toca para obter máis información sobre os xestos."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"A atenuación extra agora está incluída no control desprazable do brillo"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Agora podes aumentar a atenuación da pantalla: só tes que baixar o nivel de brillo aínda máis.\n\nComo agora esta opción está incluída no control desprazable do brillo, quitaranse os atallos de atenuación extra."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Quitar atallos de atenuación extra"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Quitáronse os atallos de atenuación extra"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Conectividade"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accesibilidade"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilidades"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index f4de6ca..a0732d7 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"સ્પીકર અને ડિસ્પ્લે"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"સૂચવેલા ડિવાઇસ"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"મીડિયાને બીજા ડિવાઇસ પર ખસેડવા માટે તમારું શેર કરેલું સત્ર રોકો"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"રોકો"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"બ્રોડકાસ્ટ પ્રક્રિયાની કામ કરવાની રીત"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"ઉમેરો"</string>
<string name="manage_users" msgid="1823875311934643849">"વપરાશકર્તાઓને મેનેજ કરો"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"આ નોટિફિકેશન તેને વિભાજિત સ્ક્રીનમાં ખેંચવાની સુવિધાને સપોર્ટ કરતું નથી"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"લોકેશન સક્રિય"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"વાઇ-ફાઇ ઉપલબ્ધ નથી"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"પ્રાધાન્યતા મોડ"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"અલાર્મ સેટ"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"લૉક સ્ક્રીન કસ્ટમાઇઝ કરો"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"લૉક સ્ક્રીનને કસ્ટમાઇઝ કરવા માટે અનલૉક કરો"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"વાઇ-ફાઇ ઉપલબ્ધ નથી"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"લોકેશન સક્રિય"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"કૅમેરા બ્લૉક કરેલો છે"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"કૅમેરા અને માઇક્રોફોન બ્લૉક કરેલા છે"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"માઇક્રોફોન બ્લૉક કરેલો છે"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ટચપૅડના સંકેતો અને કીબોર્ડના શૉર્ટકટ જેવું બીજું ઘણું જાણો"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"પાછળ જવાનો સંકેત"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"હોમ સ્ક્રીન પર જવાનો સંકેત"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"તાજેતરની ઍપ જુઓ"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"થઈ ગયું"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"પાછા જાઓ"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"પાછા જવા માટે, ટચપૅડ પર ગમે ત્યાં ત્રણ આંગળી વડે ડાબે અથવા જમણે સ્વાઇપ કરો.\n\nઆના માટે તમે કીબોર્ડ શૉર્ટકટ Action + ESCનો ઉપયોગ કરી શકો છો."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"કોઈપણ સમયે તમારી હોમ સ્ક્રીન પર જવા માટે, ત્રણ આંગળી વડે તમારી સ્ક્રીનની સૌથી નીચેની બાજુએથી ઉપરની તરફ સ્વાઇપ કરો."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"સરસ!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"તમે હોમ સ્ક્રીન પર જવાનો સંકેત પૂર્ણ કર્યો છે."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"તાજેતરની ઍપ જુઓ"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"તમારા ટચપૅડ પર ત્રણ આંગળીઓનો ઉપયોગ કરીને ઉપર સ્વાઇપ કરો અને દબાવી રાખો."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ખૂબ સરસ કામ!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"તમે \"તાજેતરની ઍપ જુઓ\" સંકેત પૂર્ણ કર્યો."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ઍક્શન કી"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"તમારી ઍપ ઍક્સેસ કરવા માટે, તમારા કીબોર્ડ પરની ઍક્શન કી દબાવો."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"અભિનંદન!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"ત્રણ આંગળીઓનો ઉપયોગ કરીને ઉપર સ્વાઇપ કરો અને દબાવી રાખો. સંકેતો વિશે વધુ જાણવા માટે ટૅપ કરો."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"બધી ઍપ જોવા માટે તમારા કીબોર્ડનો ઉપયોગ કરો"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"કોઈપણ સમયે ઍક્શન કી દબાવો. સંકેતો વિશે વધુ જાણવા માટે ટૅપ કરો."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"બ્રાઇટનેસ સ્લાઇડર હવે એક્સ્ટ્રા ડિમનો ભાગ છે"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"તમે હવે બ્રાઇટનેસ લેવલને હજી પણ ઘટાડીને સ્ક્રીનને એક્સ્ટ્રા ડિમ બનાવી શકો છો.\n\nઆ સુવિધા હવે બ્રાઇટનેસ સ્લાઇડરનો ભાગ હોવાથી એક્સ્ટ્રા ડિમ શૉર્ટકટને કાઢી નાખવામાં આવી રહ્યાં છે."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"એક્સ્ટ્રા ડિમ શૉર્ટકટ કાઢી નાખો"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"એક્સ્ટ્રા ડિમ શૉર્ટકટ કાઢી નાખ્યા"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"કનેક્ટિવિટી"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ઍક્સેસિબિલિટી"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"યુટિલિટી"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index b9af773..3984f71 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"स्पीकर और डिसप्ले"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"सुझाए गए डिवाइस"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"मीडिया को किसी दूसरे डिवाइस में ट्रांसफ़र करने के लिए, अपने शेयर किए गए सेशन को बंद करें"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"बंद करें"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ब्रॉडकास्ट करने की सुविधा कैसे काम करती है"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"जोड़ें"</string>
<string name="manage_users" msgid="1823875311934643849">"उपयोगकर्ताओं को मैनेज करें"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"इस सूचना को स्प्लिट स्क्रीन मोड में, खींचा और छोड़ा नहीं जा सकता"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"जगह की जानकारी की सेटिंग चालू है"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"वाई-फ़ाई उपलब्ध नहीं है"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"प्राथमिकता मोड"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट किया गया"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"लॉक स्क्रीन को पसंद के मुताबिक बनाएं"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"लॉक स्क्रीन को पसंद के मुताबिक बनाने के लिए अनलॉक करें"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"वाई-फ़ाई उपलब्ध नहीं है"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"जगह की जानकारी की सेटिंग चालू है"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"कैमरे का ऐक्सेस नहीं है"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"कैमरे और माइक्रोफ़ोन का ऐक्सेस नहीं है"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"माइक्रोफ़ोन का ऐक्सेस नहीं है"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"टचपैड पर हाथ के जेस्चर, कीबोर्ड शॉर्टकट वगैरह के बारे में जानें"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"पीछे जाने का जेस्चर"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"होम स्क्रीन पर जाने का जेस्चर"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखें"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"हो गया"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"वापस जाएं"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"वापस जाने के लिए, टचपैड पर कहीं भी तीन उंगलियों से दाईं या बाईं ओर स्वाइप करें.\n\nइसके अलावा, ऐसा करने के लिए Action + ESC बटन का भी इस्तेमाल किया जा सकता है."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"किसी भी समय फ़ोन की होम स्क्रीन पर जाने के लिए, तीन उंगलियों से फ़ोन पर सबसे नीचे से ऊपर की ओर स्वाइप करें."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"बढ़िया!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"आपने जान लिया कि हाथ का जेस्चर इस्तेमाल करके, होम स्क्रीन पर कैसे जाएं."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखें"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"अपने टचपैड पर तीन उंगलियों से ऊपर की ओर स्वाइप करें और फिर होल्ड करें."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"बहुत बढ़िया!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"आपने हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखने के लिए, हाथ के जेस्चर के बारे में जान लिया है."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ऐक्शन बटन"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"अपने ऐप्लिकेशन ऐक्सेस करने के लिए, कीबोर्ड पर ऐक्शन बटन दबाएं."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"बधाई हो!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"तीन उंगलियों से ऊपर की ओर स्वाइप करें और दबाकर रखें. जेस्चर की ज़्यादा जानकारी पाने के लिए टैप करें."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"सभी ऐप्लिकेशन देखने के लिए, कीबोर्ड का इस्तेमाल करें"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"किसी भी समय ऐक्शन बटन दबाएं. हाथ के जेस्चर के बारे में ज़्यादा जानने के लिए टैप करें."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"स्क्रीन की रोशनी को सामान्य लेवल से और कम करने की सुविधा, अब ब्राइटनेस स्लाइडर का हिस्सा है"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"अब ब्राइटनेस लेवल घटाकर, स्क्रीन की रोशनी को सामान्य लेवल से और कम किया जा सकता है.\n\nयह सुविधा ब्राइटनेस स्लाइडर का हिस्सा है. इसलिए, स्क्रीन की रोशनी को सामान्य लेवल से और कम करने की सुविधा वाले शॉर्टकट हटा दिए गए हैं."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"स्क्रीन की रोशनी को सामान्य लेवल से और कम करने की सुविधा वाले शॉर्टकट हटाएं"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"स्क्रीन की रोशनी को सामान्य लेवल से और कम करने की सुविधा वाले शॉर्टकट हटा दिए गए हैं"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"कनेक्टिविटी"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"सुलभता"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"काम की सेवाएं"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index c34c07e..545d1d1 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Zvučnici i zasloni"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Predloženi uređaji"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Zaustavite dijeljenu sesiju da biste premjestili medij na drugi uređaj"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Zaustavi"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako emitiranje funkcionira"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index abc7bd0..e0df7c4 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Hangfalak és kijelzők"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Javasolt eszközök"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Állítsa le a megosztott munkamenetet, ha át szeretné helyezni a médiát egy másik eszközre"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Leállítás"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"A közvetítés működése"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index d25cb52..db3553a 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -577,7 +577,7 @@
<string name="empty_shade_text" msgid="8935967157319717412">"Ծանուցումներ չկան"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Նոր ծանուցումներ չկան"</string>
<string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"Ծանուցումների ձայնի իջեցումը միացված է"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Սարքի և ծանուցումների ձայնն ավտոմատ իջեցվում է մինչև 2 րոպե, երբ շատ ծանուցումներ եք ստանում։"</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Սարքի և ծանուցումների ձայնն ավտոմատ իջեցվում է մինչև 2 րոպեով, երբ շատ ծանուցումներ եք ստանում։"</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Անջատել"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Ապակողպեք՝ տեսնելու հին ծանուցումները"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Այս սարքը կառավարում է ձեր ծնողը"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Բարձրախոսներ և էկրաններ"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Առաջարկվող սարքեր"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Կանգնեցրեք ընդհանուր աշխատաշրջանը՝ մուլտիմեդիա բովանդակությունն այլ սարք տեղափոխելու համար"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Կանգնեցնել"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Ինչպես է աշխատում հեռարձակումը"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index bf1085d..97b0337 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -577,7 +577,7 @@
<string name="empty_shade_text" msgid="8935967157319717412">"Tidak ada notifikasi"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Tidak ada notifikasi baru"</string>
<string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"Pengurangan suara dan getaran notifikasi aktif"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Saat Anda menerima terlalu banyak notifikasi sekaligus, volume dan notifikasi perangkat akan otomatis dikurangi hingga selama 2 menit."</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Saat Anda menerima terlalu banyak notifikasi sekaligus, volume dan getaran perangkat akan otomatis dikurangi hingga selama 2 menit."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Nonaktifkan"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Buka kunci untuk melihat notifikasi lama"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Perangkat ini dikelola oleh orang tuamu"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speaker & Layar"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Perangkat yang Disarankan"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Menghentikan sesi berbagi Anda untuk memindahkan media ke perangkat lain"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Berhenti"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cara kerja siaran"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 987a51d..7df9b2a 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Hátalarar og skjáir"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Tillögur að tækjum"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Stöðvaðu sameiginlega lotu til að flytja efni yfir í annað tæki"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Stöðva"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Svona virkar útsending"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"Bæta við"</string>
<string name="manage_users" msgid="1823875311934643849">"Stjórna notendum"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Þessi tilkynning styður ekki að draga yfir á skiptan skjá."</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"Staðsetning virk"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi ekki tiltækt"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Forgangsstilling"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Vekjari stilltur"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Sérsníða lásskjá"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Taktu úr lás til að sérsníða lásskjá"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi er ekki til staðar"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Staðsetning virk"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Lokað fyrir myndavél"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Lokað fyrir myndavél og hljóðnema"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Lokað fyrir hljóðnema"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Kynntu þér bendingar á snertifleti, flýtilykla og fleira"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Bending til að fara til baka"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Bending til að fara á upphafsskjá"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Sjá nýleg forrit"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Lokið"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Til baka"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Strjúktu til vinstri eða hægri með þremur fingrum hvar sem er á snertifletinum til að fara til baka.\n\nÞú getur einnig notað flýtileiðaraðgerðina + ESC til að gera þetta."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Strjúktu upp frá neðri brún skjásins með þremur fingrum til að opna heimaskjáinn."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Flott!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Þú laukst við að kynna þér bendinguna „heim“."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Sjá nýleg forrit"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Strjúktu upp og haltu þremur fingrum inni á snertifletinum."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Vel gert!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Þú framkvæmdir bendinguna til að sjá nýleg forrit."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Aðgerðalykill"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Ýttu á aðgerðalykilinn á lyklaborðinu til að opna forritin þín."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Til hamingju!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Strjúktu upp og haltu með þremur fingrum. Ýttu til að læra fleiri bendingar."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Notaðu lyklaborðið til að sjá öll forrit"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Ýttu hvenær sem er á aðgerðalykilinn. Ýttu til að læra fleiri bendingar."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Nú er stillingin „Mjög dökkt“ hluti af birtusleðanum"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Nú geturðu gert skjáinn mjög dökkan með því að lækka birtustigið enn frekar.\n\nÞar sem þessi eiginleiki er nú hluti af birtusleðanum verða flýtilyklar fyrir mjög dökka stillingu fjarlægðir."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Fjarlægja flýtilykla fyrir mjög dökka stillingu"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Flýtilyklar fyrir mjög dökka stillingu verða fjarlægðir"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Tengigeta"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Aðgengileiki"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Aukabúnaður"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index e2733b1..f1bbc0a 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -577,7 +577,7 @@
<string name="empty_shade_text" msgid="8935967157319717412">"Nessuna notifica"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Nessuna nuova notifica"</string>
<string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"Attenuazione delle notifiche attivata"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Volume e avvisi sono ridotti automaticamente fino a 2 minuti quando ricevi troppe notifiche insieme."</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Volume e avvisi vengono ridotti automaticamente per un massimo di 2 minuti quando ricevi troppe notifiche contemporaneamente."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Disattiva"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Sblocca per vedere le notifiche meno recenti"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Questo dispositivo è gestito dai tuoi genitori"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speaker e display"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivi consigliati"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Interrompi la sessione condivisa per spostare i contenuti multimediali su un altro dispositivo"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Interrompi"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Come funziona la trasmissione"</string>
@@ -1454,18 +1458,11 @@
<skip />
<!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connettività"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibilità"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilità"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privacy"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Forniti dalle app"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Display"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Sconosciuti"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 2a006a8..2cf4f37 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -440,7 +440,7 @@
<string name="zen_mode_on" msgid="9085304934016242591">"מצב מופעל"</string>
<string name="zen_mode_on_with_details" msgid="7416143430557895497">"פועל • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="zen_mode_off" msgid="1736604456618147306">"מצב מושבת"</string>
- <string name="zen_mode_set_up" msgid="7457957033034460064">"הגדרה"</string>
+ <string name="zen_mode_set_up" msgid="7457957033034460064">"להגדרה"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"שינוי ב\'הגדרות\'"</string>
<string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{אין מצבים פעילים}=1{מצב פעיל אחד ({mode})}one{# מצבים פעילים}two{# מצבים פעילים}other{# מצבים פעילים}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"כדי לא להפריע לך, המכשיר לא ירטוט ולא ישמיע שום צליל, חוץ מהתראות, תזכורות, אירועים ושיחות ממתקשרים מסוימים לבחירתך. המצב הזה לא ישפיע על צלילים שהם חלק מתוכן שבחרת להפעיל, כמו מוזיקה, סרטונים ומשחקים."</string>
@@ -576,7 +576,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"כן, אפשר להתחיל"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"אין התראות"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"אין התראות חדשות"</string>
- <string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"הפוגת ההתראות מופעלת"</string>
+ <string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"הפוגת התראות מופעלת"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"עוצמת הקול וההתראות במכשיר מופחתות אוטומטית למשך עד 2 דקות כשמתקבלות יותר מדי התראות בבת אחת."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"השבתה"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"יש לבטל את הנעילה כדי לראות התראות ישנות"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"רמקולים ומסכים"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"הצעות למכשירים"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"עצירת הסשן המשותף כדי להעביר מדיה למכשיר אחר"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"עצירה"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"הסבר על שידורים"</string>
@@ -1454,18 +1458,11 @@
<skip />
<!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"קישוריות"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"נגישות"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"כלי תחזוקה"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"פרטיות"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"מסופקים על ידי אפליקציות"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"מסך"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"לא ידוע"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 780254f..56491fd 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -577,7 +577,7 @@
<string name="empty_shade_text" msgid="8935967157319717412">"通知はありません"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"新しい通知はありません"</string>
<string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"通知のクールダウンが ON になっています"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"一度に多くの通知が届いたときに、最大 2 分間自動的にデバイスの音量が小さくなりアラートも減ります。"</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"一度に多くの通知が届いた場合に、最長 2 分間自動的にデバイスの音量が小さくなりアラートも減ります。"</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"OFF にする"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"ロック解除して以前の通知を表示"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"このデバイスは保護者によって管理されています"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"スピーカーとディスプレイ"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"デバイスの候補"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"メディアを他のデバイスに移動する共有中のセッションを停止します。"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"停止"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ブロードキャストの仕組み"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index dab2619..d3583fa 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"დინამიკები და დისპლეები"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"შემოთავაზებული მოწყობილობები"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"შეწყვიტეთ გაზიარებული სესია, რათა მულტიმედია სხვა მოწყობილობაზე გადაიტანოთ"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"შეწყვეტა"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ტრანსლირების მუშაობის პრინციპი"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 53ef57e..3916063 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Динамиктер мен дисплейлер"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Ұсынылған құрылғылар"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Мультимедиа файлын басқа құрылғыға жылжыту үшін ортақ сеансты тоқтатыңыз."</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Тоқтату"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Тарату қалай жүзеге асады"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index e2bba53..c72ee71 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ឧបករណ៍បំពងសំឡេង និងផ្ទាំងអេក្រង់"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"ឧបករណ៍ដែលបានណែនាំ"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"បញ្ឈប់វគ្គដែលអ្នកបានចែករំលែក ដើម្បីផ្លាស់ទីមេឌៀទៅឧបករណ៍ផ្សេងទៀត"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"បញ្ឈប់"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"របៀបដែលការផ្សាយដំណើរការ"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"បញ្ចូល"</string>
<string name="manage_users" msgid="1823875311934643849">"គ្រប់គ្រងអ្នកប្រើប្រាស់"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ការជូនដំណឹងនេះមិនអាចឱ្យអូសដើម្បីបំបែកអេក្រង់បានទេ"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"ទីតាំងដែលសកម្ម"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ត្រូវបានបិទ"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"មុខងារអាទិភាព"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"រូបកំណត់ម៉ោងរោទ៍"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"ប្ដូរអេក្រង់ចាក់សោតាមបំណង"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"ដោះសោ ដើម្បីប្ដូរអេក្រង់ចាក់សោតាមបំណង"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"មិនមាន Wi-Fi ទេ"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"ទីតាំងដែលសកម្ម"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"បានទប់ស្កាត់កាមេរ៉ា"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"បានទប់ស្កាត់កាមេរ៉ា និងមីក្រូហ្វូន"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"បានទប់ស្កាត់មីក្រូហ្វូន"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ស្វែងយល់អំពីចលនាផ្ទាំងប៉ះ ផ្លូវកាត់ក្ដារចុច និងអ្វីៗជាច្រើនទៀត"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ចលនាថយក្រោយ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ចលនាទៅទំព័រដើម"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"មើលកម្មវិធីថ្មីៗ"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"រួចរាល់"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ថយក្រោយ"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ដើម្បីថយក្រោយ សូមអូសទៅឆ្វេង ឬស្ដាំដោយប្រើម្រាមដៃបីនៅត្រង់ណាក៏បានលើផ្ទាំងប៉ះ។\n\nអ្នកក៏អាចប្រើសកម្មភាពផ្លូវកាត់ក្ដារចុច + ESC សម្រាប់ការធ្វើបែបនេះ។"</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ដើម្បីចូលទៅអេក្រង់ដើមរបស់អ្នកនៅពេលណាក៏បាន សូមអូសឡើងលើដោយប្រើម្រាមដៃបីពីផ្នែកខាងក្រោមនៃអេក្រង់របស់អ្នក។"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ល្អ!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"អ្នកបានបញ្ចប់ចលនាចូលទៅកាន់ទំព័រដើមហើយ។"</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"មើលកម្មវិធីថ្មីៗ"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"អូសឡើងលើ ហើយសង្កត់ឱ្យជាប់ដោយប្រើម្រាមដៃបីលើផ្ទាំងប៉ះរបស់អ្នក។"</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ធ្វើបានល្អ!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"អ្នកបានបញ្ចប់ការមើលចលនាកម្មវិធីថ្មីៗ។"</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"គ្រាប់ចុចសកម្មភាព"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ដើម្បីចូលប្រើប្រាស់កម្មវិធីរបស់អ្នក សូមចុចគ្រាប់ចុចសកម្មភាពនៅលើក្ដារចុចរបស់អ្នក។"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"សូមអបអរសាទរ!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"អូសឡើងលើ ហើយសង្កត់ឱ្យជាប់ដោយប្រើម្រាមដៃបី។ ចុច ដើម្បីស្វែងយល់បន្ថែមអំពីចលនា។"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"ប្រើក្ដារចុចរបស់អ្នក ដើម្បីមើលកម្មវិធីទាំងអស់"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ចុចគ្រាប់ចុចសកម្មភាពនៅពេលណាក៏បាន។ ចុច ដើម្បីស្វែងយល់បន្ថែមអំពីចលនា។"</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"ឥឡូវនេះ មុខងារងងឹតខ្លាំងក្លាយជាផ្នែកមួយនៃគ្រាប់រំកិលពន្លឺ"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"ឥឡូវនេះ អ្នកអាចធ្វើឱ្យអេក្រង់ងងឹតខ្លាំងបានដោយបន្ថយកម្រិតពន្លឺបន្ថែមទៀត។\n\nដោយសារឥឡូវមុខងារនេះក្លាយជាផ្នែកមួយនៃគ្រាប់រំកិលពន្លឺ ផ្លូវកាត់មុខងារងងឹតខ្លាំងកំពុងត្រូវបានដកចេញ។"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"ដកផ្លូវកាត់មុខងារងងឹតខ្លាំងចេញ"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"ផ្លូវកាត់មុខងារងងឹតខ្លាំងត្រូវបានដកចេញ"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"ការតភ្ជាប់"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ភាពងាយស្រួល"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"កម្មវិធីសម្រួលដំណើរការ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 0b87cbb..f1873c6 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -577,7 +577,7 @@
<string name="empty_shade_text" msgid="8935967157319717412">"ಯಾವುದೇ ಅಧಿಸೂಚನೆಗಳಿಲ್ಲ"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"ಯಾವುದೇ ಹೊಸ ಅಧಿಸೂಚನೆಗಳಿಲ್ಲ"</string>
<string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"ನೋಟಿಫಿಕೇಶನ್ ಕೂಲ್ಡೌನ್ ಆನ್ ಆಗಿದೆ"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"ನೀವು ಏಕಕಾಲದಲ್ಲಿ ತೀರಾ ಹೆಚ್ಚು ನೋಟಿಫಿಕೇಶನ್ಗಳನ್ನು ಪಡೆದಾಗ 2 ನಿಮಿಷಗಳವರೆಗೆ ನಿಮ್ಮ ಸಾಧನದ ವಾಲ್ಯೂಮ್ ಮತ್ತು ಅಲರ್ಟ್ಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಕಡಿಮೆ ಮಾಡಲಾಗುತ್ತದೆ."</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"ನೀವು ಏಕಕಾಲದಲ್ಲಿ ತೀರಾ ಹೆಚ್ಚು ನೋಟಿಫಿಕೇಶನ್ಗಳನ್ನು ಪಡೆದಾಗ 2 ನಿಮಿಷಗಳವರೆಗೆ ನಿಮ್ಮ ಸಾಧನದ ವಾಲ್ಯೂಮ್ ಮತ್ತು ಅಲರ್ಟ್ಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಕಡಿಮೆ ಮಾಡಲಾಗುತ್ತದೆ."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"ಆಫ್ ಮಾಡಿ"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"ಹಳೆಯ ಅಧಿಸೂಚನೆಗಳನ್ನು ನೋಡಲು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ಈ ಸಾಧನವನ್ನು ನಿಮ್ಮ ಪೋಷಕರು ನಿರ್ವಹಿಸುತ್ತಿದ್ದಾರೆ"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ಸ್ಪೀಕರ್ಗಳು ಮತ್ತು ಡಿಸ್ಪ್ಲೇಗಳು"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"ಸೂಚಿಸಿದ ಸಾಧನಗಳು"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"ಮೀಡಿಯಾವನ್ನು ಮತ್ತೊಂದು ಸಾಧನಕ್ಕೆ ಸರಿಸಲು ನಿಮ್ಮ ಹಂಚಿಕೊಂಡ ಸೆಶನ್ ಅನ್ನು ನಿಲ್ಲಿಸಿ"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"ನಿಲ್ಲಿಸಿ"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ಪ್ರಸಾರವು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"ಸೇರಿಸಿ"</string>
<string name="manage_users" msgid="1823875311934643849">"ಬಳಕೆದಾರರನ್ನು ನಿರ್ವಹಿಸಿ"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ಗೆ ಡ್ರ್ಯಾಗ್ ಮಾಡುವುದನ್ನು ಈ ನೋಟಿಫಿಕೇಶನ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"ಸ್ಥಳ ಸಕ್ರಿಯವಾಗಿದೆ"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ವೈ-ಫೈ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ಆದ್ಯತೆ ಮೋಡ್"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ಅಲಾರಾಂ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"ಲಾಕ್ ಸ್ಕ್ರೀನ್ ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"ಲಾಕ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಲು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ವೈ-ಫೈ ಲಭ್ಯವಿಲ್ಲ"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"ಸ್ಥಳ ಸಕ್ರಿಯವಾಗಿದೆ"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ಕ್ಯಾಮರಾವನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ರೊಫೋನ್ ಅನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ಮೈಕ್ರೋಫೋನ್ ಅನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ಟಚ್ಪ್ಯಾಡ್ ಗೆಸ್ಚರ್ಗಳು, ಕೀಬೋರ್ಡ್ಗಳ ಶಾರ್ಟ್ಕಟ್ಗಳು ಮತ್ತು ಹೆಚ್ಚಿನದನ್ನು ತಿಳಿಯಿರಿ"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ಹಿಂಬದಿ ಗೆಸ್ಚರ್"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ಹೋಮ್ ಗೆಸ್ಚರ್"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ಇತ್ತೀಚಿನ ಆ್ಯಪ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ಮುಗಿದಿದೆ"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ಹಿಂತಿರುಗಿ"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ಹಿಂತಿರುಗಲು, ಟಚ್ಪ್ಯಾಡ್ನಲ್ಲಿ ಎಲ್ಲಿಯಾದರೂ ಮೂರು ಬೆರಳುಗಳನ್ನು ಬಳಸಿ ಎಡ ಅಥವಾ ಬಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ.\n\nಇದಕ್ಕಾಗಿ ನೀವು ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್ಕಟ್ Action + ESC ಅನ್ನು ಸಹ ಬಳಸಬಹುದು."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಹೋಗಲು, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಕೆಳಗಿನಿಂದ ಮೂರು ಬೆರಳುಗಳಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ಭೇಷ್!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ನೀವು ಗೋ ಹೋಮ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ಇತ್ತೀಚಿನ ಆ್ಯಪ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"ನಿಮ್ಮ ಟಚ್ಪ್ಯಾಡ್ನಲ್ಲಿ ಮೂರು ಬೆರಳುಗಳನ್ನು ಬಳಸಿ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ಭೇಷ್!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ನೀವು ಇತ್ತೀಚಿನ ಆ್ಯಪ್ಗಳ ಗೆಸ್ಚರ್ ವೀಕ್ಷಣೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ಆ್ಯಕ್ಷನ್ ಕೀ"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ನಿಮ್ಮ ಆ್ಯಪ್ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು, ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ನಲ್ಲಿರುವ ಆ್ಯಕ್ಷನ್ ಕೀಯನ್ನು ಒತ್ತಿರಿ."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"ಅಭಿನಂದನೆಗಳು!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"ಮೂರು ಬೆರಳುಗಳಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಹಾಗೂ ಹೋಲ್ಡ್ ಮಾಡಿ. ಇನ್ನಷ್ಟು ಗೆಸ್ಚರ್ಗಳನ್ನು ತಿಳಿಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"ಎಲ್ಲಾ ಆ್ಯಪ್ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ ಅನ್ನು ಬಳಸಿ"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ಯಾವಾಗ ಬೇಕಾದರೂ ಆ್ಯಕ್ಷನ್ ಕೀಯನ್ನು ಒತ್ತಿರಿ. ಇನ್ನಷ್ಟು ಗೆಸ್ಚರ್ಗಳನ್ನು ತಿಳಿಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"ಇನ್ನಷ್ಟು ಮಬ್ಬು ಈಗ ಬ್ರೈಟ್ನೆಸ್ ಸ್ಲೈಡರ್ನ ಭಾಗವಾಗಿದೆ"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"ನೀವು ಈಗ ಬ್ರೈಟ್ನೆಸ್ನ ಮಟ್ಟವನ್ನು ಇನ್ನಷ್ಟು ಕಡಿಮೆ ಮಾಡುವ ಮೂಲಕ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಇನ್ನಷ್ಟು ಮಬ್ಬುಗೊಳಿಸಬಹುದು.\n\n ಈ ಫೀಚರ್ ಈಗ ಬ್ರೈಟ್ನೆಸ್ ಸ್ಲೈಡರ್ನ ಭಾಗವಾಗಿರುವುದರಿಂದ, ಇನ್ನಷ್ಟು ಮಬ್ಬಾದ ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತಿದೆ."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"ಇನ್ನಷ್ಟು ಮಬ್ಬು ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"ಇನ್ನಷ್ಟು ಮಬ್ಬು ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"ಕನೆಕ್ಟಿವಿಟಿ"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"ಯುಟಿಲಿಟಿಗಳು"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 4f4c5b9..3e851a1 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"스피커 및 디스플레이"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"추천 기기"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"미디어를 다른 기기로 이동하려면 공유 세션을 중지하세요."</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"중지"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"브로드캐스팅 작동 원리"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 023d69e..7148a5b 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -577,7 +577,7 @@
<string name="empty_shade_text" msgid="8935967157319717412">"Билдирме жок"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Жаңы билдирмелер жок"</string>
<string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"Билдирмелердин үнүн басаңдатуу күйүк"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Бир убакта өтө көп билдирмелер келгенде, түзмөктүн үнү жана эскертүүлөрдүн саны 2 мүнөткө азайтылат."</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Өтө көп билдирме келсе, түзмөктүн үнү 2 мүнөткө басаңдап, эскертүүлөрдүн саны азаят."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Өчүрүү"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Билдирмелерди көрүү үчүн кулпуну ачыңыз"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Бул түзмөктү ата-энең башкарат"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Динамиктер жана дисплейлер"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Сунушталган түзмөктөр"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Медиафайлдарды башка түзмөккө жылдыруу үчүн жалпы сеансыңызды токтотуңуз"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Токтотуу"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Кабарлоо кантип иштейт"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 67a11d4..a5b6218 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ລຳໂພງ ແລະ ຈໍສະແດງຜົນ"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"ອຸປະກອນທີ່ແນະນຳ"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"ຢຸດເຊດຊັນທີ່ແບ່ງປັນຂອງທ່ານເພື່ອຍ້າຍມີເດຍໄປຫາອຸປະກອນອື່ນ"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"ຢຸດ"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ການອອກອາກາດເຮັດວຽກແນວໃດ"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"ເພີ່ມ"</string>
<string name="manage_users" msgid="1823875311934643849">"ຈັດການຜູ້ໃຊ້"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ການແຈ້ງເຕືອນນີ້ບໍ່ຮອງຮັບການລາກເພື່ອແບ່ງໜ້າຈໍ"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"ສະຖານທີ່ທີ່ນຳໃຊ້ຢູ່"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ບໍ່ສາມາດໃຊ້ Wi‑Fi ໄດ້"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ໂໝດຄວາມສຳຄັນ"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ຕັ້ງໂມງປຸກແລ້ວ"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"ປັບແຕ່ງໜ້າຈໍລັອກ"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"ປົດລັອກເພື່ອປັບແຕ່ງໜ້າຈໍລັອກ"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ບໍ່ພ້ອມໃຫ້ນຳໃຊ້"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"ສະຖານທີ່ທີ່ນຳໃຊ້ຢູ່"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ກ້ອງຖ່າຍຮູບຖືກບລັອກຢູ່"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ກ້ອງຖ່າຍຮູບ ແລະ ໄມໂຄຣໂຟນຖືກບລັອກຢູ່"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ໄມໂຄຣໂຟນຖືກບລັອກຢູ່"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ສຶກສາທ່າທາງຂອງແຜ່ນສຳຜັດ, ຄີລັດ ແລະ ອື່ນໆ"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ທ່າທາງສຳລັບກັບຄືນ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ທ່າທາງສຳລັບໜ້າຫຼັກ"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ເບິ່ງແອັບຫຼ້າສຸດ"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ແລ້ວໆ"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ກັບຄືນ"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ເພື່ອກັບຄືນ, ໃຫ້ໃຊ້ 3 ນິ້ວປັດຊ້າຍ ຫຼື ຂວາບ່ອນໃດກໍໄດ້ເທິງແຜ່ນສຳຜັດ.\n\nທ່ານຍັງສາມາດໃຊ້ຄຳສັ່ງຄີລັດ + ESC ສຳລັບການດຳເນີນການນີ້ໄດ້ນຳ."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ເພື່ອໄປຫາໜ້າຫຼັກຂອງທ່ານຕອນໃດກໍໄດ້, ໃຫ້ປັດຂຶ້ນດ້ວຍສາມນິ້ວຈາກລຸ່ມສຸດຂອງໜ້າຈໍຂອງທ່ານ."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ດີຫຼາຍ!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ທ່ານໃຊ້ທ່າທາງໄປໜ້າຫຼັກສຳເລັດແລ້ວ."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ເບິ່ງແອັບຫຼ້າສຸດ"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"ໃຊ້ 3 ນິ້ວປັດຂຶ້ນແລ້ວຄ້າງໄວ້ຢູ່ແຜ່ນສໍາຜັດຂອງທ່ານ."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ດີຫຼາຍ!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ທ່ານເບິ່ງທ່າທາງຂອງແອັບຫຼ້າສຸດສຳເລັດແລ້ວ."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ປຸ່ມຄຳສັ່ງ"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ເພື່ອເຂົ້າເຖິງແອັບ, ໃຫ້ກົດປຸ່ມຄຳສັ່ງຢູ່ແປ້ນພິມຂອງທ່ານ."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"ຂໍສະແດງຄວາມຍິນດີ!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"ໃຊ້ 3 ນິ້ວປັດຂຶ້ນ ແລ້ວຄ້າງໄວ້. ແຕະເພື່ອສຶກສາທ່າທາງເພີ່ມເຕີມ."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"ໃຊ້ແປ້ນພິມຂອງທ່ານເພື່ອເບິ່ງແອັບທັງໝົດ"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ກົດປຸ່ມຄຳສັ່ງໄດ້ທຸກເວລາ. ແຕະເພື່ອສຶກສາທ່າທາງເພີ່ມເຕີມ."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"ຕອນນີ້ການຫຼຸດແສງເປັນພິເສດເປັນສ່ວນໜຶ່ງຂອງແຖບເລື່ອນຄວາມສະຫວ່າງແລ້ວ"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"ຕອນນີ້ທ່ານສາມາດເຮັດໃຫ້ໜ້າຈໍມືດລົງເປັນພິເສດໄດ້ໂດຍການຫຼຸດລະດັບຄວາມສະຫວ່າງລົງໃຫ້ຫຼາຍຂຶ້ນ.\n\nເນື່ອງຈາກຕອນນີ້ຄຸນສົມບັດນີ້ເປັນສ່ວນໜຶ່ງຂອງແຖບເລື່ອນຄວາມສະຫວ່າງແລ້ວ, ທາງລັດທີ່ຫຼຸດແສງເປັນພິເສດຈຶ່ງຈະຖືກລຶບອອກ."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"ລຶບທາງລັດທີ່ຫຼຸດແສງເປັນພິເສດອອກ"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"ລຶບທາງລັດທີ່ຫຼຸດແສງເປັນພິເສດອອກແລ້ວ"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"ການເຊື່ອມຕໍ່"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ການຊ່ວຍເຂົ້າເຖິງ"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"ບໍລິການສາທາລະນູປະໂພກ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index c813416..e210a99 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Garsiakalbiai ir ekranai"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Siūlomi įrenginiai"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Sustabdyti bendrinamą seansą norint perkelti mediją į kitą įrenginį"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Sustabdyti"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kaip veikia transliacija"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index a2e4130..625da92 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Skaļruņi un displeji"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Ieteiktās ierīces"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Pārtrauciet savu kopīgoto sesiju, lai pārvietotu multivides saturu uz citu ierīci."</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Pārtraukt"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kā darbojas apraide"</string>
@@ -1454,18 +1458,11 @@
<skip />
<!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Savienojamība"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Pieejamība"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilītprogrammas"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Konfidencialitāte"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Nodrošina lietotnes"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Displejs"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nezināma"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index d4b066e..f1aab84 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Звучници и екрани"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Предложени уреди"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Сопрете ја споделената сесија за да ги преместите аудиовизуелните содржини на друг уред"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Сопри"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Како функционира емитувањето"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"Додај"</string>
<string name="manage_users" msgid="1823875311934643849">"Управувајте со корисниците"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Известувањево не поддржува влечење на поделен екран"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"Локацијата е активна"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi е недостапна"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Приоритетен режим"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Алармот е наместен"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Приспособете го заклучениот екран"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Отклучување за приспособување на заклучениот екран"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi не е достапно"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Локацијата е активна"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камерата е блокирана"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камерата и микрофонот се блокирани"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофонот е блокиран"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Научете движења за допирната подлога, кратенки од тастатурата и друго"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Движење за назад"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Движење за почетен екран"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Прегледајте ги неодамнешните апликации"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"За да се вратите назад, повлечете налево или надесно со три прста каде било на допирната подлога.\n\nЗа ова може да ја користите и кратенката од тастатурата Action + ESC."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"За да одите на вашиот почетен екран кога сакате, повлечете нагоре со три прсти од дното на екранот."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Одлично!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Го научивте движењето за враќање на почетниот екран."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Прегледајте ги неодамнешните апликации"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Повлечете нагоре и задржете со три прста на допирната подлога."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Одлично!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Го завршивте движењето за прегледување на неодамнешните апликации."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Копче за дејство"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"За да пристапите до апликациите, притиснете го копчето за дејство на тастатурата."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Честитки!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Повлечете нагоре и задржете со три прста. Допрете за да научите повеќе движења."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Користете ја тастатурата за да ги видите сите апликации"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Притиснете го копчето за дејство кога сакате. Допрете за да научите повеќе движења."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Отсега „Дополнително затемнување“ е дел од лизгачот за осветленост"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Отсега може да го затемнувате екранот дополнително со намалување на нивото на осветленост уште повеќе.\n\nОтсега функцијава е дел од лизгачот за осветленост, па се отстрануваат кратенките за „Дополнително затемнување“."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Отстрани ги кратенките за „Дополнително затемнување“"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Кратенките за „Дополнително затемнување“ се отстранети"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Поврзливост"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Пристапност"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Услужни програми"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index fbb36b1..42281ce 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"സ്പീക്കറുകളും ഡിസ്പ്ലേകളും"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"നിർദ്ദേശിച്ച ഉപകരണങ്ങൾ"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"മീഡിയയെ മറ്റൊരു ഉപകരണത്തിലേക്ക് നീക്കുന്നതിന് നിങ്ങളുടെ പങ്കിട്ട സെഷൻ നിർത്തുക"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"നിർത്തുക"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ബ്രോഡ്കാസ്റ്റ് എങ്ങനെയാണ് പ്രവർത്തിക്കുന്നത്"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"ചേർക്കുക"</string>
<string name="manage_users" msgid="1823875311934643849">"ഉപയോക്താക്കളെ മാനേജ് ചെയ്യുക"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"സ്പ്ലിറ്റ് സ്ക്രീനിലേക്ക് വലിച്ചിടുന്നതിനെ ഈ അറിയിപ്പ് പിന്തുണയ്ക്കുന്നില്ല"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"ലൊക്കേഷൻ സജീവമാണ്"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"വൈഫൈ ലഭ്യമല്ല"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"മുൻഗണനാ മോഡ്"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"അലാറം സജ്ജീകരിച്ചു"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"ലോക്ക് സ്ക്രീൻ ഇഷ്ടാനുസൃതമാക്കൂ"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"ലോക്ക് സ്ക്രീൻ ഇഷ്ടാനുസൃതമാക്കാൻ അൺലോക്ക് ചെയ്യുക"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"വൈഫൈ ലഭ്യമല്ല"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"ലൊക്കേഷൻ സജീവമാണ്"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ക്യാമറ ബ്ലോക്ക് ചെയ്തിരിക്കുന്നു"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ക്യാമറയും മൈക്രോഫോണും ബ്ലോക്ക് ചെയ്തിരിക്കുന്നു"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"മൈക്രോഫോൺ ബ്ലോക്ക് ചെയ്തിരിക്കുന്നു"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ടച്ച്പാഡ് ജെസ്ച്ചറുകൾ, കീബോർഡ് കുറുക്കുവഴികൾ എന്നിവയും മറ്റും മനസ്സിലാക്കുക"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"\'മടങ്ങുക\' ജെസ്ച്ചർ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ഹോം ജെസ്ച്ചർ"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"അടുത്തിടെയുള്ള ആപ്പുകൾ കാണുക"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"പൂർത്തിയായി"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"മടങ്ങുക"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"തിരികെ പോകാൻ, ടച്ച്പാഡിൽ എവിടെയെങ്കിലും മൂന്ന് വിരലുകൾ ഉപയോഗിച്ച് ഇടത്തേക്കോ വലത്തേക്കോ സ്വൈപ്പ് ചെയ്യുക.\n\nഇതിന് Action + ESC കീബോഡ് കുറുക്കുവഴികളും നിങ്ങൾക്ക് ഉപയോഗിക്കാം."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ഏതുസമയത്തും ഹോം സ്ക്രീനിലേക്ക് പോകാൻ, മൂന്ന് വിരലുകൾ ഉപയോഗിച്ച് സ്ക്രീനിന്റെ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യൂ."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"കൊള്ളാം!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ഹോമിലേക്ക് പോകുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"അടുത്തിടെയുള്ള ആപ്പുകൾ കാണുക"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"നിങ്ങളുടെ ടച്ച്പാഡിൽ മൂന്ന് വിരലുകൾ കൊണ്ട് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്ത് പിടിക്കുക."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"കൊള്ളാം!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"അടുത്തിടെയുള്ള ആപ്പുകൾ കാണുക എന്ന ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Action കീ"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"നിങ്ങളുടെ ആപ്പുകൾ ആക്സസ് ചെയ്യാൻ, നിങ്ങളുടെ കീബോർഡിലെ Action കീ അമർത്തുക."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"അഭിനന്ദനങ്ങൾ!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"മൂന്ന് വിരലുകൾ കൊണ്ട് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്ത് പിടിക്കുക. കൂടുതൽ ജെസ്ച്ചറുകളറിയാൻ ടാപ്പ് ചെയ്യൂ."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"എല്ലാ ആപ്പുകളും കാണാൻ നിങ്ങളുടെ കീബോർഡ് ഉപയോഗിക്കുക"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ഏതുസമയത്തും ആക്ഷൻ കീ അമർത്തുക. കൂടുതൽ ജെസ്ച്ചറുകൾ മനസ്സിലാക്കാൻ ടാപ്പ് ചെയ്യുക."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"കൂടുതൽ ഡിം ചെയ്യൽ, ഇപ്പോൾ തെളിച്ച സ്ലൈഡറിന്റെ ഭാഗമാണ്"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"തെളിച്ചം വളരെ കുറയ്ക്കുന്നതിലൂടെ നിങ്ങൾക്കിപ്പോൾ സ്ക്രീൻ കൂടുതൽ ഡിം ചെയ്യാനാകും.\n\nഈ ഫീച്ചർ ഇപ്പോൾ തെളിച്ച സ്ലൈഡറിന്റെ ഭാഗമായതിനാൽ, കൂടുതൽ ഡിം ചെയ്യൽ കുറുക്കുവഴികൾ നീക്കം ചെയ്യുകയാണ്."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"കൂടുതൽ ഡിം ചെയ്യൽ കുറുക്കുവഴികൾ നീക്കം ചെയ്യുക"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"കൂടുതൽ ഡിം ചെയ്യൽ കുറുക്കുവഴികൾ നീക്കം ചെയ്തു"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"കണക്റ്റിവിറ്റി"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ഉപയോഗസഹായി"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"യൂട്ടിലിറ്റികൾ"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 57948a27..b861020 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Чанга яригч ба дэлгэц"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Санал болгосон төхөөрөмжүүд"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Өөр төхөөрөмж рүү медиа зөөхийн тулд хуваалцсан харилцан үйлдлээ зогсооно уу"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Зогсоох"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Нэвтрүүлэлт хэрхэн ажилладаг вэ?"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"Нэмэх"</string>
<string name="manage_users" msgid="1823875311934643849">"Хэрэглэгчдийг удирдах"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Энэ мэдэгдэл нь дэлгэцийг хуваах горим руу чирэхийг дэмждэггүй"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"Байршил идэвхтэй"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi боломжгүй"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Чухал горим"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Сэрүүлгийг тохируулсан"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Түгжээтэй дэлгэцийг өөрчлөх"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Түгжээтэй дэлгэцийг өөрчлөхийн тулд түгжээг тайлна уу"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi боломжгүй байна"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Байршил идэвхтэй"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камерыг блоклосон"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камер болон микрофоныг блоклосон"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофоныг блоклосон"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Мэдрэгч самбарын зангаа, товчлуурын шууд холбоос болон бусад зүйлийг мэдэж аваарай"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Буцах зангаа"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Үндсэн нүүрний зангаа"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Саяхны аппуудыг харах"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Болсон"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Буцах"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Буцахын тулд мэдрэгч самбар дээр гурван хуруугаар хүссэн газраа зүүн эсвэл баруун тийш шударна уу.\n\nТа мөн үүнийг хийхэд Action + ESC товчлуурын шууд холбоосыг ашиглах боломжтой."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Үндсэн нүүр лүүгээ хүссэн үедээ очихын тулд дэлгэцийнхээ доод талаас гурван хуруугаараа дээш шударна уу."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Янзтай!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Та үндсэн нүүр лүү очих зангааг гүйцэтгэлээ."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Саяхны аппуудыг харах"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Мэдрэгч самбар дээрээ гурван хуруугаа ашиглан дээш шудраад, удаан дарна уу."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Сайн байна!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Та саяхны аппуудыг харах зангааг гүйцэтгэсэн."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Тусгай товчлуур"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Аппууддаа хандахын тулд гар дээр тань байх тусгай товчлуурыг дарна уу."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Баяр хүргэе!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Гурван хуруугаа ашиглан дээш шудраад, удаан дарна уу. Илүү олон зангаа сурахын тулд товшино уу."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Бүх аппыг харахын тулд гараа ашиглах"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Тусгай товчлуурыг хүссэн үедээ дарна уу. Илүү олон зангаа сурахын тулд товшино уу."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Хэт бүүдгэр онцлог одоо гэрэлтүүлгийн гулсуулагчийн нэг хэсэг боллоо"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Та одоо гэрэлтүүлгийн түвшнийг бүр илүү багасгаснаар дэлгэцийг хэт бүүдгэр болгох боломжтой.\n\nЭнэ онцлог нь одоо гэрэлтүүлгийн гулсуулагчийн нэг хэсэг болсон тул Хэт бүүдгэр онцлогийн тохиргоог хасаж байна."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Хэт бүүдгэр онцлогийн товчлолыг хасах"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Хэт бүүдгэр онцлогийн товчлолыг хассан"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Холболт"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Хандалт"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Хэрэгсэл"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 0f3b051..eac5553 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"स्पीकर आणि डिस्प्ले"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"सुचवलेली डिव्हाइस"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"मीडिया दुसऱ्या डिव्हाइसवर शेअर करण्यासाठी तुमचे शेअर केलेले सेशन थांबवा"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"थांबवा"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ब्रॉडकास्टिंग कसे काम करते"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"जोडा"</string>
<string name="manage_users" msgid="1823875311934643849">"वापरकर्ते व्यवस्थापित करा"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ही सूचना स्प्लिट स्क्रीनवर ड्रॅग करण्याला सपोर्ट करत नाही"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"स्थान अॅक्टिव्ह आहे"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"वाय-फाय उपलब्ध नाही"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"प्राधान्य मोड"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट केला"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"कस्टमाइझ लॉक स्क्रीन"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"लॉक स्क्रीन कस्टमाइझ करण्यासाठी अनलॉक करा"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"वाय-फाय उपलब्ध नाही"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"स्थान अॅक्टिव्ह आहे"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"कॅमेरा ब्लॉक केला"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"कॅमेरा आणि मायक्रोफोन ब्लॉक केले आहेत"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"मायक्रोफोन ब्लॉक केला"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"टचपॅड जेश्चर, कीबोर्ड शॉर्टकट आणि आणखी बरेच काही जाणून घ्या"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"मागे जा जेश्चर"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"होम जेश्चर"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"अलीकडील अॅप्स पहा"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"पूर्ण झाले"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"मागे जा"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"मागे जाण्यासाठी, तीन बोटांनी टचपॅडवर कुठेही डावीकडे किंवा उजवीकडे स्वाइप करा.\n\nतुम्ही यासाठी Action + ESC हा कीबोर्ड शॉर्टकटदेखील वापरू शकता."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"कधीही तुमच्या होम स्क्रीनवर जाण्यासाठी, तीन बोटांनी तुमच्या स्क्रीनच्या तळापासून स्वाइप करा."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"छान!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"तुम्ही गो होम जेश्चर पूर्ण केले आहे."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"अलीकडील अॅप्स पहा"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"तुमच्या टचपॅडवर तीन बोटांनी वरती आणि खाली स्वाइप करा."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"उत्तम कामगिरी!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"तुम्ही अलीकडील ॲप्स पाहण्याचे जेश्चर पूर्ण केले आहे."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"अॅक्शन की"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"तुमची ॲप्स अॅक्सेस करण्यासाठी, तुमच्या कीबोर्डवरील अॅक्शन की प्रेस करा."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"अभिनंदन!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"तीन बोटांनी वरती आणि खाली स्वाइप करा. आणखी जेश्चर जाणून घेण्यासाठी टॅप करा."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"सर्व ॲप्स पाहण्यासाठी तुमचा कीबोर्ड वापरा"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"अॅक्शन की कधीही प्रेस करा. आणखी जेश्चर जाणून घेण्यासाठी टॅप करा."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"आणखी डिम हे आता ब्राइटनेस स्लायडरमध्ये समाविष्ट आहे"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"तुम्ही आता ब्राइटनेसची पातळी आणखी कमी करून स्क्रीनला आणखी डिम करू शकता.\n\nहे वैशिष्ट्य आता ब्राइटनेसच्या स्लायडरमध्ये समाविष्ट असल्याने, आणखी डिम शॉर्टकट काढून टाकले जात आहेत."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"आणखी डिम शॉर्टकट काढून टाका"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"आणखी डिम शॉर्टकट काढून टाकले आहेत"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"कनेक्टिव्हिटी"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"अॅक्सेसिबिलिटी"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"उपयुक्तता"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 38434c5..ab7ae77 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Pembesar Suara & Paparan"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Peranti yang Dicadangkan"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Hentikan sesi dikongsi anda untuk mengalihkan media kepada peranti yang lain"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Berhenti"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cara siaran berfungsi"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"Tambah"</string>
<string name="manage_users" msgid="1823875311934643849">"Urus pengguna"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Pemberitahuan ini tidak menyokong penyeretan kepada skrin pisah"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"Lokasi aktif"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi dimatikan"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mod keutamaan"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Penggera ditetapkan"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Sesuaikan skrin kunci"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Buka kunci untuk menyesuaikan skrin kunci"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi tidak tersedia"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Lokasi aktif"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera disekat"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dan mikrofon disekat"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon disekat"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Ketahui gerak isyarat pad sentuh, pintasan papan kekunci dan pelbagai lagi"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gerak isyarat kembali"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gerak isyarat pergi ke laman utama"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Lihat apl terbaharu"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Selesai"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kembali"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Untuk kembali, leret ke kiri atau ke kanan menggunakan tiga jari di mana-mana sahaja pada pad sentuh.\n\nAnda juga boleh menggunakan pintasan papan kekunci Action + ESC untuk kembali."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Untuk mengakses skrin utama anda pada bila-bila masa, leret ke atas menggunakan tiga jari daripada bahagian bawah skrin anda."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bagus!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Anda telah melengkapkan gerak isyarat akses laman utama."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Lihat apl terbaharu"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Leret ke atas dan tahan menggunakan tiga jari pada pad sentuh anda."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Syabas!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Anda melengkapkan gerak isyarat lihat apl terbaharu."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Kekunci tindakan"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Untuk mengakses semua apl anda, tekan kekunci tindakan pada papan kekunci anda."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Tahniah!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Leret ke atas, tahan dengan tiga jari. Ketik untuk mengetahui lebih lanjut tentang gerak isyarat."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Gunakan papan kekunci anda untuk melihat semua apl"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Tekan kekunci tindakan pada bila-bila masa. Ketik dan ketahui lebih lanjut tentang gerak isyarat."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Kini ciri amat malap merupakan sebahagian daripada peluncur kecerahan"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Kini anda boleh menjadikan skrin amat malap dengan merendahkan lebih lagi tahap kecerahan.\n\nMemandangkan ciri ini kini merupakan sebahagian daripada peluncur kecerahan, pintasan amat malap dialih keluar."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Alih keluar pintasan amat malap"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Pintasan amat malap dialih keluar"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Kesambungan"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Kebolehaksesan"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utiliti"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index ef4b04d..89449f8 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -442,7 +442,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"ပိတ်"</string>
<string name="zen_mode_set_up" msgid="7457957033034460064">"စနစ်ထည့်သွင်းရန်"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"ဆက်တင်များတွင် စီမံရန်"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{အသုံးပြုနေသော မုဒ်မရှိပါ}=1{{mode} ကို အသုံးပြုနေသည်}other{မုဒ် # ခုကို အသုံးပြုနေသည်}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{သုံးနေသော မုဒ်မရှိပါ}=1{{mode} ကို သုံးနေသည်}other{မုဒ် # ခု သုံးနေသည်}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"နှိုးစက်သံ၊ သတိပေးချက်အသံများ၊ ပွဲစဉ်သတိပေးသံများနှင့် သင်ခွင့်ပြုထားသူများထံမှ ဖုန်းခေါ်မှုများမှလွဲ၍ အခြားအသံများနှင့် တုန်ခါမှုများက သင့်ကို အနှောင့်အယှက်ပြုမည် မဟုတ်ပါ။ သို့သော်လည်း သီချင်း၊ ဗီဒီယိုနှင့် ဂိမ်းများအပါအဝင် သင်ကရွေးချယ်ဖွင့်ထားသည့် အရာတိုင်း၏ အသံကိုမူ ကြားနေရဆဲဖြစ်ပါလိမ့်မည်။"</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"နှိုးစက်သံမှလွဲ၍ အခြားအသံများနှင့် တုန်ခါမှုများက သင့်ကို အနှောင့်အယှက်ပြုမည် မဟုတ်ပါ။ သို့သော်လည်း သီချင်း၊ ဗီဒီယိုနှင့် ဂိမ်းများအပါအဝင် သင်ကရွေးချယ်ဖွင့်ထားသည့် အရာတိုင်း၏ အသံကိုမူ ကြားနေရဆဲဖြစ်ပါလိမ့်မည်။"</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"စိတ်ကြိုက် ပြုလုပ်ရန်"</string>
@@ -577,7 +577,7 @@
<string name="empty_shade_text" msgid="8935967157319717412">"အကြောင်းကြားချက် မရှိပါ"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"အကြောင်းကြားချက်သစ် မရှိပါ"</string>
<string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"အကြောင်းကြားချက် သတိပေးမှု လျှော့ချခြင်း ဖွင့်ထားသည်"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"အကြောင်းကြားချက်များစွာ တစ်ပြိုင်နက်ရပါက သင့်စက်၏ အသံအတိုးအကျယ်နှင့် သတိပေးချက်ကို ၂ မိနစ်ကြာသည်အထိ အလိုအလျောက်လျှော့ချသည်။"</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"အကြောင်းကြားချက်များစွာ တစ်ပြိုင်နက်ရပါက သင့်စက်၏ အသံနှင့် သတိပေးချက်ကို ၂ မိနစ်ကြာသည်အထိ အလိုအလျောက်လျှော့ချသည်။"</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"ပိတ်ရန်"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"အကြောင်းကြားချက်ဟောင်းကြည့်ရန် လော့ခ်ဖွင့်ပါ"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ဤစက်ပစ္စည်းကို သင့်မိဘက စီမံခန့်ခွဲသည်"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"စပီကာနှင့် ဖန်သားပြင်များ"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"အကြံပြုထားသော စက်ပစ္စည်းများ"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"အခြားစက်သို့ မီဒီယာရွှေ့ပြောင်းရန် သင်၏မျှဝေထားသောစက်ရှင်ကို ရပ်ပါ"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"ရပ်ရန်"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ထုတ်လွှင့်မှုဆောင်ရွက်ပုံ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 55535dd..c9656f2 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Høyttalere og skjermer"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Foreslåtte enheter"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Stopp den delte økten for å flytte medieinnholdet til en annen enhet"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Stopp"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Slik fungerer kringkasting"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 68cca07..16dd82f 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -442,7 +442,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"अफ छ"</string>
<string name="zen_mode_set_up" msgid="7457957033034460064">"सेटअप गर्नुहोस्"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"सेटिङमा गई व्यवस्थापन गर्नुहोस्"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{कुनै पनि मोड सक्रिय छैन}=1{{mode} सक्रिय छ}other{# वटा मोड सक्रिय छन्}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{कुनै पनि सक्रिय छैन}=1{{mode} सक्रिय छ}other{# मोड सक्रिय छन्}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"तपाईंलाई अलार्म, रिमाइन्डर, कार्यक्रम र तपाईंले निर्दिष्ट गर्नुभएका कलरहरू बाहेकका ध्वनि र कम्पनहरूले बाधा पुऱ्याउने छैनन्। तपाईंले अझै सङ्गीत, भिडियो र खेलहरू लगायत आफूले प्ले गर्न छनौट गरेका जुनसुकै कुरा सुन्न सक्नुहुनेछ।"</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"तपाईंलाई अलार्महरू बाहेकका ध्वनि र कम्पनहरूले बाधा पुऱ्याउने छैनन्। तपाईंले अझै सङ्गीत, भिडियो र खेलहरू लगायत आफूले प्ले गर्न छनौट गरेका जुनसुकै कुरा सुन्न सक्नुहुनेछ।"</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">" कस्टम बनाउनुहोस्"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"स्पिकर तथा डिस्प्लेहरू"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"सिफारिस गरिएका डिभाइसहरू"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"मिडिया अर्को डिभाइसमा सार्नका लागि तपाईंले सेयर गरेको सत्र अन्त्य गर्नुहोस्"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"रोक्नुहोस्"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"प्रसारण गर्ने सुविधाले कसरी काम गर्छ"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"हाल्नुहोस्"</string>
<string name="manage_users" msgid="1823875311934643849">"प्रयोगकर्ताहरूको व्यवस्थापन गर्नुहोस्"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"यो सूचना ड्र्याग गरेर स्प्लिट स्क्रिनमा लैजान मिल्दैन"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"लोकेसन सक्रिय छ"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi उपलब्ध छैन"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"प्राथमिकता मोड"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट गरिएको छ"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"लक स्क्रिन कस्टमाइज गर्नुहोस्"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"लक स्क्रिन कस्टमाइज गर्न अनलक गर्नुहोस्"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi उपलब्ध छैन"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"लोकेसन सक्रिय छ"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"क्यामेरा ब्लक गरिएको छ"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"क्यामेरा र माइक्रोफोन ब्लक गरिएको छ"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"माइक्रोफोन ब्लक गरिएको छ"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"टचप्याड जेस्चर, किबोर्डका सर्टकट र अन्य कुरा प्रयोग गर्न सिक्नुहोस्"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ब्याक जेस्चर"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"होम जेस्चर"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"हालसालै चलाइएका एपहरू हेर्नुहोस्"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"सम्पन्न भयो"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"पछाडि जानुहोस्"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"पछाडि जान तीन वटा औँलाले टचप्याडमा कतै छोएर बायाँ वा दायाँतिर स्वाइप गर्नुहोस्।\n\nतपाईं यसका लागि किबोर्डको सर्टकट \"Action + ESC\" पनि प्रयोग गर्न सक्नुहुन्छ।"</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"जुनसुकै बेला आफ्नो होम स्क्रिनमा जान स्क्रिनको फेदबाट तीन वटा औँलाले माथितिर स्वाइप गर्नुहोस्।"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"राम्रो!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"तपाईंले \"होम स्क्रिनमा जानुहोस्\" नामक जेस्चर प्रयोग गर्ने तरिका सिक्नुभयो।"</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"हालसालै चलाइएका एपहरू हेर्नुहोस्"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"तीन वटा औँला प्रयोग गरी टचप्याडमा माथितिर स्वाइप गर्नुहोस् र होल्ड गर्नुहोस्।"</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"अद्भुत!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"तपाईंले हालसालै चलाइएका एपहरू हेर्ने जेस्चर पूरा गर्नुभएको छ।"</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"एक्सन की"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"आफ्ना एपहरू एक्सेस गर्न आफ्नो किबोर्डमा भएको एक्सन की थिच्नुहोस्।"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"बधाई छ!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"तिन वटा औँला प्रयोग गरी माथितिर स्वाइप गर्नुहोस् र होल्ड गर्नुहोस्। थप जेस्चर प्रयोग गर्ने तरिका सिक्न ट्याप गर्नुहोस्।"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"सबै एपहरू हेर्न आफ्नो किबोर्ड प्रयोग गर्नुहोस्"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"जुनसुकै बेला एक्सन की थिच्नुहोस्। थप जेस्चर प्रयोग गर्ने तरिका सिक्न ट्याप गर्नुहोस्।"</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"\"अझै मधुरो\" सुविधा अब चमक घटबढ गर्ने स्लाइडरमा समावेश गरिएको छ"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"तपाईं चमकको स्तर अझ बढी घटाएर स्क्रिन अझै मधुरो बनाउन सक्नुहुन्छ।\n\n\"अझै मधुरो\" सुविधा अब चमक घटबढ गर्ने स्लाइडरमा समावेश गरिएकाले यो सुविधाका सर्टकर्टहरू हटाइँदै छन्।"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"\"अझै मधुरो\" सुविधाका सर्टकटहरू हटाउनुहोस्"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"\"अझै मधुरो\" सुविधाका सर्टकटहरू हटाइएका छन्"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"कनेक्टिभिटी"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"सर्वसुलभता"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"युटिलिटी"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 2e9fc8e..b10c203 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -577,7 +577,7 @@
<string name="empty_shade_text" msgid="8935967157319717412">"Geen meldingen"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Geen nieuwe meldingen"</string>
<string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"Afkoelperiode van meldingen staat aan"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Je apparaatvolume en meldingen worden automatisch maximaal 2 minuten beperkt als je te veel meldingen tegelijk krijgt."</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Als je te veel meldingen tegelijk krijgt, worden het volume op je apparaat en meldingen automatisch maximaal 2 minuten beperkt."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Uitzetten"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Ontgrendel om oudere meldingen te zien"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Dit apparaat wordt beheerd door je ouder"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Speakers en schermen"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Voorgestelde apparaten"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Stop je gedeelde sessie om media naar een ander apparaat te verplaatsen"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Stoppen"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Hoe uitzenden werkt"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 7eced26..64b2b7c 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ସ୍ପିକର ଏବଂ ଡିସପ୍ଲେଗୁଡ଼ିକ"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"ପ୍ରସ୍ତାବିତ ଡିଭାଇସଗୁଡ଼ିକ"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"ଅନ୍ୟ ଏକ ଡିଭାଇସକୁ ମିଡିଆ ମୁଭ କରିବା ପାଇଁ ଆପଣଙ୍କ ସେୟାର କରାଯାଇଥିବା ସେସନକୁ ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ବ୍ରଡକାଷ୍ଟିଂ କିପରି କାମ କରେ"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"ଯୋଗ କରନ୍ତୁ"</string>
<string name="manage_users" msgid="1823875311934643849">"ୟୁଜରମାନଙ୍କୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ଏହି ବିଜ୍ଞପ୍ତି ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନକୁ ଟାଣିବାକୁ ସମର୍ଥନ କରେ ନାହିଁ"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"ଲୋକେସନ ସକ୍ରିୟ ଅଛି"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ୱାଇ-ଫାଇ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ପ୍ରାଥମିକତା ମୋଡ"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ଆଲାରାମ ସେଟ"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"ଲକ ସ୍କ୍ରିନକୁ କଷ୍ଟମାଇଜ କରନ୍ତୁ"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"ଲକ ସ୍କ୍ରିନକୁ କଷ୍ଟମାଇଜ କରିବା ପାଇଁ ଅନଲକ କରନ୍ତୁ"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ୱାଇ-ଫାଇ ଉପଲବ୍ଧ ନାହିଁ"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"ଲୋକେସନ ସକ୍ରିୟ ଅଛି"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"କେମେରାକୁ ବ୍ଲକ କରାଯାଇଛି"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"କେମେରା ଏବଂ ମାଇକ୍ରୋଫୋନକୁ ବ୍ଲକ କରାଯାଇଛି"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ମାଇକ୍ରୋଫୋନକୁ ବ୍ଲକ କରାଯାଇଛି"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ଟଚପେଡ ଜେଶ୍ଚର, କୀବୋର୍ଡ ସର୍ଟକଟ ଏବଂ ଆହୁରି ଅନେକ କିଛି ବିଷୟରେ ଜାଣନ୍ତୁ"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ବେକ ଜେଶ୍ଚର"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ହୋମ ଜେଶ୍ଚର"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ବର୍ତ୍ତମାନର ଆପ୍ସ ଭ୍ୟୁ କରନ୍ତୁ"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ହୋଇଗଲା"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ପଛକୁ ଫେରନ୍ତୁ"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ପଛକୁ ଫେରିବା ପାଇଁ ଯେ କୌଣସି ସ୍ଥାନରେ ତିନି ଆଙ୍ଗୁଠି ବ୍ୟବହାର କରି ବାମ କିମ୍ବା ଡାହାଣକୁ ସ୍ୱାଇପ କରନ୍ତୁ।\n\nଏଥିପାଇଁ ଆପଣ କୀବୋର୍ଡ ସର୍ଟକଟ ଆକ୍ସନ + ESC ମଧ୍ୟ ବ୍ୟବହାର କରିପାରିବେ।"</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ଯେ କୌଣସି ସମୟରେ ଆପଣଙ୍କ ହୋମ ସ୍କ୍ରିନକୁ ଯିବା ପାଇଁ ଆପଣଙ୍କ ସ୍କିନର ତଳୁ ତିନୋଟି ଆଙ୍ଗୁଠିରେ ଉପରକୁ ସ୍ୱାଇପ କରନ୍ତୁ।"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ବଢ଼ିଆ!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ଆପଣ \'ହୋମକୁ ଯାଆନ୍ତୁ\' ଜେଶ୍ଚର ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ବର୍ତ୍ତମାନର ଆପ୍ସ ଭ୍ୟୁ କରନ୍ତୁ"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"ଆପଣଙ୍କ ଟଚପେଡରେ ତିନୋଟି ଆଙ୍ଗୁଠିକୁ ବ୍ୟବହାର କରି ଉପରକୁ ସ୍ୱାଇପ କରି ଧରି ରଖନ୍ତୁ।"</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ବଢ଼ିଆ କାମ!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ଆପଣ ବର୍ତ୍ତମାନର ଆପ୍ସ ଜେଶ୍ଚରକୁ ଭ୍ୟୁ କରିବା ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ଆକ୍ସନ କୀ"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ଆପଣଙ୍କ ଆପ୍ସ ଆକ୍ସେସ କରିବା ପାଇଁ ଆପଣଙ୍କର କୀବୋର୍ଡରେ ଆକ୍ସନ କୀ\'କୁ ଦବାନ୍ତୁ।"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"ଅଭିନନ୍ଦନ!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"ତିନୋଟି ଆଙ୍ଗୁଠିରେ ଉପରକୁ ସ୍ୱାଇପ କରି ଧରି ରଖନ୍ତୁ। ଜେଶ୍ଚରଗୁଡ଼ିକ ବିଷୟରେ ଅଧିକ ଜାଣିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"ସମସ୍ତ ଆପ୍ସ ଭ୍ୟୁ କରିବା ପାଇଁ ଆପଣଙ୍କ କୀବୋର୍ଡକୁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ଯେ କୌଣସି ସମୟରେ ଆକ୍ସନ କୀ\'କୁ ଦବାନ୍ତୁ। ଜେଶ୍ଚରଗୁଡ଼ିକ ବିଷୟରେ ଅଧିକ ଜାଣିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"ଅତିରିକ୍ତ ଡିମ ବର୍ତ୍ତମାନ ଉଜ୍ଜ୍ୱଳତା ସ୍ଲାଇଡରର ଅଂଶ ଅଟେ"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"ବର୍ତ୍ତମାନ ଆପଣ ଉଜ୍ଜ୍ୱଳତାର ଲେଭେଲକୁ ଆହୁରି କମ କରି ସ୍କ୍ରିନକୁ ଅତିରିକ୍ତ ଡିମ କରିପାରିବେ।\n\nଏହି ଫିଚର ବର୍ତ୍ତମାନ ଉଜ୍ଜ୍ୱଳତା ସ୍ଲାଇଡରର ଅଂଶ ହୋଇଥିବା ଯୋଗୁଁ ଅତିରିକ୍ତ ଡିମ ସର୍ଟକଟଗୁଡ଼ିକୁ କାଢ଼ି ଦିଆଯାଉଛି।"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"ଅତିରିକ୍ତ ଡିମ ସର୍ଟକଟକୁ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"ଅତିରିକ୍ତ ଡିମ ସର୍ଟକଟକୁ କାଢ଼ି ଦିଆଯାଇଛି"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"କନେକ୍ଟିଭିଟି"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ଆକ୍ସେସିବିଲିଟୀ"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"ୟୁଟିଲିଟି"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 6a46613..dda36f7 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -577,7 +577,7 @@
<string name="empty_shade_text" msgid="8935967157319717412">"ਕੋਈ ਸੂਚਨਾ ਨਹੀਂ"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"ਕੋਈ ਨਵੀਂ ਸੂਚਨਾ ਨਹੀਂ ਹੈ"</string>
<string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"ਨੋਟੀਫ਼ਿਕੇਸ਼ਨ ਕੂਲਡਾਊਨ ਚਾਲੂ ਹੈ"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"ਇੱਕ ਵਾਰ \'ਚ ਕਈ ਸੂਚਨਾਵਾਂ ਮਿਲਣ \'ਤੇ, ਡੀਵਾਈਸ ਦੀ ਅਵਾਜ਼ ਤੇ ਅਲਰਟ ਵੱਧੋ-ਵੱਧ 2 ਮਿੰਟਾਂ ਲਈ ਆਪਣੇ ਆਪ ਘਟ ਹੋ ਜਾਂਦੇ ਹਨ।"</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"ਇੱਕ ਵਾਰ \'ਚ ਕਈ ਸੂਚਨਾਵਾਂ ਮਿਲਣ \'ਤੇ, ਡੀਵਾਈਸ ਦੀ ਅਵਾਜ਼ ਅਤੇ ਅਲਰਟ ਵੱਧੋ-ਵੱਧ 2 ਮਿੰਟਾਂ ਲਈ ਆਪਣੇ-ਆਪ ਘੱਟ ਜਾਂਦੇ ਹਨ।"</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"ਬੰਦ ਕਰੋ"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"ਪੁਰਾਣੀਆਂ ਸੂਚਨਾਵਾਂ ਦੇਖਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ਇਸ ਡੀਵਾਈਸ ਦਾ ਪ੍ਰਬੰਧਨ ਤੁਹਾਡੇ ਮਾਂ-ਪਿਓ ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ਸਪੀਕਰ ਅਤੇ ਡਿਸਪਲੇਆਂ"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"ਸੁਝਾਏ ਗਏ ਡੀਵਾਈਸ"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"ਮੀਡੀਆ ਨੂੰ ਕਿਸੇ ਹੋਰ ਡੀਵਾਈਸ \'ਤੇ ਲਿਜਾਉਣ ਲਈ ਆਪਣੇ ਸਾਂਝੇ ਕੀਤੇ ਸੈਸ਼ਨ ਨੂੰ ਬੰਦ ਕਰੋ"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"ਬੰਦ ਕਰੋ"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ਪ੍ਰਸਾਰਨ ਕਿਵੇਂ ਕੰਮ ਕਰਦਾ ਹੈ"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="manage_users" msgid="1823875311934643849">"ਵਰਤੋਂਕਾਰਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ਇਹ ਸੂਚਨਾ ਸਪਲਿਟ ਸਕ੍ਰੀਨ \'ਤੇ ਘਸੀਟਣ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ ਹੈ"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"ਟਿਕਾਣਾ ਕਿਰਿਆਸ਼ੀਲ ਹੈ"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ਵਾਈ-ਫਾਈ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ਤਰਜੀਹੀ ਮੋਡ"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ਅਲਾਰਮ ਸੈੱਟ ਹੈ"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"ਲਾਕ ਸਕ੍ਰੀਨ ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰੋ"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"ਲਾਕ ਸਕ੍ਰੀਨ ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰਨ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ਵਾਈ-ਫਾਈ ਉਪਲਬਧ ਨਹੀਂ"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"ਟਿਕਾਣਾ ਕਿਰਿਆਸ਼ੀਲ ਹੈ"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ਕੈਮਰਾ ਬਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ਕੈਮਰਾ ਅਤੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਬਲਾਕ ਕੀਤੇ ਗਏ"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਬਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ਟੱਚਪੈਡ ਇਸ਼ਾਰੇ, ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ ਅਤੇ ਹੋਰ ਬਹੁਤ ਕੁਝ ਬਾਰੇ ਜਾਣੋ"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ਪਿੱਛੇ ਜਾਣ ਦਾ ਇਸ਼ਾਰਾ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ਹੋਮ \'ਤੇ ਜਾਣ ਦਾ ਇਸ਼ਾਰਾ"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ਹਾਲੀਆ ਐਪਾਂ ਦੇਖੋ"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ਹੋ ਗਿਆ"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ਵਾਪਸ ਜਾਓ"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ਵਾਪਸ ਜਾਣ ਲਈ, ਟੱਚਪੈਡ \'ਤੇ ਕਿਤੇ ਵੀ ਤਿੰਨ ਉਂਗਲਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਖੱਬੇ ਜਾਂ ਸੱਜੇ ਪਾਸੇ ਵੱਲ ਸਵਾਈਪ ਕਰੋ।\n\nਤੁਸੀਂ ਇਸ ਲਈ ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ Action + ESC ਦੀ ਵਰਤੋਂ ਵੀ ਕਰ ਸਕਦੇ ਹੋ।"</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ਕਿਸੇ ਵੀ ਸਮੇਂ ਆਪਣੀ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਜਾਣ ਲਈ, ਤਿੰਨ ਉਂਗਲਾਂ ਨਾਲ ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ।"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ਵਧੀਆ!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ਤੁਸੀਂ \'ਹੋਮ \'ਤੇ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ।"</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ਹਾਲੀਆ ਐਪਾਂ ਦੇਖੋ"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"ਆਪਣੇ ਟੱਚਪੈਡ \'ਤੇ ਤਿੰਨ ਉਂਗਲਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰ ਕੇ ਦਬਾਈ ਰੱਖੋ।"</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ਬਹੁਤ ਵਧੀਆ!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ਤੁਸੀਂ \'ਹਾਲੀਆ ਐਪਾਂ ਦੇਖੋ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ ਹੈ।"</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ਕਾਰਵਾਈ ਕੁੰਜੀ"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ਆਪਣੀਆਂ ਐਪਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ, ਆਪਣੇ ਕੀ-ਬੋਰਡ \'ਤੇ ਕਾਰਵਾਈ ਕੁੰਜੀ ਨੂੰ ਦਬਾਓ।"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"ਵਧਾਈਆਂ!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"ਤਿੰਨ ਉਂਗਲਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰ ਕੇ ਦਬਾਈ ਰੱਖੋ। ਹੋਰ ਇਸ਼ਾਰਿਆਂ ਨੂੰ ਜਾਣਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"ਸਾਰੀਆਂ ਐਪਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਆਪਣਾ ਕੀ-ਬੋਰਡ ਵਰਤੋ"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ਕਿਸੇ ਵੀ ਸਮੇਂ ਕਾਰਵਾਈ ਕੁੰਜੀ ਦਬਾਓ। ਹੋਰ ਇਸ਼ਾਰਿਆਂ ਨੂੰ ਜਾਣਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"\'ਜ਼ਿਆਦਾ ਘੱਟ ਚਮਕ\' ਹੁਣ ਚਮਕ ਸਲਾਈਡਰ ਦਾ ਹਿੱਸਾ ਹੈ"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"ਤੁਸੀਂ ਹੁਣ ਚਕਮ ਦੇ ਪੱਧਰ ਨੂੰ ਹੋਰ ਵੀ ਘੱਟ ਕਰ ਕੇ ਸਕ੍ਰੀਨ ਦੀ ਚਮਕ ਨੂੰ ਜ਼ਿਆਦਾ ਘੱਟ ਕਰ ਸਕਦੇ ਹੋ।\n\nਕਿਉਂਕਿ ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਹੁਣ ਚਮਕ ਸਲਾਈਡਰ ਦਾ ਹਿੱਸਾ ਹੈ, \'ਜ਼ਿਆਦਾ ਘੱਟ ਚਮਕ\' ਸ਼ਾਰਟਕੱਟ ਹਟਾਏ ਜਾ ਰਹੇ ਹਨ।"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"\'ਜ਼ਿਆਦਾ ਘੱਟ ਚਮਕ\' ਸ਼ਾਰਟਕੱਟ ਹਟਾਓ"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"\'ਜ਼ਿਆਦਾ ਘੱਟ ਚਮਕ\' ਸ਼ਾਰਟਕੱਟ ਹਟਾਏ ਗਏ"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"ਕਨੈਕਟੀਵਿਟੀ"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ਪਹੁੰਚਯੋਗਤਾ"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"ਉਪਯੋਗਤਾਵਾਂ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 770d995..c1cdb58 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -577,7 +577,7 @@
<string name="empty_shade_text" msgid="8935967157319717412">"Brak powiadomień"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Brak nowych powiadomień"</string>
<string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"Wyciszanie powiadomień jest włączone"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Gdy otrzymasz za dużo powiadomień, dźwięk i alerty zostaną automatycznie wyciszone na maks. 2 min."</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Gdy w krótkim czasie otrzymasz za dużo powiadomień, dźwięki zostaną automatycznie wyciszone na maks. 2 min."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Wyłącz"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Odblokuj i zobacz starsze powiadomienia"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Tym urządzeniem zarządza Twój rodzic"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Głośniki i wyświetlacze"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Proponowane urządzenia"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Zatrzymaj udostępnianie sesji, aby przenieść multimedia na inne urządzenie"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Zatrzymaj"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jak działa transmitowanie"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 0563454..fe90562 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Alto-falantes e telas"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Opções de dispositivos"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Interrompa sua sessão compartilhada para transferir mídia a outro dispositivo"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Parar"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 0b31bab..3e9d782 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Altifalantes e ecrãs"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispositivos sugeridos"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Pare a sua sessão partilhada para mover conteúdos multimédia para outro dispositivo"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Parar"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 0563454..fe90562 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Alto-falantes e telas"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Opções de dispositivos"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Interrompa sua sessão compartilhada para transferir mídia a outro dispositivo"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Parar"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 5edcaf1..1279ca2 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Difuzoare și ecrane"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Dispozitive sugerate"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Oprește sesiunea comună ca să muți elementul media pe alt dispozitiv"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Oprește"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cum funcționează transmisia"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index a1f1750..5572658 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Колонки и дисплеи"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Рекомендуемые устройства"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Чтобы перенести медиафайлы на другое устройство, закройте доступ."</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Закрыть"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Как работают трансляции"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 3dac0c5..b0e322e 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ස්පීකර් සහ සංදර්ශක"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"යෝජිත උපාංග"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"මාධ්ය වෙනත් උපාංගයකට ගෙන යාමට ඔබේ බෙදා ගත් සැසිය නවත්වන්න"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"නවත්වන්න"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"විකාශනය ක්රියා කරන ආකාරය"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"එක් කරන්න"</string>
<string name="manage_users" msgid="1823875311934643849">"පරිශීලකයන් කළමනාකරණය කරන්න"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"මෙම දැනුම්දීම බෙදුම් තිරය වෙත ඇද ගෙන යාමට සහාය නොදක්වයි."</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"ස්ථානය සක්රියයි"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ලබා ගත නොහැකිය"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ප්රමුඛතා ප්රකාරය"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"සීනුව සකසන ලදි"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"අගුළු තිරය අභිරුචිකරණය කරන්න"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"අගුළු තිරය අභිරුචිකරණය කිරීමට අගුළු හරින්න"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ලද නොහැක"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"ස්ථානය සක්රියයි"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"කැමරාව අවහිරයි"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"කැමරාව සහ මයික්රොෆෝනය අවහිරයි"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"මයික්රොෆෝනය අවහිරයි"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ස්පර්ශ පෑඩ් අභිනයන්, යතුරුපුවරු කෙටිමං සහ තවත් දේ ඉගෙන ගන්න"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ආපසු අභිනය"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"නිවෙස් අභිනය"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"මෑත යෙදුම් බලන්න"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"නිමයි"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ආපස්සට යන්න"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ආපසු යාමට, ස්පර්ශ පුවරුවවේ ඕනෑම තැනක ඇඟිලි තුනක් භාවිතයෙන් වමට හෝ දකුණට ස්වයිප් කරන්න.\n\nඔබට මේ සඳහා යතුරු පුවරු කෙටිමං ක්රියාව + ESC ද භාවිත කළ හැක."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ඕනෑම වේලාවක ඔබේ මුල් තිරයට යාමට, ඔබේ තිරයේ පහළ සිට ඇඟිලි තුනකින් ඉහළට ස්වයිප් කරන්න."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"කදිමයි!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ඔබ මුල් පිටුවට යාමේ ඉංගිතය සම්පූර්ණ කළා."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"මෑත යෙදුම් බලන්න"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"ඉහළට ස්වයිප් කර ඔබේ ස්පර්ශ පුවරුව මත ඇඟිලි තුනක් භාවිතා කර සිටින්න."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"අනර්ඝ වැඩක්!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ඔබ මෑත යෙදුම් ඉංගිත බැලීම සම්පූර්ණ කර ඇත."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ක්රියා යතුර"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ඔබේ යෙදුම් වෙත ප්රවේශ වීමට, ඔබේ යතුරු පුවරුවෙහි ක්රියා යතුර ඔබන්න."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"සුබ පැතුම්!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"ඇඟිලි තුනක් භාවිතයෙන් ඉහළට ස්වයිප් කර අල්ලාගෙන සිටින්න. තව ඉංගිත දැන ගැනීමට තට්ටු කරන්න."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"සියලුම යෙදුම් බැලීමට ඔබේ යතුරු පුවරුව භාවිත කරන්න"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ඕනෑම අවස්ථාවක ක්රියාකාරී යතුර ඔබන්න. තව ඉංගිත දැන ගැනීමට තට්ටු කරන්න."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"තවත් අඳුරු දැන් දීප්තියේ ස්ලයිඩරයේ කොටසකි"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"ඔබට දැන් දීප්ති මට්ටම තවත් අඩු කිරීමෙන් තිරය තවත් අඳුරු කළ හැක.\n\nමෙම විශේෂාංගය දැන් දීප්තියේ ස්ලයිඩරයේ කොටසක් බැවින්, අමතර අඳුරු කෙටිමං ඉවත් කරනු ලැබේ."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"තවත් අඳුරු කෙටිමං ඉවත් කරන්න"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"තවත් අඳුරු කෙටිමං ඉවත් කරන ලදි"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"සබැඳුම් හැකියාව"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ප්රවේශ්යතාව"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"උපයෝගිතා"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 166a95c..50d9828 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -440,7 +440,7 @@
<string name="zen_mode_on" msgid="9085304934016242591">"Zapnuté"</string>
<string name="zen_mode_on_with_details" msgid="7416143430557895497">"Zapnuté • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="zen_mode_off" msgid="1736604456618147306">"Vypnuté"</string>
- <string name="zen_mode_set_up" msgid="7457957033034460064">"Nastavenie"</string>
+ <string name="zen_mode_set_up" msgid="7457957033034460064">"Nastaviť"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Správa v nastaveniach"</string>
<string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Žiadne aktívne režimy}=1{{mode} je aktívny}few{# režimy sú aktívne}many{# modes are active}other{# režimov je aktívnych}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"Nebudú vás vyrušovať zvuky ani vibrácie, iba budíky, pripomenutia, udalosti a volajúci, ktorých určíte. Budete naďalej počuť všetko, čo sa rozhodnete prehrať, ako napríklad hudbu, videá a hry."</string>
@@ -577,7 +577,7 @@
<string name="empty_shade_text" msgid="8935967157319717412">"Žiadne upozornenia"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Žiadne nové upozornenia"</string>
<string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"Stlmenie upozornení je zapnuté"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Keď dostanete priveľa upozornení naraz, hlasitosť vášho zariadenia a počet upozornení sa automaticky znížia až na dve minúty."</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Keď dostanete priveľa upozornení naraz, až na dve minúty sa zníži hlasitosť zariadenia a upozornenia sa obmedzia."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Vypnúť"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Odomknutím zobrazíte staršie upozornenia"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Toto zariadenie spravuje tvoj rodič"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Reproduktory a obrazovky"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Navrhované zariadenia"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Ak chcete preniesť médiá do iného zariadenia, ukončite zdieľanú reláciu"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Ukončiť"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Ako vysielanie funguje"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index fa80b3a..6452a54 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Zvočniki in zasloni"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Predlagane naprave"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Ustavi deljeno sejo za premik predstavnosti v drugo napravo."</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Ustavi"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako deluje oddajanje"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"Dodaj"</string>
<string name="manage_users" msgid="1823875311934643849">"Upravljaj uporabnike"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"To obvestilo ne podpira vlečenja v razdeljen zaslon."</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"Lokacija je aktivna"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ni na voljo."</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prednostni način"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je nastavljen."</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Prilagajanje zaklenjenega zaslona"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Odklenite za prilagajanje zaklenjenega zaslona"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ni na voljo."</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Lokacija je aktivna"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Fotoaparat je blokiran."</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Fotoaparat in mikrofon sta blokirana."</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokiran."</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Učenje potez na sledilni ploščici, bližnjičnih tipk in drugega"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Poteza za pomik nazaj"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Poteza za začetni zaslon"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ogled nedavnih aplikacij"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Končano"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazaj"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Za pomik nazaj povlecite levo ali desno s tremi prsti kjer koli na sledilni ploščici.\n\nUporabite lahko tudi bližnjični tipki Action + ESC."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Za pomik na začetni zaslon lahko kadar koli s tremi prsti povlečete navzgor z dna zaslona."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Odlično!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Izvedli ste potezo za pomik na začetni zaslon."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ogled nedavnih aplikacij"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Na sledilni ploščici s tremi prsti povlecite navzgor in pridržite."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Odlično!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Izvedli ste potezo za ogled nedavnih aplikacij."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tipka za dejanja"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Za dostop do aplikacij pritisnite tipko za dejanja na tipkovnici."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Čestitamo!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"S tremi prsti povlecite navzgor in pridržite. Dotaknite se, če želite spoznati več potez."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Uporaba tipkovnice za prikaz vseh aplikacij"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Kadar koli pritisnite tipko za dejanja. Dotaknite se, če želite spoznati več potez."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Funkcija Zelo zatemnjeno je zdaj del drsnika za svetlost"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Zdaj lahko zelo zatemnite zaslon tako, da dodatno zmanjšate raven svetlosti.\n\nKer je ta funkcija zdaj del drsnika za svetlost, bodo bližnjice do funkcije Zelo zatemnjeno odstranjene."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Odstrani bližnjice do funkcije Zelo zatemnjeno"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Bližnjice do funkcije Zelo zatemnjeno so odstranjene"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Povezljivost"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Dostopnost"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Orodja"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 0b700f8..7ea8044 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Altoparlantët dhe ekranet"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Pajisjet e sugjeruara"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Ndalo sesionin e ndarë për ta zhvendosur median në një pajisje tjetër"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Ndalo"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Si funksionon transmetimi"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"Shto"</string>
<string name="manage_users" msgid="1823875311934643849">"Menaxho përdoruesit"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Ky njoftim nuk mbështet zvarritjen tek ekrani i ndarë"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"Vendndodhja aktive"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi nuk ofrohet"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modaliteti \"Me përparësi\""</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmi është caktuar"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Personalizo ekranin e kyçjes"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Shkyçe për të personalizuar ekranin e kyçjes"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi nuk ofrohet"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Vendndodhja aktive"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera u bllokua"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dhe mikrofoni u bllokuan"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofoni u bllokua"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Mëso gjestet e bllokut me prekje, shkurtoret e tastierës etj."</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gjesti i kthimit prapa"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gjesti për të shkuar tek ekrani bazë"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Shiko aplikacionet e fundit"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"U krye"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kthehu prapa"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Për t\'u kthyer, rrëshqit shpejt majtas ose djathtas duke përdorur tri gishta kudo në bllokun me prekje.\n\nPër ta bërë këtë, mund të përdorësh gjithashtu shkurtoren e tastierës \"Action + ESC\"."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Për të shkuar tek ekrani bazë në çdo kohë, rrëshqit shpejt lart me tre gishta nga fundi i ekranit."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bukur!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"E ke përfunduar gjestin e kalimit tek ekrani bazë."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Shiko aplikacionet e fundit"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Rrëshqit shpejt lart dhe mbaj shtypur me tre gishta në bllokun me prekje."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Punë e shkëlqyer!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Përfundove gjestin për shikimin e aplikacioneve të fundit."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tasti i veprimit"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Për t\'u qasur në aplikacionet e tua, shtyp tastin e veprimit në tastierë."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Urime!"</string>
@@ -1446,26 +1443,15 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Rrëshqit shpejt lart dhe mbaj shtypur me tre gishta. Trokit për të mësuar më shumë gjeste."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Përdor tastierën për të shikuar të gjitha aplikacionet"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Shtyp tastin e veprimit në çdo kohë. Trokit për të mësuar më shumë gjeste."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Modaliteti \"Shumë më i zbehtë\" tani është pjesë e rrëshqitësit të ndriçimit"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Tani mund ta bësh ekranin shumë më të zbehtë duke e ulur nivelin e ndriçimit edhe më tej.\n\nDuke qenë se kjo veçori tani është pjesë e rrëshqitësit të ndriçimit, shkurtoret e modalitetit \"Shumë më i zbehtë\" janë hequr."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Hiq shkurtoret e modalitetit \"Shumë më i zbehtë\""</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Shkurtoret e modalitetit \"Shumë më i zbehtë\" u hoqën"</string>
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Lidhshmëria"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Qasshmëria"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Aplikacione utilitare"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privatësia"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Mundësuar nga aplikacionet"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Ekrani"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nuk njihet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index b1abb59..1930eade 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Звучници и екрани"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Предложени уређаји"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Зауставите дељену сесију да бисте преместили медијски садржај на други уређај"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Заустави"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Како функционише емитовање"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 8817fe8..a4abb77 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -576,7 +576,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Starta nu"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Inga aviseringar"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Det finns inga nya aviseringar"</string>
- <string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"Gradvis sänkning för aviseringar är på"</string>
+ <string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"Dämpning av aviseringar är på"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Enheten sänker volymen och minimerar aviseringar i upp till två minuter när du får för många aviseringar samtidigt."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Inaktivera"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Lås upp för att se äldre aviseringar"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Högtalare och skärmar"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Förslag på enheter"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Stoppa din delade session för att flytta media till en annan enhet"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Stoppa"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Så fungerar utsändning"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 28f677a..67ad0b5 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -440,9 +440,9 @@
<string name="zen_mode_on" msgid="9085304934016242591">"Imewashwa"</string>
<string name="zen_mode_on_with_details" msgid="7416143430557895497">"Imewashwa • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="zen_mode_off" msgid="1736604456618147306">"Imezimwa"</string>
- <string name="zen_mode_set_up" msgid="7457957033034460064">"Weka mipangilio"</string>
+ <string name="zen_mode_set_up" msgid="7457957033034460064">"Ratibu"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Dhibiti katika mipangilio"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Hakuna hali za kutumika}=1{Unatumia {mode}}other{Unatumia hali #}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Hakuna hali zinazotumika}=1{Unatumia {mode}}other{Unatumia hali #}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"Hutasumbuliwa na sauti na mitetemo, isipokuwa kengele, vikumbusho, matukio na simu zinazopigwa na watu uliobainisha. Bado utasikia chochote utakachochagua kucheza, ikiwa ni pamoja na muziki, video na michezo."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"Hutasumbuliwa na sauti na mitetemo, isipokuwa kengele. Bado utasikia chochote utakachochagua kucheza, ikiwa ni pamoja na muziki, video na michezo."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"Badilisha upendavyo"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Spika na Skrini"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Vifaa Vilivyopendekezwa"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Simamisha kipindi unachoshiriki ili uhamishie maudhui kwenye kifaa kingine"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Simamisha"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jinsi utangazaji unavyofanya kazi"</string>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 3efe7a5..2a27b47 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -26,10 +26,6 @@
<dimen name="keyguard_clock_top_margin">8dp</dimen>
<dimen name="keyguard_smartspace_top_offset">0dp</dimen>
- <!-- New keyboard shortcut helper -->
- <dimen name="shortcut_helper_width">864dp</dimen>
- <dimen name="shortcut_helper_height">728dp</dimen>
-
<!-- QS-->
<dimen name="qs_panel_padding_top">16dp</dimen>
<dimen name="qs_panel_padding">24dp</dimen>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 3b8e3c2..c574912 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ஸ்பீக்கர்கள் & டிஸ்ப்ளேக்கள்"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"பரிந்துரைக்கப்படும் சாதனங்கள்"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"மீடியாவை வேறொரு சாதனத்திற்கு மாற்ற \'பகிரப்படும் அமர்வை\' நிறுத்தவும்"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"நிறுத்து"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"பிராட்காஸ்ட் எவ்வாறு செயல்படுகிறது?"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 84fc147..f4bf055 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -577,7 +577,7 @@
<string name="empty_shade_text" msgid="8935967157319717412">"నోటిఫికేషన్లు లేవు"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"కొత్త నోటిఫికేషన్లు ఏవీ లేవు"</string>
<string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"నోటిఫికేషన్ కూల్డౌన్ ఆన్ అయింది"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"ఒకేసారి పలు నోటిఫికేషన్లు వస్తే, పరికర వాల్యూమ్, అలర్ట్లు ఆటోమేటిక్గా 2 నిమిషాలకు తగ్గించబడతాయి."</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"ఒకేసారి పలు నోటిఫికేషన్లు వస్తే, పరికర వాల్యూమ్, అలర్ట్స్ ఆటోమేటిగ్గా 2 నిమిషాలకు తగ్గించబడతాయి."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"ఆఫ్ చేయండి"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"పాత నోటిఫికేషన్ల కోసం అన్లాక్ చేయండి"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ఈ పరికరాన్ని మీ తల్లి/తండ్రి మేనేజ్ చేస్తున్నారు"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"స్పీకర్లు & డిస్ప్లేలు"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"సూచించబడిన పరికరాలు"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"మీడియాను మరొక పరికరానికి తరలించడానికి మీ షేర్ చేసిన సెషన్ను ఆపండి"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"ఆపండి"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ప్రసారం కావడం అనేది ఎలా పని చేస్తుంది"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"జోడించండి"</string>
<string name="manage_users" msgid="1823875311934643849">"యూజర్లను మేనేజ్ చేయండి"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ఈ నోటిఫికేషన్ స్ప్లిట్ స్క్రీన్కు లాగడాన్ని సపోర్ట్ చేయదు"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"లొకేషన్ యాక్టివ్గా ఉంది"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi అందుబాటులో లేదు"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ముఖ్యమైన ఫైల్స్ మోడ్"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"అలారం సెట్ చేశాను"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"లాక్ స్క్రీన్ అనుకూలంగా మార్చండి"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"లాక్ స్క్రీన్ను అనుకూలంగా మార్చుకోవడానికి అన్లాక్ చేయండి"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi అందుబాటులో లేదు"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"లొకేషన్ యాక్టివ్గా ఉంది"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"కెమెరా బ్లాక్ చేయబడింది"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"కెమెరా, మైక్రోఫోన్ బ్లాక్ చేయబడ్డాయి"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"మైక్రోఫోన్ బ్లాక్ చేయబడింది"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"టచ్ప్యాడ్ సంజ్ఞలు, కీబోర్డ్ షార్ట్కట్లు, అలాగే మరిన్నింటిని గురించి తెలుసుకోండి"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"వెనుకకు పంపే సంజ్ఞ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"హోమ్కు పంపే సంజ్ఞ"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ఇటీవలి యాప్లను చూడండి"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"పూర్తయింది"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"వెనుకకు"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"వెనుకకు వెళ్లడానికి, టచ్ప్యాడ్లో ఎక్కడైనా మూడు వేళ్లను ఉపయోగించి ఎడమ లేదా కుడి వైపునకు స్వైప్ చేయండి.\n\nమీరు దీని కోసం + ESC కీబోర్డ్ షార్ట్కట్ యాక్షన్ను కూడా ఉపయోగించవచ్చు."</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ఏ సమయంలోనైనా మీ మొదటి స్క్రీన్కు వెళ్లడానికి, మీ స్క్రీన్ కింది నుండి మూడు వేళ్లతో పైకి స్వైప్ చేయండి."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"సూపర్!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"మొదటి స్క్రీన్కు వెళ్ళడానికి ఉపయోగించే సంజ్ఞకు సంబంధించిన ట్యుటోరియల్ను మీరు పూర్తి చేశారు."</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ఇటీవలి యాప్లను చూడండి"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"మీ టచ్ప్యాడ్లో మూడు వేళ్లను ఉపయోగించి పైకి స్వైప్ చేసి, హోల్డ్ చేయండి."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"పనితీరు అద్భుతంగా ఉంది!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"మీరు ఇటీవలి యాప్ల వీక్షణ సంజ్ఞను పూర్తి చేశారు."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"యాక్షన్ కీ"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"మీ యాప్లను యాక్సెస్ చేయడానికి, మీ కీబోర్డ్లో యాక్షన్ కీని నొక్కండి."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"అభినందనలు!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"మూడు వేళ్లతో పైకి స్వైప్ చేసి, హోల్డ్ చేయండి. మరిన్ని సంజ్ఞల గురించి తెలుసుకోవడానికి ట్యాప్ చేయండి."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"యాప్లన్నింటినీ చూడటానికి మీ కీబోర్డ్ను ఉపయోగించండి"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ఏ సమయంలోనైనా యాక్షన్ కీని నొక్కండి. మరిన్ని సంజ్ఞల గురించి తెలుసుకోవడానికి ట్యాప్ చేయండి."</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"కాంతిని మరింత డిమ్ చేసే ఫీచర్ ఇప్పుడు బ్రైట్నెస్ స్లయిడర్లో ఒక భాగం"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"మీరు ఇప్పుడు బ్రైట్నెస్ స్థాయిని మరింత తగ్గించడం ద్వారా స్క్రీన్ను కాంతిని మరింత డిమ్ చేయవచ్చు.\n\nఈ ఫీచర్ ఇప్పుడు బ్రైట్నెస్ స్లయిడర్లో భాగం కాబట్టి, కాంతిని మరింత డిమ్ చేసే షార్ట్కట్లు తీసివేయబడుతున్నాయి."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"కాంతిని మరింత డిమ్ చేసే షార్ట్కట్లను తీసివేయండి"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"కాంతిని మరింత డిమ్ చేసే షార్ట్కట్లు తీసివేయబడ్డాయి"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"కనెక్టివిటీ"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibility"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"యుటిలిటీలు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 1d7a782..4224831 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"ลำโพงและจอแสดงผล"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"อุปกรณ์ที่แนะนำ"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"หยุดเซสชันที่แชร์อยู่เพื่อย้ายสื่อไปยังอุปกรณ์อื่น"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"หยุด"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"วิธีการทำงานของการออกอากาศ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 00be27b..5145f26a 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Mga Speaker at Display"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Mga Iminumungkahing Device"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Ihinto ang iyong nakabahaging session para maglipat ng media sa ibang device"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Ihinto"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Paano gumagana ang pag-broadcast"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 0031687..63c9a3c 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"%%<xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Hoparlörler ve Ekranlar"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Önerilen Cihazlar"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Medyayı başka bir cihaza taşımak için paylaşılan oturumunuzu durdurun"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Durdur"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Yayınlamanın işleyiş şekli"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 715b179..98ed6c04 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Колонки й екрани"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Пропоновані пристрої"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Зупиніть сеанс спільного доступу, щоб перенести медіаконтент на інший пристрій"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Зупинити"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Як працює трансляція"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 78a7f428..cd57d52a 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"%%<xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"اسپیکرز اور ڈسپلیز"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"تجویز کردہ آلات"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"میڈیا کو دوسرے آلے پر منتقل کرنے کے لیے اپنا مشترکہ سیشن بند کریں"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"بند کریں"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"براڈکاسٹنگ کیسے کام کرتا ہے"</string>
@@ -1289,8 +1293,7 @@
<string name="add" msgid="81036585205287996">"شامل کریں"</string>
<string name="manage_users" msgid="1823875311934643849">"صارفین کا نظم کریں"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"یہ اطلاع اسپلٹ اسکرین پر گھسیٹنے کو سپورٹ نہیں کرتی ہے"</string>
- <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
- <skip />
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"مقام فعال ہے"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi دستیاب نہیں ہے"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ترجیحی وضع"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"الارم سیٹ ہوگیا"</string>
@@ -1347,8 +1350,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"مقفل اسکرین کو حسب ضرورت بنائیں"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"مقفل اسکرین کو حسب ضرورت بنانے کے لیے غیر مقفل کریں"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi دستیاب نہیں ہے"</string>
- <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
- <skip />
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"مقام فعال ہے"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"کیمرا مسدود ہے"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"کیمرا اور مائیکروفون مسدود ہے"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"مائیکروفون مسدود ہے"</string>
@@ -1404,8 +1406,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ٹچ پیڈ کے اشارے، کی بورڈ شارٹ کٹس اور مزید جانیں"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"پیچھے جانے کا اشارہ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ہوم کا اشارہ"</string>
- <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
- <skip />
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"حالیہ ایپس دیکھیں"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ہو گیا"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"واپس جائیں"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"واپس جانے کے لیے، ٹچ پیڈ پر کہیں بھی تین انگلیوں کی مدد سے دائیں یا بائیں سوائپ کریں۔\n\nآپ اس کیلئے کی بورڈ شارٹ کٹ ایکشن + Esc کا بھی استعمال کر سکتے ہیں۔"</string>
@@ -1415,14 +1416,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"کسی بھی وقت اپنی ہوم اسکرین پر جانے کے لیے، تین انگلیوں کی مدد سے اپنی اسکرین کے نیچے سے اوپر کی طرف سوائپ کریں۔"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"عمدہ!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"آپ نے ہوم پر جانے کا اشارہ مکمل کر لیا۔"</string>
- <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
- <skip />
- <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
- <skip />
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"حالیہ ایپس دیکھیں"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"اپنے ٹچ پیڈ پر تین انگلیوں کا استعمال کرتے ہوئے اوپر کی طرف سوائپ کریں اور دبائے رکھیں۔"</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"بہترین!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"آپ نے حالیہ ایپس کا اشارہ مکمل کر لیا ہے۔"</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ایکشن کلید"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"اپنی ایپس تک رسائی حاصل کرنے کے لیے، اپنے کی بورڈ پر ایکشن کلید کو دبائیں۔"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"مبارکباد!"</string>
@@ -1446,14 +1443,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"تین انگلیوں سے اوپر کی طرف سوائپ کریں اور دبائے رکھیں۔ مزید اشارے جاننے کے لیے تھپتھپائیں۔"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"سبھی ایپس دیکھنے کے لیے اپنے کی بورڈ کا استعمال کریں"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"کسی بھی وقت ایکشن کلید دبائیں۔ مزید اشارے جاننے کے لیے تھپتھپائیں۔"</string>
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
- <skip />
- <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
- <skip />
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"اضافی دھندلا اب چمک سلائیڈر کا حصہ ہے"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"آپ چمکیلے پن لیول کو مزید کم کر کے اپنی اسکرین کو اضافی دھندلی بنا سکتے ہیں۔\n\nچونکہ یہ خصوصیت اب چمکیلے پن کے سلائیڈر کا حصہ ہے، اس لیے اضافی دھندلا شارٹ کٹس کو ہٹایا جا رہا ہے۔"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"اضافی دھندلا شارٹ کٹس کو ہٹائیں"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"اضافی دھندلا شارٹ کٹس ہٹا دیے گئے"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"کنیکٹویٹی"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ایکسیسبیلٹی"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"یوٹیلیٹیز"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 51cf8b5..07faf6a 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -442,7 +442,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"Yoqilmagan"</string>
<string name="zen_mode_set_up" msgid="7457957033034460064">"Sozlash"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Sozlamalarda boshqarish"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Hech qanday rejim faol emas}=1{{mode} faol}other{# ta rejim faol}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{0 ta rejim faol}=1{{mode} faol}other{# ta rejim faol}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"Turli ovoz va tebranishlar endi sizni bezovta qilmaydi. Biroq, signallar, eslatmalar, tadbirlar haqidagi bildirishnomalar va siz tanlagan abonentlardan kelgan chaqiruvlar bundan mustasno. Lekin, ijro etiladigan barcha narsalar, jumladan, musiqa, video va o‘yinlar ovozi eshitiladi."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"Turli ovoz va tebranishlar endi sizni bezovta qilmaydi. Biroq, signallar bundan mustasno. Lekin, ijro etiladigan barcha narsalar, jumladan, musiqa, video va o‘yinlar ovozi eshitiladi."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"Sozlash"</string>
@@ -576,7 +576,7 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"Boshlash"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Bildirishnomalar yo‘q"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Yangi bildirishoma yoʻq"</string>
- <string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"Bildirishnomalarni sekinlatish yoniq"</string>
+ <string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"Bildirishnomalar ovozini pasaytirish yoniq"</string>
<string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Bir vaqtda juda koʻp bildirishnoma olsangiz, qurilmangiz tovushi va ogohlantirishlar 2 daqiqagacha avtomatik pasaytiriladi."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Faolsizlantirish"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Eskilarini koʻrish uchun qulfni yeching"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Karnaylar va displeylar"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Taklif qilingan qurilmalar"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Mediani boshqa qurilmaga koʻchirish uchun umumiy seansingizni toʻxtating"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Toʻxtatish"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Translatsiya qanday ishlaydi"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index fb9abd7..279fe1e 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Loa và màn hình"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Thiết bị được đề xuất"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Dừng phiên chia sẻ của bạn để chuyển nội dung nghe nhìn sang thiết bị khác"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Dừng"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cách tính năng truyền hoạt động"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index d311aa3..6b1f0a7 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -442,7 +442,7 @@
<string name="zen_mode_off" msgid="1736604456618147306">"已关闭"</string>
<string name="zen_mode_set_up" msgid="7457957033034460064">"设置"</string>
<string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"在设置中管理"</string>
- <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{未启用任何模式}=1{{mode}已启用}other{# 个模式已启用}}"</string>
+ <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{未启用任何模式}=1{已启用“{mode}”模式}other{已启用 # 个模式}}"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"您将不会受到声音和振动的打扰(闹钟、提醒、活动和所指定来电者的相关提示音除外)。您依然可以听到您选择播放的任何内容(包括音乐、视频和游戏)的相关音效。"</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"您将不会受到声音和振动的打扰(闹钟提示音除外)。您依然可以听到您选择播放的任何内容(包括音乐、视频和游戏)的相关音效。"</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"自定义"</string>
@@ -576,8 +576,8 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"立即开始"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"没有通知"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"没有新通知"</string>
- <string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"“通知音量渐降”设置已开启"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"当您一次收到过多通知时,设备音量会自动降低,提醒次数也会自动减少,这种状况最长可持续 2 分钟。"</string>
+ <string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"已触发“通知音量渐降”"</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"如果您在短时间内收到很多通知,设备音量和提醒次数会自动降低,最长持续 2 分钟。"</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"关闭"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"解锁即可查看旧通知"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"此设备由您的家长管理"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"音箱和显示屏"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"建议的设备"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"停止共享的会话,即可将媒体移到其他设备"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"停止"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"广播的运作方式"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 91ae846..13b1a0f 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -576,8 +576,8 @@
<string name="media_projection_action_text" msgid="3634906766918186440">"立即開始"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"沒有通知"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"沒有新通知"</string>
- <string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"調低通知強度功能已開啟"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"如果同一時間收到太多通知,裝置會在最長 2 分鐘內調低音量,並減少警示。"</string>
+ <string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"通知緩和已開啟"</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"當你在短時間內收到太多通知時,裝置就會調低音量並減少通知數量最多兩分鐘。"</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"關閉"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"解鎖即可查看舊通知"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"此裝置由你的家長管理"</string>
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"喇叭和螢幕"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"建議的裝置"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"停止共享工作階段以移動媒體至其他裝置"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"停止"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"廣播運作方式"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 93a99e6..0107819 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"喇叭和螢幕"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"建議的裝置"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"停止共用的工作階段,即可將媒體移至其他裝置"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"停止"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"廣播功能的運作方式"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 9fc1166..8eddc80 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -1179,6 +1179,10 @@
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
<string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Izipikha Neziboniso"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"Amadivayisi Aphakanyisiwe"</string>
+ <!-- no translation found for media_input_group_title (2057057473860783021) -->
+ <skip />
+ <!-- no translation found for media_output_group_title (6789001895863332576) -->
+ <skip />
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"Misa iseshini yakho eyabiwe ukuze uhambise imidiya kwenye idivayisi"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"Misa"</string>
<string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Indlela ukusakaza okusebenza ngayo"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 00846cb..e94248d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1005,10 +1005,6 @@
<dimen name="ksh_app_item_minimum_height">64dp</dimen>
<dimen name="ksh_category_separator_margin">16dp</dimen>
- <!-- New keyboard shortcut helper -->
- <dimen name="shortcut_helper_width">412dp</dimen>
- <dimen name="shortcut_helper_height">728dp</dimen>
-
<!-- The size of corner radius of the arrow in the onboarding toast. -->
<dimen name="recents_onboarding_toast_arrow_corner_radius">2dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ba3822b..a3db776 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3711,6 +3711,12 @@
[CHAR LIMIT=NONE]
-->
<string name="shortcut_helper_key_combinations_or_separator">or</string>
+ <!-- Content description of the drag handle that allows to swipe to dismiss the shortcut helper.
+ The helper is a component that shows the user which keyboard shortcuts they can
+ use. The helper shows shortcuts in categories, which can be collapsed or expanded.
+ [CHAR LIMIT=NONE] -->
+ <string name="shortcut_helper_content_description_drag_handle">Drag handle</string>
+
<!-- Keyboard touchpad tutorial scheduler-->
<!-- Notification title for launching keyboard tutorial [CHAR_LIMIT=100] -->
diff --git a/packages/SystemUI/res/xml/media_session_collapsed.xml b/packages/SystemUI/res/xml/media_session_collapsed.xml
index 2f2b10f..66c54a3 100644
--- a/packages/SystemUI/res/xml/media_session_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_session_collapsed.xml
@@ -65,7 +65,7 @@
<Constraint
android:id="@+id/header_title"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginStart="@dimen/qs_media_padding"
@@ -87,13 +87,11 @@
app:layout_constraintEnd_toStartOf="@id/header_artist"
app:layout_constraintTop_toTopOf="@id/header_artist"
app:layout_constraintBottom_toBottomOf="@id/header_artist"
- app:layout_constraintVertical_bias="0"
- app:layout_constraintHorizontal_bias="0"
- app:layout_constraintHorizontal_chainStyle="packed" />
+ app:layout_constraintVertical_bias="0" />
<Constraint
android:id="@+id/header_artist"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/qs_media_padding"
android:layout_marginBottom="@dimen/qs_media_padding"
@@ -102,6 +100,8 @@
app:layout_constrainedWidth="true"
app:layout_constraintStart_toEndOf="@id/media_explicit_indicator"
app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintHorizontal_weight="1"
+ app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintVertical_bias="0" />
<Constraint
diff --git a/packages/SystemUI/res/xml/media_session_expanded.xml b/packages/SystemUI/res/xml/media_session_expanded.xml
index 0140d52..19cc3bc5 100644
--- a/packages/SystemUI/res/xml/media_session_expanded.xml
+++ b/packages/SystemUI/res/xml/media_session_expanded.xml
@@ -58,7 +58,7 @@
<Constraint
android:id="@+id/header_title"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/qs_media_padding"
android:layout_marginEnd="@dimen/qs_media_padding"
@@ -80,13 +80,11 @@
app:layout_constraintStart_toStartOf="@id/header_title"
app:layout_constraintEnd_toStartOf="@id/header_artist"
app:layout_constraintTop_toTopOf="@id/header_artist"
- app:layout_constraintBottom_toTopOf="@id/media_action_barrier_top"
- app:layout_constraintHorizontal_bias="0"
- app:layout_constraintHorizontal_chainStyle="packed"/>
+ app:layout_constraintBottom_toTopOf="@id/media_action_barrier_top" />
<Constraint
android:id="@+id/header_artist"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/qs_media_padding"
android:layout_marginBottom="@dimen/qs_media_padding"
@@ -95,6 +93,8 @@
app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
app:layout_constraintStart_toEndOf="@id/media_explicit_indicator"
app:layout_constraintBottom_toTopOf="@id/media_action_barrier_top"
+ app:layout_constraintHorizontal_weight="1"
+ app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintVertical_bias="0" />
<Constraint
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 121577e..78cd02f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -345,6 +345,10 @@
|| (sysuiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0) {
return false;
}
+ // Disable back gesture on the hub, but not when the shade is showing.
+ if ((sysuiStateFlags & SYSUI_STATE_COMMUNAL_HUB_SHOWING) != 0) {
+ return (sysuiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE) == 0;
+ }
if ((sysuiStateFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0) {
sysuiStateFlags &= ~SYSUI_STATE_NAV_BAR_HIDDEN;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index b10d37e..c95a94e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -34,9 +34,7 @@
import com.android.systemui.CoreStartable
import com.android.systemui.Flags.lightRevealMigration
import com.android.systemui.biometrics.data.repository.FacePropertyRepository
-import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
-import com.android.systemui.biometrics.shared.model.toSensorType
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.domain.interactor.AuthRippleInteractor
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
@@ -104,7 +102,6 @@
private var udfpsController: UdfpsController? = null
private var udfpsRadius: Float = -1f
- private var udfpsType: FingerprintSensorType = FingerprintSensorType.UNKNOWN
override fun start() {
init()
@@ -373,11 +370,8 @@
private val udfpsControllerCallback =
object : UdfpsController.Callback {
override fun onFingerDown() {
- // only show dwell ripple for device entry non-ultrasonic udfps
- if (
- keyguardUpdateMonitor.isFingerprintDetectionRunning &&
- udfpsType != FingerprintSensorType.UDFPS_ULTRASONIC
- ) {
+ // only show dwell ripple for device entry
+ if (keyguardUpdateMonitor.isFingerprintDetectionRunning) {
showDwellRipple()
}
}
@@ -403,7 +397,6 @@
if (it.size > 0) {
udfpsController = udfpsControllerProvider.get()
udfpsRadius = authController.udfpsRadius
- udfpsType = it[0].sensorType.toSensorType()
if (mView.isAttachedToWindow) {
udfpsController?.addCallback(udfpsControllerCallback)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 5ffb9ab2..a3904ca 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -19,6 +19,7 @@
import static android.app.StatusBarManager.SESSION_BIOMETRIC_PROMPT;
import static android.app.StatusBarManager.SESSION_KEYGUARD;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
import static android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP;
import static android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD;
import static android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING;
@@ -329,6 +330,22 @@
int sensorId,
@BiometricFingerprintConstants.FingerprintAcquired int acquiredInfo
) {
+ if (isUltrasonic()) {
+ if (acquiredInfo == FINGERPRINT_ACQUIRED_START) {
+ mFgExecutor.execute(() -> {
+ for (Callback cb : mCallbacks) {
+ cb.onFingerDown();
+ }
+ });
+ } else {
+ mFgExecutor.execute(() -> {
+ for (Callback cb : mCallbacks) {
+ cb.onFingerUp();
+ }
+ });
+ }
+ }
+
if (BiometricFingerprintConstants.shouldDisableUdfpsDisplayMode(acquiredInfo)) {
boolean acquiredGood = acquiredInfo == FINGERPRINT_ACQUIRED_GOOD;
mFgExecutor.execute(() -> {
@@ -1024,6 +1041,10 @@
return mSensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
}
+ private boolean isUltrasonic() {
+ return mSensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC;
+ }
+
public boolean isFingerDown() {
return mOnFingerDown;
}
@@ -1105,8 +1126,10 @@
}
}
- for (Callback cb : mCallbacks) {
- cb.onFingerDown();
+ if (isOptical()) {
+ for (Callback cb : mCallbacks) {
+ cb.onFingerDown();
+ }
}
}
@@ -1143,8 +1166,10 @@
if (mOnFingerDown) {
mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId, pointerId, x,
y, minor, major, orientation, time, gestureStart, isAod);
- for (Callback cb : mCallbacks) {
- cb.onFingerUp();
+ if (isOptical()) {
+ for (Callback cb : mCallbacks) {
+ cb.onFingerUp();
+ }
}
}
mOnFingerDown = false;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
index bb450c0..18a7739 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
@@ -83,7 +83,7 @@
/** Sets whether Udfps overlay should handle touches */
fun setHandleTouches(shouldHandle: Boolean = true) {
- if (authController.isUltrasonicUdfpsSupported
+ if (authController.isUdfpsSupported
&& shouldHandle != _shouldHandleTouches.value) {
fingerprintManager?.setIgnoreDisplayTouches(
requestId.value,
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/ComposeBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/ComposeBouncerViewBinder.kt
index b5e54d5..fdbc18d 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/ComposeBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/ComposeBouncerViewBinder.kt
@@ -5,7 +5,6 @@
import androidx.activity.OnBackPressedDispatcherOwner
import androidx.activity.setViewTreeOnBackPressedDispatcherOwner
import androidx.compose.ui.platform.ComposeView
-import androidx.core.view.isGone
import androidx.lifecycle.Lifecycle
import com.android.systemui.bouncer.ui.BouncerDialogFactory
import com.android.systemui.bouncer.ui.composable.BouncerContainer
@@ -13,7 +12,6 @@
import com.android.systemui.bouncer.ui.viewmodel.BouncerSceneContentViewModel
import com.android.systemui.lifecycle.WindowLifecycleState
import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.lifecycle.setSnapshotBinding
import com.android.systemui.lifecycle.viewModel
import kotlinx.coroutines.awaitCancellation
@@ -50,7 +48,6 @@
setContent { BouncerContainer(viewModelFactory, dialogFactory) }
}
)
- view.setSnapshotBinding { view.isGone = !viewModel.isVisible }
awaitCancellation()
} finally {
view.removeAllViews()
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
index 873d1b3..4185aed 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
@@ -86,6 +86,9 @@
_animateFailure.value = authenticationResult != AuthenticationResult.SUCCEEDED
clearInput()
+ if (authenticationResult == AuthenticationResult.SUCCEEDED) {
+ onSuccessfulAuthentication()
+ }
}
awaitCancellation()
}
@@ -116,6 +119,9 @@
/** Returns the input entered so far. */
protected abstract fun getInput(): List<Any>
+ /** Invoked after a successful authentication. */
+ protected open fun onSuccessfulAuthentication() = Unit
+
/** Perform authentication result haptics */
private fun performAuthenticationHapticFeedback(result: AuthenticationResult) {
if (result == AuthenticationResult.SKIPPED) return
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
index c60f932..5a4f8eb 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
@@ -16,17 +16,15 @@
package com.android.systemui.bouncer.ui.viewmodel
-import androidx.compose.runtime.getValue
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
import com.android.systemui.lifecycle.ExclusiveActivatable
-import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
-import com.android.systemui.util.kotlin.Utils.Companion.sample
import com.android.systemui.util.kotlin.sample
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
@@ -39,11 +37,6 @@
private val deviceUnlockedInteractor: DeviceUnlockedInteractor,
) : ExclusiveActivatable() {
- private val hydrator = Hydrator("BouncerContainerViewModel")
-
- val isVisible: Boolean by
- hydrator.hydratedStateOf(traceName = "isVisible", source = legacyInteractor.isShowing)
-
override suspend fun onActivated(): Nothing {
coroutineScope {
launch {
@@ -74,8 +67,7 @@
legacyInteractor.hide()
}
}
-
- hydrator.activate()
+ awaitCancellation()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
index 2493cf1..1427d78 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
@@ -81,50 +81,59 @@
val selectedUserId: StateFlow<Int> = _selectedUserId.asStateFlow()
private val requests = Channel<Request>(Channel.BUFFERED)
+ private var wasSuccessfullyAuthenticated = false
override suspend fun onActivated(): Nothing {
- coroutineScope {
- launch { super.onActivated() }
- launch {
- requests.receiveAsFlow().collect { request ->
- when (request) {
- is OnImeSwitcherButtonClicked -> {
- inputMethodInteractor.showInputMethodPicker(
- displayId = request.displayId,
- showAuxiliarySubtypes = false,
- )
- }
- is OnImeDismissed -> {
- interactor.onImeHiddenByUser()
+ try {
+ coroutineScope {
+ launch { super.onActivated() }
+ launch {
+ requests.receiveAsFlow().collect { request ->
+ when (request) {
+ is OnImeSwitcherButtonClicked -> {
+ inputMethodInteractor.showInputMethodPicker(
+ displayId = request.displayId,
+ showAuxiliarySubtypes = false,
+ )
+ }
+ is OnImeDismissed -> {
+ interactor.onImeHiddenByUser()
+ }
}
}
}
+ launch {
+ combine(isInputEnabled, isTextFieldFocused) { hasInput, hasFocus ->
+ hasInput && !hasFocus && !wasSuccessfullyAuthenticated
+ }
+ .collect { _isTextFieldFocusRequested.value = it }
+ }
+ launch {
+ selectedUserInteractor.selectedUser.collect { _selectedUserId.value = it }
+ }
+ launch {
+ // Re-fetch the currently-enabled IMEs whenever the selected user changes, and
+ // whenever
+ // the UI subscribes to the `isImeSwitcherButtonVisible` flow.
+ combine(
+ // InputMethodManagerService sometimes takes
+ // some time to update its internal state when the
+ // selected user changes.
+ // As a workaround, delay fetching the IME info.
+ selectedUserInteractor.selectedUser.onEach {
+ delay(DELAY_TO_FETCH_IMES)
+ },
+ _isImeSwitcherButtonVisible.onSubscriberAdded(),
+ ) { selectedUserId, _ ->
+ inputMethodInteractor.hasMultipleEnabledImesOrSubtypes(selectedUserId)
+ }
+ .collect { _isImeSwitcherButtonVisible.value = it }
+ }
+ awaitCancellation()
}
- launch {
- combine(isInputEnabled, isTextFieldFocused) { hasInput, hasFocus ->
- hasInput && !hasFocus
- }
- .collect { _isTextFieldFocusRequested.value = it }
- }
- launch { selectedUserInteractor.selectedUser.collect { _selectedUserId.value = it } }
- launch {
- // Re-fetch the currently-enabled IMEs whenever the selected user changes, and
- // whenever
- // the UI subscribes to the `isImeSwitcherButtonVisible` flow.
- combine(
- // InputMethodManagerService sometimes takes some time to update its
- // internal
- // state when the selected user changes. As a workaround, delay fetching the
- // IME
- // info.
- selectedUserInteractor.selectedUser.onEach { delay(DELAY_TO_FETCH_IMES) },
- _isImeSwitcherButtonVisible.onSubscriberAdded()
- ) { selectedUserId, _ ->
- inputMethodInteractor.hasMultipleEnabledImesOrSubtypes(selectedUserId)
- }
- .collect { _isImeSwitcherButtonVisible.value = it }
- }
- awaitCancellation()
+ } finally {
+ // reset whenever the view model is "deactivated"
+ wasSuccessfullyAuthenticated = false
}
}
@@ -141,6 +150,10 @@
return _password.value.toCharArray().toList()
}
+ override fun onSuccessfulAuthentication() {
+ wasSuccessfullyAuthenticated = true
+ }
+
/** Notifies that the user has changed the password input. */
fun onPasswordInputChanged(newPassword: String) {
if (newPassword.isNotEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index 769976e..ae4b679d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -282,6 +282,8 @@
return !mRecentKeyEvents.isEmpty();
}
+ // Deprecated in favor of {@code isTouchScreenSource}, b/329221787
+ @Deprecated
public boolean isFromTrackpad() {
if (Flags.nonTouchscreenDevicesBypassFalsing()) {
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index 6e01393..08a7c39 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -19,11 +19,13 @@
import android.provider.Settings
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.TransitionKey
+import com.android.internal.logging.UiEventLogger
import com.android.systemui.CoreStartable
import com.android.systemui.Flags.communalSceneKtfRefactor
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
+import com.android.systemui.communal.shared.log.CommunalUiEvent
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalTransitionKeys
import com.android.systemui.communal.shared.model.EditModeState
@@ -84,6 +86,7 @@
@Application private val applicationScope: CoroutineScope,
@Background private val bgScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
+ private val uiEventLogger: UiEventLogger,
) : CoreStartable {
private var screenTimeout: Int = DEFAULT_SCREEN_TIMEOUT
@@ -146,7 +149,7 @@
screenTimeout =
systemSettings.getInt(
Settings.System.SCREEN_OFF_TIMEOUT,
- DEFAULT_SCREEN_TIMEOUT
+ DEFAULT_SCREEN_TIMEOUT,
)
}
.launchIn(bgScope)
@@ -160,7 +163,7 @@
combine(
communalSceneInteractor.currentScene,
// Emit a value on start so the combine starts.
- communalInteractor.userActivity.emitOnStart()
+ communalInteractor.userActivity.emitOnStart(),
) { scene, _ ->
// Only timeout if we're on the hub is open.
scene == CommunalScenes.Communal
@@ -184,6 +187,7 @@
CommunalScenes.Blank,
"dream started after timeout",
)
+ uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT)
}
}
}
@@ -212,6 +216,7 @@
newScene = CommunalScenes.Blank,
loggingReason = "hub timeout",
)
+ uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT)
}
timeoutJob = null
}
@@ -219,7 +224,7 @@
}
private suspend fun determineSceneAfterTransition(
- lastStartedTransition: TransitionStep,
+ lastStartedTransition: TransitionStep
): Pair<SceneKey, TransitionKey>? {
val to = lastStartedTransition.to
val from = lastStartedTransition.from
@@ -251,9 +256,8 @@
Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
}
from == KeyguardState.DOZING && to == KeyguardState.GLANCEABLE_HUB -> {
- // Make sure the communal hub is showing (immediately, not fading in) when
- // transitioning from dozing to hub.
- Pair(CommunalScenes.Communal, CommunalTransitionKeys.Immediately)
+ // Make sure the communal hub is showing when transitioning from dozing to hub.
+ Pair(CommunalScenes.Communal, CommunalTransitionKeys.SimpleFade)
}
else -> null
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepository.kt
index f77dd58..f0f7ca5 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSmartspaceRepository.kt
@@ -82,19 +82,26 @@
}
_timers.value =
- timerTargets.map { (stableId, target) ->
- CommunalSmartspaceTimer(
- // The view layer should have the instance based smartspaceTargetId instead of
- // stable id, so that when a new instance of the timer is created, for example,
- // when it is paused, the view should re-render its remote views.
- smartspaceTargetId =
- if (communalTimerFlickerFix()) stableId else target.smartspaceTargetId,
- createdTimestampMillis = targetCreationTimes[stableId]!!,
- remoteViews = target.remoteViews!!,
- )
- }
-
- logger.d({ "Smartspace timers updated: $str1" }) { str1 = _timers.value.toString() }
+ timerTargets
+ .map { (stableId, target) ->
+ CommunalSmartspaceTimer(
+ // The view layer should have the instance based smartspaceTargetId instead
+ // of stable id, so that when a new instance of the timer is created, for
+ // example, when it is paused, the view should re-render its remote views.
+ smartspaceTargetId =
+ if (communalTimerFlickerFix()) stableId else target.smartspaceTargetId,
+ createdTimestampMillis = targetCreationTimes[stableId]!!,
+ remoteViews = target.remoteViews!!,
+ )
+ }
+ .also { newVal ->
+ // Only log when value changes to avoid filling up the buffer.
+ if (newVal != _timers.value) {
+ logger.d({ "Smartspace timers updated: $str1" }) {
+ str1 = newVal.toString()
+ }
+ }
+ }
}
override fun startListening() {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractor.kt
index 7453368..f7cd2ab 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractor.kt
@@ -16,10 +16,13 @@
package com.android.systemui.communal.domain.interactor
+import android.annotation.SuppressLint
import android.app.ActivityManager
+import android.app.DreamManager
import com.android.systemui.common.usagestats.domain.UsageStatsInteractor
import com.android.systemui.common.usagestats.shared.model.ActivityEventModel
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.log.LogBuffer
@@ -34,10 +37,12 @@
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.takeWhile
+import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withTimeout
@@ -56,6 +61,8 @@
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val taskStackChangeListeners: TaskStackChangeListeners,
private val usageStatsInteractor: UsageStatsInteractor,
+ private val dreamManager: DreamManager,
+ @Background private val bgScope: CoroutineScope,
@CommunalLog logBuffer: LogBuffer,
) {
private companion object {
@@ -127,13 +134,21 @@
* Checks if an activity starts while on the glanceable hub and dismisses the keyguard if it
* does. This can detect activities started due to broadcast trampolines from widgets.
*/
+ @SuppressLint("MissingPermission")
suspend fun waitForActivityStartAndDismissKeyguard() {
if (waitForActivityStartWhileOnHub()) {
logger.d("Detected trampoline, requesting unlock")
activityStarter.dismissKeyguardThenExecute(
- /* action= */ { false },
+ /* action= */ {
+ // Kill the dream when launching the trampoline activity. Right now the exit
+ // animation stalls when tapping the battery widget, and the dream remains
+ // visible until the transition hits some timeouts and gets cancelled.
+ // TODO(b/362841648): remove once exit animation is fixed.
+ bgScope.launch { dreamManager.stopDream() }
+ false
+ },
/* cancel= */ null,
- /* afterKeyguardGone= */ false
+ /* afterKeyguardGone= */ false,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
index 11fb233..78156db 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
@@ -30,6 +30,4 @@
val ToEditMode = TransitionKey("ToEditMode")
/** Transition to the glanceable hub after exiting edit mode */
val FromEditMode = TransitionKey("FromEditMode")
- /** Immediately transitions without any delay */
- val Immediately = TransitionKey("Immediately")
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 8f913ff..78a8a42 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -113,6 +113,7 @@
import android.view.inputmethod.InputMethodManager;
import android.view.textclassifier.TextClassificationManager;
+import androidx.annotation.NonNull;
import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
import androidx.core.app.NotificationManagerCompat;
@@ -718,6 +719,19 @@
@Provides
@Singleton
+ static ViewCaptureAwareWindowManager.Factory viewCaptureAwareWindowManagerFactory(
+ Lazy<ViewCapture> daggerLazyViewCapture) {
+ return new ViewCaptureAwareWindowManager.Factory() {
+ @NonNull
+ @Override
+ public ViewCaptureAwareWindowManager create(@NonNull WindowManager windowManager) {
+ return provideViewCaptureAwareWindowManager(windowManager, daggerLazyViewCapture);
+ }
+ };
+ }
+
+ @Provides
+ @Singleton
static PermissionManager providePermissionManager(Context context) {
PermissionManager pm = context.getSystemService(PermissionManager.class);
if (pm != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/HomeControlsDreamService.kt b/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/HomeControlsDreamService.kt
index 77c54ec..3992c3f 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/HomeControlsDreamService.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/HomeControlsDreamService.kt
@@ -39,6 +39,7 @@
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
class HomeControlsDreamService
@Inject
@@ -53,7 +54,7 @@
) : DreamService() {
private val serviceJob = SupervisorJob()
- private val serviceScope = CoroutineScope(bgDispatcher + serviceJob)
+ private val serviceScope = CoroutineScope(bgDispatcher + serviceJob + createCoroutineTracingContext("HomeControlsDreamService"))
private val logger = DreamLogger(logBuffer, TAG)
private lateinit var taskFragmentComponent: TaskFragmentComponent
private val wakeLock: WakeLock by lazy {
diff --git a/packages/SystemUI/src/com/android/systemui/education/dagger/ContextualEducationModule.kt b/packages/SystemUI/src/com/android/systemui/education/dagger/ContextualEducationModule.kt
index 7e2c9f8..4caf95b 100644
--- a/packages/SystemUI/src/com/android/systemui/education/dagger/ContextualEducationModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/dagger/ContextualEducationModule.kt
@@ -16,6 +16,7 @@
package com.android.systemui.education.dagger
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
import com.android.systemui.CoreStartable
import com.android.systemui.Flags
import com.android.systemui.contextualeducation.GestureType
@@ -56,7 +57,7 @@
fun provideEduDataStoreScope(
@Background bgDispatcher: CoroutineDispatcher
): CoroutineScope {
- return CoroutineScope(bgDispatcher + SupervisorJob())
+ return CoroutineScope(bgDispatcher + SupervisorJob() + createCoroutineTracingContext("EduDataStoreScope"))
}
@EduClock
diff --git a/packages/SystemUI/src/com/android/systemui/grid/ui/compose/SpannedGrids.kt b/packages/SystemUI/src/com/android/systemui/grid/ui/compose/SpannedGrids.kt
new file mode 100644
index 0000000..62ab18b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/grid/ui/compose/SpannedGrids.kt
@@ -0,0 +1,321 @@
+/*
+ * 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.grid.ui.compose
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.layout.Placeable
+import androidx.compose.ui.semantics.CollectionInfo
+import androidx.compose.ui.semantics.CollectionItemInfo
+import androidx.compose.ui.semantics.collectionInfo
+import androidx.compose.ui.semantics.collectionItemInfo
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
+import kotlin.math.max
+
+/**
+ * Horizontal (non lazy) grid that supports [spans] for its elements.
+ *
+ * The elements will be laid down vertically first, and then by columns. So assuming LTR layout, it
+ * will be (for a span list `[2, 1, 2, 1, 1, 1, 1, 1]` and 4 rows):
+ * ```
+ * 0 2 5
+ * 0 2 6
+ * 1 3 7
+ * 4
+ * ```
+ *
+ * where repeated numbers show larger span. If an element doesn't fit in a column due to its span,
+ * it will start a new column.
+ *
+ * Elements in [spans] must be in the interval `[1, rows]` ([rows] > 0), and the composables are
+ * associated with the corresponding span based on their index.
+ *
+ * Due to the fact that elements are seen as a linear list that's laid out in a grid, the semantics
+ * represent the collection as a list of elements.
+ */
+@Composable
+fun HorizontalSpannedGrid(
+ rows: Int,
+ columnSpacing: Dp,
+ rowSpacing: Dp,
+ spans: List<Int>,
+ modifier: Modifier = Modifier,
+ composables: @Composable BoxScope.(spanIndex: Int) -> Unit,
+) {
+ SpannedGrid(
+ primarySpaces = rows,
+ crossAxisSpacing = rowSpacing,
+ mainAxisSpacing = columnSpacing,
+ spans = spans,
+ isVertical = false,
+ modifier = modifier,
+ composables = composables,
+ )
+}
+
+/**
+ * Horizontal (non lazy) grid that supports [spans] for its elements.
+ *
+ * The elements will be laid down horizontally first, and then by rows. So assuming LTR layout, it
+ * will be (for a span list `[2, 1, 2, 1, 1, 1, 1, 1]` and 4 columns):
+ * ```
+ * 0 0 1
+ * 2 2 3 4
+ * 5 6 7
+ * ```
+ *
+ * where repeated numbers show larger span. If an element doesn't fit in a row due to its span, it
+ * will start a new row.
+ *
+ * Elements in [spans] must be in the interval `[1, columns]` ([columns] > 0), and the composables
+ * are associated with the corresponding span based on their index.
+ *
+ * Due to the fact that elements are seen as a linear list that's laid out in a grid, the semantics
+ * represent the collection as a list of elements.
+ */
+@Composable
+fun VerticalSpannedGrid(
+ columns: Int,
+ columnSpacing: Dp,
+ rowSpacing: Dp,
+ spans: List<Int>,
+ modifier: Modifier = Modifier,
+ composables: @Composable BoxScope.(spanIndex: Int) -> Unit,
+) {
+ SpannedGrid(
+ primarySpaces = columns,
+ crossAxisSpacing = columnSpacing,
+ mainAxisSpacing = rowSpacing,
+ spans = spans,
+ isVertical = true,
+ modifier = modifier,
+ composables = composables,
+ )
+}
+
+@Composable
+private fun SpannedGrid(
+ primarySpaces: Int,
+ crossAxisSpacing: Dp,
+ mainAxisSpacing: Dp,
+ spans: List<Int>,
+ isVertical: Boolean,
+ modifier: Modifier = Modifier,
+ composables: @Composable BoxScope.(spanIndex: Int) -> Unit,
+) {
+ val crossAxisArrangement = Arrangement.spacedBy(crossAxisSpacing)
+ spans.forEachIndexed { index, span ->
+ check(span in 1..primarySpaces) {
+ "Span out of bounds. Span at index $index has value of $span which is outside of the " +
+ "expected rance of [1, $primarySpaces]"
+ }
+ }
+
+ if (isVertical) {
+ check(crossAxisSpacing >= 0.dp) { "Negative columnSpacing $crossAxisSpacing" }
+ check(mainAxisSpacing >= 0.dp) { "Negative rowSpacing $mainAxisSpacing" }
+ } else {
+ check(mainAxisSpacing >= 0.dp) { "Negative columnSpacing $mainAxisSpacing" }
+ check(crossAxisSpacing >= 0.dp) { "Negative rowSpacing $crossAxisSpacing" }
+ }
+
+ val totalMainAxisGroups: Int =
+ remember(primarySpaces, spans) {
+ var currentAccumulated = 0
+ var groups = 1
+ spans.forEach { span ->
+ if (currentAccumulated + span <= primarySpaces) {
+ currentAccumulated += span
+ } else {
+ groups += 1
+ currentAccumulated = span
+ }
+ }
+ groups
+ }
+
+ val slotPositionsAndSizesCache = remember {
+ object {
+ var sizes = IntArray(0)
+ var positions = IntArray(0)
+ }
+ }
+
+ Layout(
+ {
+ (0 until spans.size).map { spanIndex ->
+ Box(
+ Modifier.semantics {
+ collectionItemInfo =
+ if (isVertical) {
+ CollectionItemInfo(spanIndex, 1, 0, 1)
+ } else {
+ CollectionItemInfo(0, 1, spanIndex, 1)
+ }
+ }
+ ) {
+ composables(spanIndex)
+ }
+ }
+ },
+ modifier.semantics { collectionInfo = CollectionInfo(spans.size, 1) },
+ ) { measurables, constraints ->
+ check(measurables.size == spans.size)
+ val crossAxisSize = if (isVertical) constraints.maxWidth else constraints.maxHeight
+ check(crossAxisSize != Constraints.Infinity) { "Width must be constrained" }
+ if (slotPositionsAndSizesCache.sizes.size != primarySpaces) {
+ slotPositionsAndSizesCache.sizes = IntArray(primarySpaces)
+ slotPositionsAndSizesCache.positions = IntArray(primarySpaces)
+ }
+ calculateCellsCrossAxisSize(
+ crossAxisSize,
+ primarySpaces,
+ crossAxisSpacing.roundToPx(),
+ slotPositionsAndSizesCache.sizes,
+ )
+ val cellSizesInCrossAxis = slotPositionsAndSizesCache.sizes
+
+ // with is needed because of the double receiver (Density, Arrangement).
+ with(crossAxisArrangement) {
+ arrange(
+ crossAxisSize,
+ slotPositionsAndSizesCache.sizes,
+ LayoutDirection.Ltr,
+ slotPositionsAndSizesCache.positions,
+ )
+ }
+ val startPositions = slotPositionsAndSizesCache.positions
+
+ val mainAxisSpacingPx = mainAxisSpacing.roundToPx()
+ val mainAxisTotalGaps = (totalMainAxisGroups - 1) * mainAxisSpacingPx
+ val mainAxisSize = if (isVertical) constraints.maxHeight else constraints.maxWidth
+ val mainAxisElementConstraint =
+ if (mainAxisSize == Constraints.Infinity) {
+ Constraints.Infinity
+ } else {
+ max(0, (mainAxisSize - mainAxisTotalGaps) / totalMainAxisGroups)
+ }
+
+ val mainAxisSizes = IntArray(totalMainAxisGroups) { 0 }
+
+ var currentSlot = 0
+ var mainAxisGroup = 0
+ val placeables =
+ measurables.mapIndexed { index, measurable ->
+ val span = spans[index]
+ if (currentSlot + span > primarySpaces) {
+ currentSlot = 0
+ mainAxisGroup += 1
+ }
+ val crossAxisConstraint =
+ calculateWidth(cellSizesInCrossAxis, startPositions, currentSlot, span)
+ PlaceResult(
+ measurable.measure(
+ makeConstraint(
+ isVertical,
+ mainAxisElementConstraint,
+ crossAxisConstraint,
+ )
+ ),
+ currentSlot,
+ mainAxisGroup,
+ )
+ .also {
+ currentSlot += span
+ mainAxisSizes[mainAxisGroup] =
+ max(
+ mainAxisSizes[mainAxisGroup],
+ if (isVertical) it.placeable.height else it.placeable.width,
+ )
+ }
+ }
+
+ val mainAxisTotalSize = mainAxisTotalGaps + mainAxisSizes.sum()
+ val mainAxisStartingPoints =
+ mainAxisSizes.runningFold(0) { acc, value -> acc + value + mainAxisSpacingPx }
+ val height = if (isVertical) mainAxisTotalSize else crossAxisSize
+ val width = if (isVertical) crossAxisSize else mainAxisTotalSize
+
+ layout(width, height) {
+ placeables.forEach { (placeable, slot, mainAxisGroup) ->
+ val x =
+ if (isVertical) {
+ startPositions[slot]
+ } else {
+ mainAxisStartingPoints[mainAxisGroup]
+ }
+ val y =
+ if (isVertical) {
+ mainAxisStartingPoints[mainAxisGroup]
+ } else {
+ startPositions[slot]
+ }
+ placeable.placeRelative(x, y)
+ }
+ }
+ }
+}
+
+fun makeConstraint(isVertical: Boolean, mainAxisSize: Int, crossAxisSize: Int): Constraints {
+ return if (isVertical) {
+ Constraints(maxHeight = mainAxisSize, minWidth = crossAxisSize, maxWidth = crossAxisSize)
+ } else {
+ Constraints(maxWidth = mainAxisSize, minHeight = crossAxisSize, maxHeight = crossAxisSize)
+ }
+}
+
+private fun calculateWidth(sizes: IntArray, positions: IntArray, startSlot: Int, span: Int): Int {
+ val crossAxisSize =
+ if (span == 1) {
+ sizes[startSlot]
+ } else {
+ val endSlot = startSlot + span - 1
+ positions[endSlot] + sizes[endSlot] - positions[startSlot]
+ }
+ .coerceAtLeast(0)
+ return crossAxisSize
+}
+
+private fun calculateCellsCrossAxisSize(
+ gridSize: Int,
+ slotCount: Int,
+ spacingPx: Int,
+ outArray: IntArray,
+) {
+ check(outArray.size == slotCount)
+ val gridSizeWithoutSpacing = gridSize - spacingPx * (slotCount - 1)
+ val slotSize = gridSizeWithoutSpacing / slotCount
+ val remainingPixels = gridSizeWithoutSpacing % slotCount
+ outArray.indices.forEach { index ->
+ outArray[index] = slotSize + if (index < remainingPixels) 1 else 0
+ }
+}
+
+private data class PlaceResult(
+ val placeable: Placeable,
+ val slotIndex: Int,
+ val mainAxisGroup: Int,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
index b271356..f32c94b 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
@@ -22,6 +22,7 @@
import androidx.annotation.RawRes
import androidx.annotation.StringRes
import androidx.compose.animation.AnimatedContent
+import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.core.LinearEasing
@@ -40,6 +41,7 @@
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@@ -67,21 +69,22 @@
enum class TutorialActionState {
NOT_STARTED,
IN_PROGRESS,
- FINISHED
+ FINISHED,
}
@Composable
fun ActionTutorialContent(
actionState: TutorialActionState,
onDoneButtonClicked: () -> Unit,
- config: TutorialScreenConfig
+ config: TutorialScreenConfig,
) {
Column(
verticalArrangement = Arrangement.Center,
modifier =
Modifier.fillMaxSize()
.background(config.colors.background)
- .padding(start = 48.dp, top = 124.dp, end = 48.dp, bottom = 48.dp)
+ .safeDrawingPadding()
+ .padding(start = 48.dp, top = 100.dp, end = 48.dp, bottom = 8.dp),
) {
Row(modifier = Modifier.fillMaxWidth().weight(1f)) {
TutorialDescription(
@@ -92,16 +95,18 @@
bodyTextId =
if (actionState == FINISHED) config.strings.bodySuccessResId
else config.strings.bodyResId,
- modifier = Modifier.weight(1f)
+ modifier = Modifier.weight(1f),
)
Spacer(modifier = Modifier.width(76.dp))
TutorialAnimation(
actionState,
config,
- modifier = Modifier.weight(1f).padding(top = 8.dp)
+ modifier = Modifier.weight(1f).padding(top = 8.dp),
)
}
- DoneButton(onDoneButtonClicked = onDoneButtonClicked)
+ AnimatedVisibility(visible = actionState == FINISHED, enter = fadeIn()) {
+ DoneButton(onDoneButtonClicked = onDoneButtonClicked)
+ }
}
}
@@ -110,19 +115,19 @@
@StringRes titleTextId: Int,
titleColor: Color,
@StringRes bodyTextId: Int,
- modifier: Modifier = Modifier
+ modifier: Modifier = Modifier,
) {
Column(verticalArrangement = Arrangement.Top, modifier = modifier) {
Text(
text = stringResource(id = titleTextId),
style = MaterialTheme.typography.displayLarge,
- color = titleColor
+ color = titleColor,
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = stringResource(id = bodyTextId),
style = MaterialTheme.typography.bodyLarge,
- color = Color.White
+ color = Color.White,
)
}
}
@@ -131,7 +136,7 @@
fun TutorialAnimation(
actionState: TutorialActionState,
config: TutorialScreenConfig,
- modifier: Modifier = Modifier
+ modifier: Modifier = Modifier,
) {
Box(modifier = modifier.fillMaxWidth()) {
AnimatedContent(
@@ -152,18 +157,18 @@
// state which shares initial animation frame with both FINISHED and NOT_STARTED
EnterTransition.None togetherWith ExitTransition.None
}
- }
+ },
) { state ->
when (state) {
NOT_STARTED ->
EducationAnimation(
config.animations.educationResId,
- config.colors.animationColors
+ config.colors.animationColors,
)
IN_PROGRESS ->
FrozenSuccessAnimation(
config.animations.successResId,
- config.colors.animationColors
+ config.colors.animationColors,
)
FINISHED ->
SuccessAnimation(config.animations.successResId, config.colors.animationColors)
@@ -175,7 +180,7 @@
@Composable
private fun FrozenSuccessAnimation(
@RawRes successAnimationId: Int,
- animationProperties: LottieDynamicProperties
+ animationProperties: LottieDynamicProperties,
) {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(successAnimationId))
LottieAnimation(
@@ -188,7 +193,7 @@
@Composable
private fun EducationAnimation(
@RawRes educationAnimationId: Int,
- animationProperties: LottieDynamicProperties
+ animationProperties: LottieDynamicProperties,
) {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(educationAnimationId))
val progress by
@@ -203,7 +208,7 @@
@Composable
private fun SuccessAnimation(
@RawRes successAnimationId: Int,
- animationProperties: LottieDynamicProperties
+ animationProperties: LottieDynamicProperties,
) {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(successAnimationId))
val progress by animateLottieCompositionAsState(composition, iterations = 1)
@@ -217,13 +222,13 @@
@Composable
fun rememberColorFilterProperty(
layerName: String,
- color: Color
+ color: Color,
): LottieDynamicProperty<ColorFilter> {
return rememberLottieDynamicProperty(
LottieProperty.COLOR_FILTER,
value = PorterDuffColorFilter(color.toArgb(), PorterDuff.Mode.SRC_ATOP),
// "**" below means match zero or more layers, so ** layerName ** means find layer with that
// name at any depth
- keyPath = arrayOf("**", layerName, "**")
+ keyPath = arrayOf("**", layerName, "**"),
)
}
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 4bf552e0..93cd1cf4 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
@@ -36,6 +36,7 @@
import androidx.compose.foundation.layout.FlowRowScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@@ -71,8 +72,6 @@
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
-import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass
-import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -116,7 +115,6 @@
import androidx.compose.ui.util.fastForEachIndexed
import androidx.compose.ui.zIndex
import com.android.compose.ui.graphics.painter.rememberDrawablePainter
-import com.android.compose.windowsizeclass.LocalWindowSizeClass
import com.android.systemui.keyboard.shortcut.shared.model.Shortcut
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
@@ -188,10 +186,7 @@
}
}
-@Composable
-private fun shouldUseSinglePane() =
- LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Compact ||
- LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Compact
+@Composable private fun shouldUseSinglePane() = hasCompactWindowSize()
@Composable
private fun ShortcutHelperSinglePane(
@@ -425,7 +420,7 @@
onKeyboardSettingsClicked: () -> Unit,
) {
val selectedCategory = categories.fastFirstOrNull { it.type == selectedCategoryType }
- Column(modifier = modifier.fillMaxSize().padding(start = 24.dp, end = 24.dp, top = 26.dp)) {
+ Column(modifier = modifier.fillMaxSize().padding(horizontal = 24.dp)) {
TitleBar()
Spacer(modifier = Modifier.height(12.dp))
Row(Modifier.fillMaxWidth()) {
@@ -801,6 +796,8 @@
style = MaterialTheme.typography.headlineSmall,
)
},
+ windowInsets = WindowInsets(top = 0.dp, bottom = 0.dp, left = 0.dp, right = 0.dp),
+ expandedHeight = 64.dp,
)
}
@@ -835,6 +832,7 @@
onSearch = {},
leadingIcon = { Icon(Icons.Default.Search, contentDescription = null) },
placeholder = { Text(text = stringResource(R.string.shortcut_helper_search_placeholder)) },
+ windowInsets = WindowInsets(top = 0.dp, bottom = 0.dp, left = 0.dp, right = 0.dp),
content = {},
)
}
@@ -847,9 +845,7 @@
shape = RoundedCornerShape(24.dp),
color = Color.Transparent,
modifier =
- Modifier.semantics { role = Role.Button }
- .fillMaxWidth()
- .padding(horizontal = 12.dp),
+ Modifier.semantics { role = Role.Button }.fillMaxWidth().padding(horizontal = 12.dp),
interactionSource = interactionSource,
interactionsConfig =
InteractionsConfig(
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt
new file mode 100644
index 0000000..1f0d696
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut.ui.composable
+
+import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass
+import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
+import androidx.compose.runtime.Composable
+import com.android.compose.windowsizeclass.LocalWindowSizeClass
+
+/**
+ * returns true if either size of the window is compact. This represents majority of phone windows
+ * portrait
+ */
+@Composable
+fun hasCompactWindowSize() =
+ LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Compact ||
+ LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Compact
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt
index 799999a..b9a16c4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt
@@ -18,31 +18,43 @@
import android.content.ActivityNotFoundException
import android.content.Intent
-import android.graphics.Insets
+import android.content.res.Configuration
import android.os.Bundle
import android.provider.Settings
-import android.view.View
-import android.view.WindowInsets
-import androidx.activity.BackEventCompat
import androidx.activity.ComponentActivity
-import androidx.activity.OnBackPressedCallback
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.ModalBottomSheet
+import androidx.compose.material3.Surface
+import androidx.compose.material3.rememberModalBottomSheetState
+import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
-import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.input.key.key
+import androidx.compose.ui.input.key.onKeyEvent
+import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
-import androidx.core.view.updatePadding
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.android.compose.theme.PlatformTheme
import com.android.systemui.keyboard.shortcut.ui.composable.ShortcutHelper
+import com.android.systemui.keyboard.shortcut.ui.composable.hasCompactWindowSize
import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutHelperViewModel
import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
-import com.android.systemui.util.dpToPx
-import com.google.android.material.bottomsheet.BottomSheetBehavior
-import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
-import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN
import javax.inject.Inject
import kotlinx.coroutines.launch
@@ -55,52 +67,58 @@
constructor(private val userTracker: UserTracker, private val viewModel: ShortcutHelperViewModel) :
ComponentActivity() {
- private val bottomSheetContainer
- get() = requireViewById<View>(R.id.shortcut_helper_sheet_container)
-
- private val bottomSheet
- get() = requireViewById<View>(R.id.shortcut_helper_sheet)
-
- private val bottomSheetBehavior
- get() = BottomSheetBehavior.from(bottomSheet)
-
override fun onCreate(savedInstanceState: Bundle?) {
setupEdgeToEdge()
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_keyboard_shortcut_helper)
- setUpWidth()
- expandBottomSheet()
- setUpInsets()
- setUpPredictiveBack()
- setUpSheetDismissListener()
- setUpDismissOnTouchOutside()
- setUpComposeView()
+ setContent { Content() }
observeFinishRequired()
viewModel.onViewOpened()
}
- private fun setUpWidth() {
- // we override this because when maxWidth isn't specified, material imposes a max width
- // constraint on bottom sheets on larger screens which is smaller than our desired width.
- bottomSheetBehavior.maxWidth =
- resources.getDimension(R.dimen.shortcut_helper_width).dpToPx(resources).toInt()
+ @Composable
+ private fun Content() {
+ CompositionLocalProvider(LocalContext provides userTracker.userContext) {
+ PlatformTheme { BottomSheet { finish() } }
+ }
}
- private fun setUpComposeView() {
- requireViewById<ComposeView>(R.id.shortcut_helper_compose_container).apply {
- setContent {
- CompositionLocalProvider(LocalContext provides userTracker.userContext) {
- PlatformTheme {
- val shortcutsUiState by
- viewModel.shortcutsUiState.collectAsStateWithLifecycle()
- ShortcutHelper(
- shortcutsUiState = shortcutsUiState,
- onKeyboardSettingsClicked = ::onKeyboardSettingsClicked,
- onSearchQueryChanged = { viewModel.onSearchQueryChanged(it) },
- )
- }
- }
- }
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Composable
+ private fun BottomSheet(onDismiss: () -> Unit) {
+ ModalBottomSheet(
+ onDismissRequest = { onDismiss() },
+ modifier =
+ Modifier.width(getWidth()).padding(top = getTopPadding()).onKeyEvent {
+ if (it.key == Key.Escape) {
+ onDismiss()
+ true
+ } else false
+ },
+ sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
+ dragHandle = { DragHandle() },
+ ) {
+ val shortcutsUiState by viewModel.shortcutsUiState.collectAsStateWithLifecycle()
+ ShortcutHelper(
+ shortcutsUiState = shortcutsUiState,
+ onKeyboardSettingsClicked = ::onKeyboardSettingsClicked,
+ onSearchQueryChanged = { viewModel.onSearchQueryChanged(it) },
+ )
+ }
+ }
+
+ @Composable
+ fun DragHandle() {
+ val dragHandleContentDescription =
+ stringResource(id = R.string.shortcut_helper_content_description_drag_handle)
+ Surface(
+ modifier =
+ Modifier.padding(top = 16.dp, bottom = 6.dp).semantics {
+ contentDescription = dragHandleContentDescription
+ },
+ color = MaterialTheme.colorScheme.outlineVariant,
+ shape = MaterialTheme.shapes.extraLarge,
+ ) {
+ Box(Modifier.size(width = 32.dp, height = 4.dp))
}
}
@@ -139,81 +157,27 @@
window.setDecorFitsSystemWindows(false)
}
- private fun setUpInsets() {
- bottomSheetContainer.setOnApplyWindowInsetsListener { _, insets ->
- val safeDrawingInsets = insets.safeDrawing
- // Make sure the bottom sheet is not covered by the status bar.
- bottomSheetBehavior.maxHeight =
- windowManager.maximumWindowMetrics.bounds.height() - safeDrawingInsets.top
- // Make sure the contents inside of the bottom sheet are not hidden by system bars, or
- // cutouts.
- bottomSheet.updatePadding(
- left = safeDrawingInsets.left,
- right = safeDrawingInsets.right,
- bottom = safeDrawingInsets.bottom,
- )
- // The bottom sheet has to be expanded only after setting up insets, otherwise there is
- // a bug and it will not use full height.
- expandBottomSheet()
-
- // Return CONSUMED if you don't want want the window insets to keep passing
- // down to descendant views.
- WindowInsets.CONSUMED
- }
+ @Composable
+ private fun getTopPadding(): Dp {
+ return if (hasCompactWindowSize()) DefaultTopPadding else LargeScreenTopPadding
}
- private fun expandBottomSheet() {
- bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
- bottomSheetBehavior.skipCollapsed = true
- }
-
- private fun setUpPredictiveBack() {
- val onBackPressedCallback =
- object : OnBackPressedCallback(/* enabled= */ true) {
- override fun handleOnBackStarted(backEvent: BackEventCompat) {
- bottomSheetBehavior.startBackProgress(backEvent)
- }
-
- override fun handleOnBackProgressed(backEvent: BackEventCompat) {
- bottomSheetBehavior.updateBackProgress(backEvent)
- }
-
- override fun handleOnBackPressed() {
- bottomSheetBehavior.handleBackInvoked()
- }
-
- override fun handleOnBackCancelled() {
- bottomSheetBehavior.cancelBackProgress()
- }
+ @Composable
+ private fun getWidth(): Dp {
+ return if (hasCompactWindowSize()) {
+ DefaultWidth
+ } else
+ when (LocalConfiguration.current.orientation) {
+ Configuration.ORIENTATION_LANDSCAPE -> LargeScreenWidthLandscape
+ else -> LargeScreenWidthPortrait
}
- onBackPressedDispatcher.addCallback(
- owner = this,
- onBackPressedCallback = onBackPressedCallback,
- )
}
- private fun setUpSheetDismissListener() {
- bottomSheetBehavior.addBottomSheetCallback(
- object : BottomSheetCallback() {
- override fun onStateChanged(bottomSheet: View, newState: Int) {
- if (newState == STATE_HIDDEN) {
- finish()
- }
- }
-
- override fun onSlide(bottomSheet: View, slideOffset: Float) {}
- }
- )
- }
-
- private fun setUpDismissOnTouchOutside() {
- bottomSheetContainer.setOnClickListener { finish() }
+ companion object {
+ private val DefaultTopPadding = 64.dp
+ private val LargeScreenTopPadding = 72.dp
+ private val DefaultWidth = 412.dp
+ private val LargeScreenWidthPortrait = 704.dp
+ private val LargeScreenWidthLandscape = 864.dp
}
}
-
-private val WindowInsets.safeDrawing
- get() =
- getInsets(WindowInsets.Type.systemBars())
- .union(getInsets(WindowInsets.Type.displayCutout()))
-
-private fun Insets.union(insets: Insets): Insets = Insets.max(this, insets)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 1a0525d..ba23eb3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -346,6 +346,7 @@
private boolean mShuttingDown;
private boolean mDozing;
private boolean mAnimatingScreenOff;
+ private boolean mIgnoreDismiss;
private final Context mContext;
private final FalsingCollector mFalsingCollector;
@@ -627,18 +628,20 @@
public void onUserSwitching(int userId) {
Log.d(TAG, String.format("onUserSwitching %d", userId));
synchronized (KeyguardViewMediator.this) {
+ mIgnoreDismiss = true;
notifyTrustedChangedLocked(mUpdateMonitor.getUserHasTrust(userId));
resetKeyguardDonePendingLocked();
- dismiss(null /* callback */, null /* message */);
+ resetStateLocked();
adjustStatusBarLocked();
}
}
@Override
public void onUserSwitchComplete(int userId) {
+ mIgnoreDismiss = false;
Log.d(TAG, String.format("onUserSwitchComplete %d", userId));
- // We are calling dismiss again and with a delay as there are race conditions
- // in some scenarios caused by async layout listeners
+ // We are calling dismiss with a delay as there are race conditions in some scenarios
+ // caused by async layout listeners
mHandler.postDelayed(() -> dismiss(null /* callback */, null /* message */), 500);
}
@@ -2442,6 +2445,10 @@
}
public void dismiss(IKeyguardDismissCallback callback, CharSequence message) {
+ if (mIgnoreDismiss) {
+ android.util.Log.i(TAG, "Ignoring request to dismiss (user switch in progress?)");
+ return;
+ }
mHandler.obtainMessage(DISMISS, new DismissMessage(callback, message)).sendToTarget();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index 80a0cee..b0820a7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -24,7 +24,6 @@
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.shared.model.CommunalScenes
-import com.android.systemui.communal.shared.model.CommunalTransitionKeys
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -95,10 +94,7 @@
scope.launch {
powerInteractor.isAwake
.filterRelevantKeyguardStateAnd { isAwake -> isAwake }
- .sample(
- keyguardInteractor.biometricUnlockState,
- ::Pair,
- )
+ .sample(keyguardInteractor.biometricUnlockState, ::Pair)
.collect {
(
_,
@@ -203,21 +199,21 @@
if (!SceneContainerFlag.isEnabled) {
startTransitionTo(
KeyguardState.GONE,
- ownerReason = "waking from dozing"
+ ownerReason = "waking from dozing",
)
}
} else if (primaryBouncerShowing) {
if (!SceneContainerFlag.isEnabled) {
startTransitionTo(
KeyguardState.PRIMARY_BOUNCER,
- ownerReason = "waking from dozing"
+ ownerReason = "waking from dozing",
)
}
} else if (isIdleOnCommunal && !communalSceneKtfRefactor()) {
if (!SceneContainerFlag.isEnabled) {
startTransitionTo(
KeyguardState.GLANCEABLE_HUB,
- ownerReason = "waking from dozing"
+ ownerReason = "waking from dozing",
)
}
} else if (isCommunalAvailable && dreamManager.canStartDreaming(true)) {
@@ -227,7 +223,7 @@
} else {
startTransitionTo(
KeyguardState.LOCKSCREEN,
- ownerReason = "waking from dozing"
+ ownerReason = "waking from dozing",
)
}
}
@@ -237,11 +233,9 @@
private suspend fun transitionToGlanceableHub() {
if (communalSceneKtfRefactor()) {
- communalSceneInteractor.changeScene(
+ communalSceneInteractor.snapToScene(
newScene = CommunalScenes.Communal,
loggingReason = "from dozing to hub",
- // Immediately show the hub when transitioning from dozing to hub.
- transitionKey = CommunalTransitionKeys.Immediately,
)
} else {
startTransitionTo(KeyguardState.GLANCEABLE_HUB)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
index 199caa1..7759298 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
@@ -162,10 +162,9 @@
.filterRelevantKeyguardStateAnd { isAsleep -> isAsleep }
.collect {
if (communalSceneKtfRefactor()) {
- communalSceneInteractor.changeScene(
+ communalSceneInteractor.snapToScene(
newScene = CommunalScenes.Blank,
loggingReason = "hub to dozing",
- transitionKey = CommunalTransitionKeys.Immediately,
keyguardState = KeyguardState.DOZING,
)
} else {
@@ -210,12 +209,12 @@
// ends, to avoid transitioning to OCCLUDED erroneously when exiting
// the dream.
.debounce(100.milliseconds),
- ::Pair
+ ::Pair,
)
.sampleFilter(
// When launching activities from widgets on the hub, we have a
// custom occlusion animation.
- communalSceneInteractor.isLaunchingWidget,
+ communalSceneInteractor.isLaunchingWidget
) { launchingWidget ->
!launchingWidget
}
@@ -253,7 +252,7 @@
noneOf(
// When launching activities from widgets on the hub, we wait to change
// scenes until the activity launch is complete.
- communalSceneInteractor.isLaunchingWidget,
+ communalSceneInteractor.isLaunchingWidget
),
)
.filterRelevantKeyguardStateAnd { isKeyguardGoingAway -> isKeyguardGoingAway }
@@ -270,7 +269,7 @@
newScene = CommunalScenes.Blank,
loggingReason = "hub to gone",
transitionKey = CommunalTransitionKeys.SimpleFade,
- keyguardState = KeyguardState.GONE
+ keyguardState = KeyguardState.GONE,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
index eb9b07a..ea80911 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
@@ -65,6 +65,7 @@
powerInteractor: PowerInteractor,
alternateBouncerInteractor: AlternateBouncerInteractor,
shadeInteractor: Lazy<ShadeInteractor>,
+ keyguardInteractor: Lazy<KeyguardInteractor>,
) {
val dismissAction: Flow<DismissAction> = repository.dismissAction
@@ -111,9 +112,9 @@
} else if (ComposeBouncerFlags.isOnlyComposeBouncerEnabled()) {
combine(
shadeInteractor.get().isAnyExpanded,
- deviceUnlockedInteractor.get().deviceUnlockStatus,
- ) { isAnyExpanded, deviceUnlockStatus ->
- isAnyExpanded && deviceUnlockStatus.isUnlocked
+ keyguardInteractor.get().isKeyguardDismissible,
+ ) { isAnyExpanded, keyguardDismissible ->
+ isAnyExpanded && keyguardDismissible
}
} else {
flow {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index deb0b2d..b5f6b41 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -261,7 +261,10 @@
->
if (biometricMessage?.message != null) {
chipbarCoordinator!!.displayView(
- createChipbarInfo(biometricMessage.message, R.drawable.ic_lock)
+ createChipbarInfo(
+ biometricMessage.message,
+ R.drawable.ic_lock,
+ )
)
} else {
chipbarCoordinator!!.removeView(ID, "occludingAppMsgNull")
@@ -324,16 +327,12 @@
.getDimensionPixelSize(R.dimen.shelf_appear_translation)
.stateIn(this)
viewModel.isNotifIconContainerVisible.collect { isVisible ->
- if (isVisible.value) {
- blueprintViewModel.refreshBlueprint()
- } else {
- childViews[aodNotificationIconContainerId]
- ?.setAodNotifIconContainerIsVisible(
- isVisible,
- iconsAppearTranslationPx.value,
- screenOffAnimationController,
- )
- }
+ childViews[aodNotificationIconContainerId]
+ ?.setAodNotifIconContainerIsVisible(
+ isVisible,
+ iconsAppearTranslationPx.value,
+ screenOffAnimationController,
+ )
}
}
@@ -383,7 +382,7 @@
if (msdlFeedback()) {
msdlPlayer?.playToken(
MSDLToken.UNLOCK,
- authInteractionProperties,
+ authInteractionProperties
)
} else {
vibratorHelper.performHapticFeedback(
@@ -399,7 +398,7 @@
if (msdlFeedback()) {
msdlPlayer?.playToken(
MSDLToken.FAILURE,
- authInteractionProperties,
+ authInteractionProperties
)
} else {
vibratorHelper.performHapticFeedback(
@@ -426,7 +425,7 @@
blueprintViewModel,
clockViewModel,
childViews,
- burnInParams,
+ burnInParams
)
)
@@ -465,7 +464,11 @@
*/
private fun createChipbarInfo(message: String, @DrawableRes icon: Int): ChipbarInfo {
return ChipbarInfo(
- startIcon = TintedIcon(Icon.Resource(icon, null), ChipbarInfo.DEFAULT_ICON_TINT),
+ startIcon =
+ TintedIcon(
+ Icon.Resource(icon, null),
+ ChipbarInfo.DEFAULT_ICON_TINT,
+ ),
text = Text.Loaded(message),
endItem = null,
vibrationEffect = null,
@@ -496,7 +499,7 @@
oldLeft: Int,
oldTop: Int,
oldRight: Int,
- oldBottom: Int,
+ oldBottom: Int
) {
// After layout, ensure the notifications are positioned correctly
childViews[nsslPlaceholderId]?.let { notificationListPlaceholder ->
@@ -512,7 +515,7 @@
viewModel.onNotificationContainerBoundsChanged(
notificationListPlaceholder.top.toFloat(),
notificationListPlaceholder.bottom.toFloat(),
- animate = shouldAnimate,
+ animate = shouldAnimate
)
}
@@ -528,7 +531,7 @@
Int.MAX_VALUE
} else {
view.getTop()
- },
+ }
)
}
} else {
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 0b8f741..cef9a4e 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
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.ui.preview
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
import android.app.WallpaperColors
import android.content.BroadcastReceiver
import android.content.Context
@@ -187,7 +188,7 @@
private var themeStyle: Style? = null
init {
- coroutineScope = CoroutineScope(applicationScope.coroutineContext + Job())
+ coroutineScope = CoroutineScope(applicationScope.coroutineContext + Job() + createCoroutineTracingContext("KeyguardPreviewRenderer"))
disposables += DisposableHandle { coroutineScope.cancel() }
clockController.setFallbackWeatherData(WeatherData.getPlaceholderWeatherData())
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
index 4cf3c4e..c6efcfa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
@@ -25,18 +25,20 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config
-import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
-data class TransitionData(val config: Config, val start: Long = System.currentTimeMillis())
+data class TransitionData(
+ val config: Config,
+ val start: Long = System.currentTimeMillis(),
+)
class KeyguardBlueprintViewModel
@Inject
constructor(
@Main private val handler: Handler,
- private val keyguardBlueprintInteractor: KeyguardBlueprintInteractor,
+ keyguardBlueprintInteractor: KeyguardBlueprintInteractor,
) {
val blueprint = keyguardBlueprintInteractor.blueprint
val blueprintId = keyguardBlueprintInteractor.blueprintId
@@ -74,9 +76,6 @@
}
}
- fun refreshBlueprint(type: Type = Type.NoTransition) =
- keyguardBlueprintInteractor.refreshBlueprint(type)
-
fun updateTransitions(data: TransitionData?, mutate: MutableSet<Transition>.() -> Unit) {
runningTransitions.mutate()
@@ -96,7 +95,7 @@
Log.w(
TAG,
"runTransition: skipping ${transition::class.simpleName}: " +
- "currentPriority=$currentPriority; config=$config",
+ "currentPriority=$currentPriority; config=$config"
)
}
apply()
@@ -107,7 +106,7 @@
Log.i(
TAG,
"runTransition: running ${transition::class.simpleName}: " +
- "currentPriority=$currentPriority; config=$config",
+ "currentPriority=$currentPriority; config=$config"
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
index c2b5d98..5559698 100644
--- a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
+++ b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
@@ -26,7 +26,7 @@
import androidx.lifecycle.LifecycleRegistry
import androidx.lifecycle.lifecycleScope
import com.android.app.tracing.coroutines.createCoroutineTracingContext
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.traceCoroutine
import com.android.systemui.Flags.coroutineTracing
import com.android.systemui.util.Assert
import com.android.systemui.util.Compile
@@ -45,6 +45,7 @@
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.launch
/**
* Runs the given [block] every time the [View] becomes attached (or immediately after calling this
@@ -137,7 +138,7 @@
): ViewLifecycleOwner {
return ViewLifecycleOwner(view).apply {
onCreate()
- lifecycleScope.launch(nameForTrace, coroutineContext) { block(view) }
+ lifecycleScope.launch(coroutineContext) { traceCoroutine(nameForTrace) { block(view) } }
}
}
@@ -367,7 +368,8 @@
* an extension function, and plumbing dagger-injected instances for static usage has little
* benefit.
*/
-private val MAIN_DISPATCHER_SINGLETON = Dispatchers.Main + createCoroutineTracingContext()
+private val MAIN_DISPATCHER_SINGLETON =
+ Dispatchers.Main + createCoroutineTracingContext("RepeatWhenAttached")
private const val DEFAULT_TRACE_NAME = "repeatWhenAttached"
private const val CURRENT_CLASS_NAME = "com.android.systemui.lifecycle.RepeatWhenAttachedKt"
private const val JAVA_ADAPTER_CLASS_NAME = "com.android.systemui.util.kotlin.JavaAdapterKt"
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt
index 130868d..1f339dd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt
@@ -33,6 +33,7 @@
import com.android.systemui.media.controls.data.repository.MediaFilterRepository
import com.android.systemui.media.controls.domain.pipeline.MediaDataProcessor
import com.android.systemui.media.controls.domain.pipeline.getNotificationActions
+import com.android.systemui.media.controls.shared.MediaLogger
import com.android.systemui.media.controls.shared.model.MediaControlModel
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.util.MediaSmartspaceLogger
@@ -59,6 +60,7 @@
private val lockscreenUserManager: NotificationLockscreenUserManager,
private val mediaOutputDialogManager: MediaOutputDialogManager,
private val broadcastDialogController: BroadcastDialogController,
+ private val mediaLogger: MediaLogger,
) {
val mediaControl: Flow<MediaControlModel?> =
@@ -73,7 +75,7 @@
instanceId: InstanceId,
delayMs: Long,
eventId: Int,
- location: Int
+ location: Int,
): Boolean {
logSmartspaceUserEvent(eventId, location)
val dismissed =
@@ -81,7 +83,7 @@
if (!dismissed) {
Log.w(
TAG,
- "Manager failed to dismiss media of instanceId=$instanceId, Token uid=${token?.uid}"
+ "Manager failed to dismiss media of instanceId=$instanceId, Token uid=${token?.uid}",
)
}
return dismissed
@@ -120,20 +122,20 @@
expandable: Expandable,
clickIntent: PendingIntent,
eventId: Int,
- location: Int
+ location: Int,
) {
logSmartspaceUserEvent(eventId, location)
- if (!launchOverLockscreen(clickIntent)) {
+ if (!launchOverLockscreen(expandable, clickIntent)) {
activityStarter.postStartActivityDismissingKeyguard(
clickIntent,
- expandable.activityTransitionController(Cuj.CUJ_SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER)
+ expandable.activityTransitionController(Cuj.CUJ_SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER),
)
}
}
fun startDeviceIntent(deviceIntent: PendingIntent) {
if (deviceIntent.isActivity) {
- if (!launchOverLockscreen(deviceIntent)) {
+ if (!launchOverLockscreen(expandable = null, deviceIntent)) {
activityStarter.postStartActivityDismissingKeyguard(deviceIntent)
}
} else {
@@ -141,20 +143,33 @@
}
}
- private fun launchOverLockscreen(pendingIntent: PendingIntent): Boolean {
+ private fun launchOverLockscreen(
+ expandable: Expandable?,
+ pendingIntent: PendingIntent,
+ ): Boolean {
val showOverLockscreen =
keyguardStateController.isShowing &&
activityIntentHelper.wouldPendingShowOverLockscreen(
pendingIntent,
- lockscreenUserManager.currentUserId
+ lockscreenUserManager.currentUserId,
)
if (showOverLockscreen) {
try {
- val options = BroadcastOptions.makeBasic()
- options.isInteractive = true
- options.pendingIntentBackgroundActivityStartMode =
- ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
- pendingIntent.send(options.toBundle())
+ if (expandable != null) {
+ activityStarter.startPendingIntentMaybeDismissingKeyguard(
+ pendingIntent,
+ /* intentSentUiThreadCallback = */ null,
+ expandable.activityTransitionController(
+ Cuj.CUJ_SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER
+ ),
+ )
+ } else {
+ val options = BroadcastOptions.makeBasic()
+ options.isInteractive = true
+ options.pendingIntentBackgroundActivityStartMode =
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+ pendingIntent.send(options.toBundle())
+ }
} catch (e: PendingIntent.CanceledException) {
Log.e(TAG, "pending intent of $instanceId was canceled")
}
@@ -166,7 +181,7 @@
fun startMediaOutputDialog(
expandable: Expandable,
packageName: String,
- token: MediaSession.Token? = null
+ token: MediaSession.Token? = null,
) {
mediaOutputDialogManager.createAndShowWithController(
packageName,
@@ -180,7 +195,7 @@
broadcastDialogController.createBroadcastDialogWithController(
broadcastApp,
packageName,
- expandable.dialogTransitionController()
+ expandable.dialogTransitionController(),
)
}
@@ -188,10 +203,14 @@
repository.logSmartspaceCardUserEvent(
eventId,
MediaSmartspaceLogger.getSurface(location),
- instanceId = instanceId
+ instanceId = instanceId,
)
}
+ fun logMediaControlIsBound(artistName: CharSequence, songName: CharSequence) {
+ mediaLogger.logMediaControlIsBound(instanceId, artistName, songName)
+ }
+
private fun Expandable.dialogController(): DialogTransitionAnimator.Controller? {
return dialogTransitionController(
cuj =
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaLogger.kt
index 7d20e17..88c47ba 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaLogger.kt
@@ -36,7 +36,7 @@
bool1 = active
str2 = reason
},
- { "add media $str1, active: $bool1, reason: $str2" }
+ { "add media $str1, active: $bool1, reason: $str2" },
)
}
@@ -48,7 +48,7 @@
str1 = instanceId.toString()
str2 = reason
},
- { "removing media $str1, reason: $str2" }
+ { "removing media $str1, reason: $str2" },
)
}
@@ -61,7 +61,7 @@
bool1 = isActive
str2 = reason
},
- { "add recommendation $str1, active $bool1, reason: $str2" }
+ { "add recommendation $str1, active $bool1, reason: $str2" },
)
}
@@ -74,7 +74,7 @@
bool1 = immediately
str2 = reason
},
- { "removing recommendation $str1, immediate=$bool1, reason: $str2" }
+ { "removing recommendation $str1, immediate=$bool1, reason: $str2" },
)
}
@@ -83,7 +83,7 @@
TAG,
LogLevel.DEBUG,
{ str1 = instanceId.toString() },
- { "adding media card $str1 to carousel" }
+ { "adding media card $str1 to carousel" },
)
}
@@ -92,7 +92,7 @@
TAG,
LogLevel.DEBUG,
{ str1 = instanceId.toString() },
- { "removing media card $str1 from carousel" }
+ { "removing media card $str1 from carousel" },
)
}
@@ -101,7 +101,7 @@
TAG,
LogLevel.DEBUG,
{ str1 = key },
- { "adding recommendation card $str1 to carousel" }
+ { "adding recommendation card $str1 to carousel" },
)
}
@@ -110,7 +110,7 @@
TAG,
LogLevel.DEBUG,
{ str1 = key },
- { "removing recommendation card $str1 from carousel" }
+ { "removing recommendation card $str1 from carousel" },
)
}
@@ -119,7 +119,24 @@
TAG,
LogLevel.DEBUG,
{ str1 = key },
- { "duplicate media notification $str1 posted" }
+ { "duplicate media notification $str1 posted" },
+ )
+ }
+
+ fun logMediaControlIsBound(
+ instanceId: InstanceId,
+ artistName: CharSequence,
+ title: CharSequence,
+ ) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = instanceId.toString()
+ str2 = artistName.toString()
+ str3 = title.toString()
+ },
+ { "binding media control, instance id= $str1, artist= $str2, title= $str3" },
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt
index 6373fed..7a6de5c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt
@@ -55,6 +55,7 @@
import com.android.systemui.media.controls.ui.viewmodel.MediaPlayerViewModel
import com.android.systemui.media.controls.util.MediaDataUtils
import com.android.systemui.monet.ColorScheme
+import com.android.systemui.monet.Style
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
import com.android.systemui.surfaceeffects.ripple.MultiRippleView
@@ -66,6 +67,8 @@
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
+private const val TAG = "MediaControlViewBinder"
+
object MediaControlViewBinder {
fun bind(
@@ -80,16 +83,19 @@
mediaCard.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
- viewModel.player.collectLatest { playerViewModel ->
- playerViewModel?.let {
- bindMediaCard(
- viewHolder,
- viewController,
- it,
- falsingManager,
- backgroundDispatcher,
- mainDispatcher,
- )
+ viewModel.player.collectLatest { player ->
+ player?.let {
+ if (viewModel.isNewPlayer(it)) {
+ bindMediaCard(
+ viewHolder,
+ viewController,
+ it,
+ falsingManager,
+ backgroundDispatcher,
+ mainDispatcher,
+ )
+ viewModel.onMediaControlIsBound(it.artistName, it.titleName)
+ }
}
}
}
@@ -143,7 +149,7 @@
viewHolder,
viewModel.outputSwitcher,
viewController,
- falsingManager
+ falsingManager,
)
bindGutsViewModel(viewHolder, viewModel, viewController, falsingManager)
bindActionButtons(viewHolder, viewModel, viewController, falsingManager)
@@ -157,7 +163,7 @@
viewController,
backgroundDispatcher,
mainDispatcher,
- isSongUpdated
+ isSongUpdated,
)
if (viewModel.playTurbulenceNoise) {
@@ -231,9 +237,6 @@
}
}
setDismissible(model.isDismissEnabled)
- setTextPrimaryColor(model.textPrimaryColor)
- setAccentPrimaryColor(model.accentPrimaryColor)
- setSurfaceColor(model.surfaceColor)
}
}
@@ -259,12 +262,12 @@
if (buttonView.id == R.id.actionPrev) {
viewController.setUpPrevButtonInfo(
buttonModel.isEnabled,
- buttonModel.notVisibleValue
+ buttonModel.notVisibleValue,
)
} else if (buttonView.id == R.id.actionNext) {
viewController.setUpNextButtonInfo(
buttonModel.isEnabled,
- buttonModel.notVisibleValue
+ buttonModel.notVisibleValue,
)
}
val animHandler = (buttonView.tag ?: AnimationBindHandler()) as AnimationBindHandler
@@ -295,7 +298,7 @@
viewController.collapsedLayout,
visible,
buttonModel.notVisibleValue,
- buttonModel.showInCollapsed
+ buttonModel.showInCollapsed,
)
}
}
@@ -350,7 +353,7 @@
createTouchRippleAnimation(
button,
viewController.colorSchemeTransition,
- multiRippleView
+ multiRippleView,
)
)
@@ -382,12 +385,12 @@
setVisibleAndAlpha(
expandedSet,
R.id.media_explicit_indicator,
- viewModel.isExplicitVisible
+ viewModel.isExplicitVisible,
)
setVisibleAndAlpha(
collapsedSet,
R.id.media_explicit_indicator,
- viewModel.isExplicitVisible
+ viewModel.isExplicitVisible,
)
// refreshState is required here to resize the text views (and prevent ellipsis)
@@ -398,7 +401,7 @@
// something is incorrectly bound, but needs to be run if other elements were
// updated while the enter animation was running
viewController.refreshState()
- }
+ },
)
}
@@ -420,22 +423,37 @@
val width = viewController.widthInSceneContainerPx
val height = viewController.heightInSceneContainerPx
withContext(backgroundDispatcher) {
+ val wallpaperColors =
+ MediaArtworkHelper.getWallpaperColor(
+ viewHolder.albumView.context,
+ backgroundDispatcher,
+ viewModel.backgroundCover,
+ TAG,
+ )
+ val isArtworkBound = wallpaperColors != null
+ val scheme =
+ wallpaperColors?.let { ColorScheme(it, true, Style.CONTENT) }
+ ?: let {
+ if (viewModel.launcherIcon is Icon.Loaded) {
+ MediaArtworkHelper.getColorScheme(viewModel.launcherIcon.drawable, TAG)
+ } else {
+ null
+ }
+ }
val artwork =
- if (viewModel.shouldAddGradient) {
+ wallpaperColors?.let {
addGradientToPlayerAlbum(
viewHolder.albumView.context,
viewModel.backgroundCover!!,
- viewModel.colorScheme,
+ scheme!!,
width,
- height
+ height,
)
- } else {
- ColorDrawable(Color.TRANSPARENT)
- }
+ } ?: ColorDrawable(Color.TRANSPARENT)
withContext(mainDispatcher) {
// Transition Colors to current color scheme
val colorSchemeChanged =
- viewController.colorSchemeTransition.updateColorScheme(viewModel.colorScheme)
+ viewController.colorSchemeTransition.updateColorScheme(scheme)
val albumView = viewHolder.albumView
// Set up width of album view constraint.
@@ -446,7 +464,7 @@
if (
updateBackground ||
colorSchemeChanged ||
- (!viewController.isArtworkBound && viewModel.shouldAddGradient)
+ (!viewController.isArtworkBound && isArtworkBound)
) {
viewController.prevArtwork?.let {
// Since we throw away the last transition, this will pop if your
@@ -461,12 +479,10 @@
transitionDrawable.isCrossFadeEnabled = true
albumView.setImageDrawable(transitionDrawable)
- transitionDrawable.startTransition(
- if (viewModel.shouldAddGradient) 333 else 80
- )
+ transitionDrawable.startTransition(if (isArtworkBound) 333 else 80)
} ?: albumView.setImageDrawable(artwork)
}
- viewController.isArtworkBound = viewModel.shouldAddGradient
+ viewController.isArtworkBound = isArtworkBound
viewController.prevArtwork = artwork
if (viewModel.useGrayColorFilter) {
@@ -493,7 +509,7 @@
transitionDrawable: TransitionDrawable,
layer: Int,
targetWidth: Int,
- targetHeight: Int
+ targetHeight: Int,
) {
val drawable = transitionDrawable.getDrawable(layer) ?: return
val width = drawable.intrinsicWidth
@@ -509,7 +525,7 @@
artworkIcon: android.graphics.drawable.Icon,
mutableColorScheme: ColorScheme,
width: Int,
- height: Int
+ height: Int,
): LayerDrawable {
val albumArt = MediaArtworkHelper.getScaledBackground(context, artworkIcon, width, height)
return MediaArtworkHelper.setUpGradientColorOnDrawable(
@@ -517,7 +533,7 @@
context.getDrawable(R.drawable.qs_media_scrim)?.mutate() as GradientDrawable,
mutableColorScheme,
MEDIA_PLAYER_SCRIM_START_ALPHA,
- MEDIA_PLAYER_SCRIM_END_ALPHA
+ MEDIA_PLAYER_SCRIM_END_ALPHA,
)
}
@@ -544,7 +560,7 @@
private fun createTouchRippleAnimation(
button: ImageButton,
colorSchemeTransition: ColorSchemeTransition,
- multiRippleView: MultiRippleView
+ multiRippleView: MultiRippleView,
): RippleAnimation {
val maxSize = (multiRippleView.width * 2).toFloat()
return RippleAnimation(
@@ -562,7 +578,7 @@
baseRingFadeParams = null,
sparkleRingFadeParams = null,
centerFillFadeParams = null,
- shouldDistort = false
+ shouldDistort = false,
)
)
}
@@ -596,7 +612,7 @@
set: ConstraintSet,
resId: Int,
visible: Boolean,
- notVisibleValue: Int
+ notVisibleValue: Int,
) {
set.setVisibility(resId, if (visible) ConstraintSet.VISIBLE else notVisibleValue)
set.setAlpha(resId, if (visible) 1.0f else 0.0f)
@@ -618,7 +634,7 @@
collapsedSet: ConstraintSet,
visible: Boolean,
notVisibleValue: Int,
- showInCollapsed: Boolean
+ showInCollapsed: Boolean,
) {
if (notVisibleValue == ConstraintSet.INVISIBLE) {
// Since time views should appear instead of buttons.
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaRecommendationsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaRecommendationsViewBinder.kt
index 5e8a879..8a04799 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaRecommendationsViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaRecommendationsViewBinder.kt
@@ -16,13 +16,24 @@
package com.android.systemui.media.controls.ui.binder
+import android.app.WallpaperColors
import android.content.Context
import android.content.res.ColorStateList
import android.content.res.Configuration
+import android.graphics.Bitmap
+import android.graphics.Color
import android.graphics.Matrix
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.graphics.drawable.Icon
+import android.graphics.drawable.LayerDrawable
+import android.os.Trace
import android.util.TypedValue
import android.view.View
import android.view.ViewGroup
+import androidx.appcompat.content.res.AppCompatResources
import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
@@ -30,17 +41,29 @@
import com.android.systemui.animation.Expandable
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.media.controls.shared.model.NUM_REQUIRED_RECOMMENDATIONS
+import com.android.systemui.media.controls.ui.animation.surfaceFromScheme
+import com.android.systemui.media.controls.ui.animation.textPrimaryFromScheme
+import com.android.systemui.media.controls.ui.animation.textSecondaryFromScheme
import com.android.systemui.media.controls.ui.controller.MediaViewController
+import com.android.systemui.media.controls.ui.util.MediaArtworkHelper
import com.android.systemui.media.controls.ui.view.RecommendationViewHolder
import com.android.systemui.media.controls.ui.viewmodel.MediaRecViewModel
import com.android.systemui.media.controls.ui.viewmodel.MediaRecommendationsViewModel
import com.android.systemui.media.controls.ui.viewmodel.MediaRecsCardViewModel
+import com.android.systemui.monet.ColorScheme
+import com.android.systemui.monet.Style
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
import com.android.systemui.util.animation.TransitionLayout
import kotlin.math.min
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+private const val TAG = "MediaRecommendationsViewBinder"
+private const val MEDIA_REC_SCRIM_START_ALPHA = 0.15f
+private const val MEDIA_REC_SCRIM_END_ALPHA = 1.0f
object MediaRecommendationsViewBinder {
@@ -50,6 +73,8 @@
viewModel: MediaRecommendationsViewModel,
mediaViewController: MediaViewController,
falsingManager: FalsingManager,
+ backgroundDispatcher: CoroutineDispatcher,
+ mainDispatcher: CoroutineDispatcher,
) {
mediaViewController.recsConfigurationChangeListener = this::updateRecommendationsVisibility
val cardView = viewHolder.recommendations
@@ -59,7 +84,14 @@
launch {
viewModel.mediaRecsCard.collectLatest { viewModel ->
viewModel?.let {
- bindRecsCard(viewHolder, it, mediaViewController, falsingManager)
+ bindRecsCard(
+ viewHolder,
+ it,
+ mediaViewController,
+ falsingManager,
+ backgroundDispatcher,
+ mainDispatcher,
+ )
}
}
}
@@ -68,19 +100,19 @@
}
}
- fun bindRecsCard(
+ suspend fun bindRecsCard(
viewHolder: RecommendationViewHolder,
viewModel: MediaRecsCardViewModel,
viewController: MediaViewController,
falsingManager: FalsingManager,
+ backgroundDispatcher: CoroutineDispatcher,
+ mainDispatcher: CoroutineDispatcher,
) {
// Set up media control location and its listener.
viewModel.onLocationChanged(viewController.currentEndLocation)
viewController.locationChangeListener = viewModel.onLocationChanged
// Bind main card.
- viewHolder.cardTitle.setTextColor(viewModel.cardTitleColor)
- viewHolder.recommendations.backgroundTintList = ColorStateList.valueOf(viewModel.cardColor)
viewHolder.recommendations.contentDescription =
viewModel.contentDescription.invoke(viewController.isGutsVisible)
@@ -100,8 +132,17 @@
return@setOnLongClickListener true
}
+ // Bind colors
+ val appIcon = viewModel.mediaRecs.first().appIcon
+ fetchAndUpdateColors(viewHolder, appIcon, backgroundDispatcher, mainDispatcher)
// Bind all recommendations.
- bindRecommendationsList(viewHolder, viewModel.mediaRecs, falsingManager)
+ bindRecommendationsList(
+ viewHolder,
+ viewModel.mediaRecs,
+ falsingManager,
+ backgroundDispatcher,
+ mainDispatcher,
+ )
updateRecommendationsVisibility(viewController, viewHolder.recommendations)
// Set visibility of recommendations.
@@ -153,26 +194,21 @@
}
gutsViewHolder.setDismissible(gutsViewModel.isDismissEnabled)
- gutsViewHolder.setTextPrimaryColor(gutsViewModel.textPrimaryColor)
- gutsViewHolder.setAccentPrimaryColor(gutsViewModel.accentPrimaryColor)
- gutsViewHolder.setSurfaceColor(gutsViewModel.surfaceColor)
}
- private fun bindRecommendationsList(
+ private suspend fun bindRecommendationsList(
viewHolder: RecommendationViewHolder,
mediaRecs: List<MediaRecViewModel>,
- falsingManager: FalsingManager
+ falsingManager: FalsingManager,
+ backgroundDispatcher: CoroutineDispatcher,
+ mainDispatcher: CoroutineDispatcher,
) {
mediaRecs.forEachIndexed { index, mediaRecViewModel ->
if (index >= NUM_REQUIRED_RECOMMENDATIONS) return@forEachIndexed
val appIconView = viewHolder.mediaAppIcons[index]
appIconView.clearColorFilter()
- if (mediaRecViewModel.appIcon != null) {
- appIconView.setImageDrawable(mediaRecViewModel.appIcon)
- } else {
- appIconView.setImageResource(R.drawable.ic_music_note)
- }
+ appIconView.setImageDrawable(mediaRecViewModel.appIcon)
val mediaCoverContainer = viewHolder.mediaCoverContainers[index]
mediaCoverContainer.setOnClickListener {
@@ -187,29 +223,24 @@
}
val mediaCover = viewHolder.mediaCoverItems[index]
- val width: Int =
- mediaCover.context.resources.getDimensionPixelSize(R.dimen.qs_media_rec_album_width)
- val height: Int =
- mediaCover.context.resources.getDimensionPixelSize(
- R.dimen.qs_media_rec_album_height_expanded
- )
- val coverMatrix = Matrix(mediaCover.imageMatrix)
- coverMatrix.postScale(1.25f, 1.25f, 0.5f * width, 0.5f * height)
- mediaCover.imageMatrix = coverMatrix
- mediaCover.setImageDrawable(mediaRecViewModel.albumIcon)
+ bindRecommendationArtwork(
+ mediaCover.context,
+ viewHolder,
+ mediaRecViewModel,
+ index,
+ backgroundDispatcher,
+ mainDispatcher,
+ )
mediaCover.contentDescription = mediaRecViewModel.contentDescription
val title = viewHolder.mediaTitles[index]
title.text = mediaRecViewModel.title
- title.setTextColor(ColorStateList.valueOf(mediaRecViewModel.titleColor))
val subtitle = viewHolder.mediaSubtitles[index]
subtitle.text = mediaRecViewModel.subtitle
- subtitle.setTextColor(ColorStateList.valueOf(mediaRecViewModel.subtitleColor))
val progressBar = viewHolder.mediaProgressBars[index]
progressBar.progress = mediaRecViewModel.progress
- progressBar.progressTintList = ColorStateList.valueOf(mediaRecViewModel.progressColor)
if (mediaRecViewModel.progress == 0) {
progressBar.visibility = View.GONE
}
@@ -291,11 +322,148 @@
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
displayAvailableDpWidth.toFloat(),
- res.displayMetrics
+ res.displayMetrics,
)
.toInt()
displayAvailableWidth / recCoverWidth
}
return min(fittedNum.toDouble(), NUM_REQUIRED_RECOMMENDATIONS.toDouble()).toInt()
}
+
+ private suspend fun bindRecommendationArtwork(
+ context: Context,
+ viewHolder: RecommendationViewHolder,
+ viewModel: MediaRecViewModel,
+ index: Int,
+ backgroundDispatcher: CoroutineDispatcher,
+ mainDispatcher: CoroutineDispatcher,
+ ) {
+ val traceCookie = viewHolder.hashCode()
+ val traceName = "MediaRecommendationsViewBinder#bindRecommendationArtwork"
+ Trace.beginAsyncSection(traceName, traceCookie)
+
+ // Capture width & height from views in foreground for artwork scaling in background
+ val width = context.resources.getDimensionPixelSize(R.dimen.qs_media_rec_album_width)
+ val height =
+ context.resources.getDimensionPixelSize(R.dimen.qs_media_rec_album_height_expanded)
+
+ withContext(backgroundDispatcher) {
+ val artwork =
+ getRecCoverBackground(
+ context,
+ viewModel.albumIcon,
+ width,
+ height,
+ backgroundDispatcher,
+ )
+ withContext(mainDispatcher) {
+ val mediaCover = viewHolder.mediaCoverItems[index]
+ val coverMatrix = Matrix(mediaCover.imageMatrix)
+ coverMatrix.postScale(1.25f, 1.25f, 0.5f * width, 0.5f * height)
+ mediaCover.imageMatrix = coverMatrix
+ mediaCover.setImageDrawable(artwork)
+ }
+ }
+ }
+
+ /** Returns the recommendation album cover of [width]x[height] size. */
+ private suspend fun getRecCoverBackground(
+ context: Context,
+ icon: Icon?,
+ width: Int,
+ height: Int,
+ backgroundDispatcher: CoroutineDispatcher,
+ ): Drawable =
+ withContext(backgroundDispatcher) {
+ return@withContext MediaArtworkHelper.getWallpaperColor(
+ context,
+ backgroundDispatcher,
+ icon,
+ TAG,
+ )
+ ?.let { wallpaperColors ->
+ addGradientToRecommendationAlbum(
+ context,
+ icon!!,
+ ColorScheme(wallpaperColors, true, Style.CONTENT),
+ width,
+ height,
+ )
+ } ?: ColorDrawable(Color.TRANSPARENT)
+ }
+
+ private fun addGradientToRecommendationAlbum(
+ context: Context,
+ artworkIcon: Icon,
+ mutableColorScheme: ColorScheme,
+ width: Int,
+ height: Int,
+ ): LayerDrawable {
+ // First try scaling rec card using bitmap drawable.
+ // If returns null, set drawable bounds.
+ val albumArt =
+ getScaledRecommendationCover(context, artworkIcon, width, height)
+ ?: MediaArtworkHelper.getScaledBackground(context, artworkIcon, width, height)
+ val gradient =
+ AppCompatResources.getDrawable(context, R.drawable.qs_media_rec_scrim)?.mutate()
+ as GradientDrawable
+ return MediaArtworkHelper.setUpGradientColorOnDrawable(
+ albumArt,
+ gradient,
+ mutableColorScheme,
+ MEDIA_REC_SCRIM_START_ALPHA,
+ MEDIA_REC_SCRIM_END_ALPHA,
+ )
+ }
+
+ /** Returns a [Drawable] of a given [artworkIcon] scaled to [width]x[height] size, . */
+ private fun getScaledRecommendationCover(
+ context: Context,
+ artworkIcon: Icon,
+ width: Int,
+ height: Int,
+ ): Drawable? {
+ check(width > 0) { "Width must be a positive number but was $width" }
+ check(height > 0) { "Height must be a positive number but was $height" }
+
+ return if (
+ artworkIcon.type == Icon.TYPE_BITMAP || artworkIcon.type == Icon.TYPE_ADAPTIVE_BITMAP
+ ) {
+ artworkIcon.bitmap?.let {
+ val bitmap = Bitmap.createScaledBitmap(it, width, height, false)
+ BitmapDrawable(context.resources, bitmap)
+ }
+ } else {
+ null
+ }
+ }
+
+ private suspend fun fetchAndUpdateColors(
+ viewHolder: RecommendationViewHolder,
+ appIcon: Drawable,
+ backgroundDispatcher: CoroutineDispatcher,
+ mainDispatcher: CoroutineDispatcher,
+ ) =
+ withContext(backgroundDispatcher) {
+ val colorScheme =
+ ColorScheme(WallpaperColors.fromDrawable(appIcon), /* darkTheme= */ true)
+ withContext(mainDispatcher) {
+ val backgroundColor = surfaceFromScheme(colorScheme)
+ val textPrimaryColor = textPrimaryFromScheme(colorScheme)
+ val textSecondaryColor = textSecondaryFromScheme(colorScheme)
+
+ viewHolder.cardTitle.setTextColor(textPrimaryColor)
+ viewHolder.recommendations.setBackgroundTintList(
+ ColorStateList.valueOf(backgroundColor)
+ )
+
+ viewHolder.mediaTitles.forEach { it.setTextColor(textPrimaryColor) }
+ viewHolder.mediaSubtitles.forEach { it.setTextColor(textSecondaryColor) }
+ viewHolder.mediaProgressBars.forEach {
+ it.progressTintList = ColorStateList.valueOf(textPrimaryColor)
+ }
+
+ viewHolder.gutsViewHolder.setColors(colorScheme)
+ }
+ }
}
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 8505a784..bb9517a 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
@@ -123,7 +123,7 @@
* Class that is responsible for keeping the view carousel up to date. This also handles changes in
* state and applies them to the media carousel like the expansion.
*/
-@ExperimentalCoroutinesApi
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class MediaCarouselController
@Inject
@@ -252,13 +252,13 @@
fun calculateAlpha(
squishinessFraction: Float,
startPosition: Float,
- endPosition: Float
+ endPosition: Float,
): Float {
val transformFraction =
MathUtils.constrain(
(squishinessFraction - startPosition) / (endPosition - startPosition),
0F,
- 1F
+ 1F,
)
return TRANSFORM_BEZIER.getInterpolation(transformFraction)
}
@@ -354,7 +354,7 @@
this::closeGuts,
falsingManager,
this::logSmartspaceImpression,
- logger
+ logger,
)
carouselLocale = context.resources.configuration.locales.get(0)
isRtl = context.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
@@ -387,7 +387,7 @@
object : MediaHostStatesManager.Callback {
override fun onHostStateChanged(
@MediaLocation location: Int,
- mediaHostState: MediaHostState
+ mediaHostState: MediaHostState,
) {
updateUserVisibility()
if (location == desiredLocation) {
@@ -412,7 +412,7 @@
bgExecutor.execute {
globalSettings.registerContentObserverSync(
Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
- animationScaleObserver
+ animationScaleObserver,
)
}
}
@@ -452,7 +452,7 @@
data: MediaData,
immediately: Boolean,
receivedSmartspaceCardLatency: Int,
- isSsReactivated: Boolean
+ isSsReactivated: Boolean,
) {
debugLogger.logMediaLoaded(key, data.active)
if (addOrUpdatePlayer(key, oldKey, data, isSsReactivated)) {
@@ -468,7 +468,7 @@
SSPACE_CARD_REPORTED__LOCKSCREEN,
SSPACE_CARD_REPORTED__DREAM_OVERLAY,
),
- rank = MediaPlayerData.getMediaPlayerIndex(key)
+ rank = MediaPlayerData.getMediaPlayerIndex(key),
)
}
if (
@@ -500,7 +500,7 @@
SSPACE_CARD_REPORTED__DREAM_OVERLAY,
),
rank = index,
- receivedLatencyMillis = receivedSmartspaceCardLatency
+ receivedLatencyMillis = receivedSmartspaceCardLatency,
)
}
}
@@ -533,7 +533,7 @@
override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceMediaData,
- shouldPrioritize: Boolean
+ shouldPrioritize: Boolean,
) {
debugLogger.logRecommendationLoaded(key, data.isActive)
// Log the case where the hidden media carousel with the existed inactive resume
@@ -568,7 +568,7 @@
receivedLatencyMillis =
(systemClock.currentTimeMillis() -
data.headphoneConnectionTimeMillis)
- .toInt()
+ .toInt(),
)
}
}
@@ -589,7 +589,7 @@
receivedLatencyMillis =
(systemClock.currentTimeMillis() -
data.headphoneConnectionTimeMillis)
- .toInt()
+ .toInt(),
)
}
if (
@@ -644,10 +644,7 @@
mediaCarouselScrollHandler.onSettingsButtonUpdated(settings)
settingsButton.setOnClickListener {
logger.logCarouselSettings()
- activityStarter.startActivity(
- settingsIntent,
- /* dismissShade= */ true,
- )
+ activityStarter.startActivity(settingsIntent, /* dismissShade= */ true)
}
}
@@ -739,7 +736,7 @@
val lp =
LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
+ ViewGroup.LayoutParams.WRAP_CONTENT,
)
when (commonViewModel) {
is MediaCommonViewModel.MediaControl -> {
@@ -771,6 +768,8 @@
commonViewModel.recsViewModel,
viewController,
falsingManager,
+ backgroundDispatcher,
+ mainDispatcher,
)
mediaContent.addView(viewHolder.recommendations, position)
controllerById[commonViewModel.key] = viewController
@@ -785,7 +784,7 @@
) {
mediaCarouselScrollHandler.scrollToPlayer(
mediaCarouselScrollHandler.visibleMediaIndex,
- destIndex = 0
+ destIndex = 0,
)
}
mediaCarouselScrollHandler.onPlayersChanged()
@@ -799,7 +798,7 @@
mediaCarouselScrollHandler.onPlayersChanged()
onAddOrUpdateVisibleToUserCard(
position,
- commonViewModel is MediaCommonViewModel.MediaControl
+ commonViewModel is MediaCommonViewModel.MediaControl,
)
}
@@ -856,7 +855,7 @@
mediaCarouselScrollHandler.qsExpanded,
mediaCarouselScrollHandler.visibleMediaIndex,
currentEndLocation,
- isMediaCardUpdate
+ isMediaCardUpdate,
)
}
}
@@ -893,7 +892,7 @@
secureSettings.getBoolForUser(
Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
true,
- UserHandle.USER_CURRENT
+ UserHandle.USER_CURRENT,
)
}
}
@@ -926,7 +925,7 @@
private fun reorderAllPlayers(
previousVisiblePlayerKey: MediaPlayerData.MediaSortKey?,
- key: String? = null
+ key: String? = null,
) {
mediaContent.removeAllViews()
for (mediaPlayer in MediaPlayerData.players()) {
@@ -960,7 +959,7 @@
TAG,
"Size of players list and number of views in carousel are out of sync. " +
"Players size is ${MediaPlayerData.players().size}. " +
- "View count is ${mediaContent.childCount}."
+ "View count is ${mediaContent.childCount}.",
)
}
}
@@ -970,7 +969,7 @@
key: String,
oldKey: String?,
data: MediaData,
- isSsReactivated: Boolean
+ isSsReactivated: Boolean,
): Boolean =
traceSection("MediaCarouselController#addOrUpdatePlayer") {
MediaPlayerData.moveIfExists(oldKey, key)
@@ -992,7 +991,7 @@
val lp =
LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
+ ViewGroup.LayoutParams.WRAP_CONTENT,
)
newPlayer.mediaViewHolder?.player?.setLayoutParams(lp)
newPlayer.bindPlayer(data, key)
@@ -1005,7 +1004,7 @@
newPlayer,
systemClock,
isSsReactivated,
- debugLogger
+ debugLogger,
)
updateViewControllerToState(newPlayer.mediaViewController, noAnimation = true)
// Media data added from a recommendation card should starts playing.
@@ -1025,7 +1024,7 @@
existingPlayer,
systemClock,
isSsReactivated,
- debugLogger
+ debugLogger,
)
val packageName = MediaPlayerData.smartspaceMediaData?.packageName ?: String()
// In case of recommendations hits.
@@ -1051,7 +1050,7 @@
private fun addSmartspaceMediaRecommendations(
key: String,
data: SmartspaceMediaData,
- shouldPrioritize: Boolean
+ shouldPrioritize: Boolean,
) =
traceSection("MediaCarouselController#addSmartspaceMediaRecommendations") {
if (DEBUG) Log.d(TAG, "Updating smartspace target in carousel")
@@ -1090,7 +1089,7 @@
val lp =
LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
+ ViewGroup.LayoutParams.WRAP_CONTENT,
)
newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp)
newRecs.bindRecommendation(data)
@@ -1117,7 +1116,7 @@
TAG,
"Size of players list and number of views in carousel are out of sync. " +
"Players size is ${MediaPlayerData.players().size}. " +
- "View count is ${mediaContent.childCount}."
+ "View count is ${mediaContent.childCount}.",
)
}
}
@@ -1173,7 +1172,7 @@
addSmartspaceMediaRecommendations(
it.targetId,
it,
- MediaPlayerData.shouldPrioritizeSs
+ MediaPlayerData.shouldPrioritizeSs,
)
}
} else {
@@ -1185,7 +1184,7 @@
key = key,
oldKey = null,
data = data,
- isSsReactivated = isSsReactivated
+ isSsReactivated = isSsReactivated,
)
}
if (recreateMedia) {
@@ -1248,7 +1247,7 @@
@MediaLocation startLocation: Int,
@MediaLocation endLocation: Int,
progress: Float,
- immediately: Boolean
+ immediately: Boolean,
) {
if (
startLocation != currentStartLocation ||
@@ -1286,7 +1285,7 @@
squishFraction,
(pageIndicator.translationY + pageIndicator.height) /
mediaCarousel.measuredHeight,
- 1F
+ 1F,
)
var alpha = 1.0f
if (!endIsVisible || !startIsVisible) {
@@ -1354,7 +1353,7 @@
currentCarouselHeight = height
mediaCarouselScrollHandler.setCarouselBounds(
currentCarouselWidth,
- currentCarouselHeight
+ currentCarouselHeight,
)
updatePageIndicatorLocation()
updatePageIndicatorAlpha()
@@ -1386,13 +1385,13 @@
private fun updateViewControllerToState(
viewController: MediaViewController,
- noAnimation: Boolean
+ noAnimation: Boolean,
) {
viewController.setCurrentState(
startLocation = currentStartLocation,
endLocation = currentEndLocation,
transitionProgress = currentTransitionProgress,
- applyImmediately = noAnimation
+ applyImmediately = noAnimation,
)
}
@@ -1411,7 +1410,7 @@
desiredHostState: MediaHostState?,
animate: Boolean,
duration: Long = 200,
- startDelay: Long = 0
+ startDelay: Long = 0,
) =
traceSection("MediaCarouselController#onDesiredLocationChanged") {
desiredHostState?.let {
@@ -1435,7 +1434,7 @@
if (animate) {
mediaPlayer.mediaViewController.animatePendingStateChange(
duration = duration,
- delay = startDelay
+ delay = startDelay,
)
}
if (shouldCloseGuts && mediaPlayer.mediaViewController.isGutsVisible) {
@@ -1506,7 +1505,7 @@
mediaCarouselViewModel.onCardVisibleToUser(
qsExpanded,
mediaCarouselScrollHandler.visibleMediaIndex,
- currentEndLocation
+ currentEndLocation,
)
return
}
@@ -1524,7 +1523,7 @@
800, // SMARTSPACE_CARD_SEEN
it.mSmartspaceId,
it.mUid,
- intArrayOf(it.surfaceForSmartspaceLogging)
+ intArrayOf(it.surfaceForSmartspaceLogging),
)
it.mIsImpressed = true
}
@@ -1559,7 +1558,7 @@
interactedSubcardCardinality: Int = 0,
rank: Int = mediaCarouselScrollHandler.visibleMediaIndex,
receivedLatencyMillis: Int = 0,
- isSwipeToDismiss: Boolean = false
+ isSwipeToDismiss: Boolean = false,
) {
if (MediaPlayerData.players().size <= rank) {
return
@@ -1600,7 +1599,7 @@
interactedSubcardCardinality,
receivedLatencyMillis,
null, // Media cards cannot have subcards.
- null // Media cards don't have dimensions today.
+ null, // Media cards don't have dimensions today.
)
if (DEBUG) {
@@ -1613,7 +1612,7 @@
"uid: $uid " +
"interactedSubcardRank: $interactedSubcardRank " +
"interactedSubcardCardinality: $interactedSubcardCardinality " +
- "received_latency_millis: $receivedLatencyMillis"
+ "received_latency_millis: $receivedLatencyMillis",
)
}
}
@@ -1633,7 +1632,7 @@
it.mUid,
intArrayOf(it.surfaceForSmartspaceLogging),
rank = index,
- isSwipeToDismiss = true
+ isSwipeToDismiss = true,
)
// Reset card impressed state when swipe to dismissed
it.mIsImpressed = false
@@ -1692,7 +1691,7 @@
active = true,
resumeAction = null,
instanceId = InstanceId.fakeInstanceId(-1),
- appUid = -1
+ appUid = -1,
)
// Whether should prioritize Smartspace card.
@@ -1741,7 +1740,7 @@
player: MediaControlPanel,
clock: SystemClock,
isSsReactivated: Boolean,
- debugLogger: MediaCarouselControllerLogger? = null
+ debugLogger: MediaCarouselControllerLogger? = null,
) {
val removedPlayer = removeMediaPlayer(key)
if (removedPlayer != null && removedPlayer != player) {
@@ -1754,7 +1753,7 @@
data,
key,
clock.currentTimeMillis(),
- isSsReactivated = isSsReactivated
+ isSsReactivated = isSsReactivated,
)
mediaData.put(key, sortKey)
mediaPlayers.put(sortKey, player)
@@ -1768,7 +1767,7 @@
shouldPrioritize: Boolean,
clock: SystemClock,
debugLogger: MediaCarouselControllerLogger? = null,
- update: Boolean = false
+ update: Boolean = false,
) {
shouldPrioritizeSs = shouldPrioritize
val removedPlayer = removeMediaPlayer(key)
@@ -1782,7 +1781,7 @@
EMPTY.copy(active = data.isActive, isPlaying = false),
key,
clock.currentTimeMillis(),
- isSsReactivated = true
+ isSsReactivated = true,
)
mediaData.put(key, sortKey)
mediaPlayers.put(sortKey, player)
@@ -1793,7 +1792,7 @@
fun moveIfExists(
oldKey: String?,
newKey: String,
- debugLogger: MediaCarouselControllerLogger? = null
+ debugLogger: MediaCarouselControllerLogger? = null,
) {
if (oldKey == null || oldKey == newKey) {
return
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
index 8bec46a..70ca824 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
@@ -545,6 +545,7 @@
/** Bind this player view based on the data given. */
public void bindPlayer(@NonNull MediaData data, String key) {
+ SceneContainerFlag.assertInLegacyMode();
if (mMediaViewHolder == null) {
return;
}
@@ -638,10 +639,7 @@
// to something which might impact the measurement
// State refresh interferes with the translation animation, only run it if it's not running.
if (!mMetadataAnimationHandler.isRunning()) {
- // Don't refresh in scene framework, because it will calculate with invalid layout sizes
- if (!SceneContainerFlag.isEnabled()) {
- mMediaViewController.refreshState();
- }
+ mMediaViewController.refreshState();
}
if (shouldPlayTurbulenceNoise()) {
@@ -907,11 +905,6 @@
// Capture width & height from views in foreground for artwork scaling in background
int width = mMediaViewHolder.getAlbumView().getMeasuredWidth();
int height = mMediaViewHolder.getAlbumView().getMeasuredHeight();
- if (SceneContainerFlag.isEnabled() && (width <= 0 || height <= 0)) {
- // TODO(b/312714128): ensure we have a valid size before setting background
- width = mMediaViewController.getWidthInSceneContainerPx();
- height = mMediaViewController.getHeightInSceneContainerPx();
- }
final int finalWidth = width;
final int finalHeight = height;
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt
index c97221e..c21513b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt
@@ -87,26 +87,19 @@
gradient: GradientDrawable,
colorScheme: ColorScheme,
startAlpha: Float,
- endAlpha: Float
+ endAlpha: Float,
): LayerDrawable {
gradient.colors =
intArrayOf(
getColorWithAlpha(backgroundStartFromScheme(colorScheme), startAlpha),
- getColorWithAlpha(backgroundEndFromScheme(colorScheme), endAlpha)
+ getColorWithAlpha(backgroundEndFromScheme(colorScheme), endAlpha),
)
return LayerDrawable(arrayOf(albumArt, gradient))
}
- /** Returns [ColorScheme] of media app given its [packageName]. */
- fun getColorScheme(
- applicationContext: Context,
- packageName: String,
- tag: String,
- style: Style = Style.TONAL_SPOT
- ): ColorScheme? {
+ /** Returns [ColorScheme] of media app given its [icon]. */
+ fun getColorScheme(icon: Drawable, tag: String, style: Style = Style.TONAL_SPOT): ColorScheme? {
return try {
- // Set up media source app's logo.
- val icon = applicationContext.packageManager.getApplicationIcon(packageName)
ColorScheme(WallpaperColors.fromDrawable(icon), true, style)
} catch (e: PackageManager.NameNotFoundException) {
Log.w(tag, "Fail to get media app info", e)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/GutsViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/GutsViewModel.kt
index 6c7c31c..314d9af 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/GutsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/GutsViewModel.kt
@@ -16,15 +16,11 @@
package com.android.systemui.media.controls.ui.viewmodel
-import android.annotation.ColorInt
import android.graphics.drawable.Drawable
/** Models UI state for media guts menu */
data class GutsViewModel(
val gutsText: CharSequence,
- @ColorInt val textPrimaryColor: Int,
- @ColorInt val accentPrimaryColor: Int,
- @ColorInt val surfaceColor: Int,
val isDismissEnabled: Boolean = true,
val onDismissClicked: () -> Unit,
val cancelTextBackground: Drawable?,
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaActionViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaActionViewModel.kt
index 82099e6..3f22d54 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaActionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaActionViewModel.kt
@@ -32,4 +32,16 @@
val buttonId: Int? = null,
val isEnabled: Boolean,
val onClicked: (Int) -> Unit,
-)
+) {
+ fun contentEquals(other: MediaActionViewModel?): Boolean {
+ return other?.let {
+ contentDescription == other.contentDescription &&
+ isVisibleWhenScrubbing == other.isVisibleWhenScrubbing &&
+ notVisibleValue == other.notVisibleValue &&
+ showInCollapsed == other.showInCollapsed &&
+ rebindId == other.rebindId &&
+ buttonId == other.buttonId &&
+ isEnabled == other.isEnabled
+ } ?: false
+ }
+}
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 64820e0..f07f2de 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
@@ -33,15 +33,9 @@
import com.android.systemui.media.controls.shared.model.MediaAction
import com.android.systemui.media.controls.shared.model.MediaButton
import com.android.systemui.media.controls.shared.model.MediaControlModel
-import com.android.systemui.media.controls.ui.animation.accentPrimaryFromScheme
-import com.android.systemui.media.controls.ui.animation.surfaceFromScheme
-import com.android.systemui.media.controls.ui.animation.textPrimaryFromScheme
-import com.android.systemui.media.controls.ui.util.MediaArtworkHelper
import com.android.systemui.media.controls.util.MediaSmartspaceLogger.Companion.SMARTSPACE_CARD_CLICK_EVENT
import com.android.systemui.media.controls.util.MediaSmartspaceLogger.Companion.SMARTSPACE_CARD_DISMISS_EVENT
import com.android.systemui.media.controls.util.MediaUiEventLogger
-import com.android.systemui.monet.ColorScheme
-import com.android.systemui.monet.Style
import com.android.systemui.res.R
import java.util.concurrent.Executor
import kotlinx.coroutines.CoroutineDispatcher
@@ -69,18 +63,30 @@
mediaControl?.let { toViewModel(it) }
}
}
- .distinctUntilChanged()
+ .distinctUntilChanged { old, new ->
+ (new == null && old == null) || new?.contentEquals(old) ?: false
+ }
.flowOn(backgroundDispatcher)
private var isPlaying = false
private var isAnyButtonClicked = false
private var location = -1
+ private var playerViewModel: MediaPlayerViewModel? = null
+
+ fun isNewPlayer(viewModel: MediaPlayerViewModel): Boolean {
+ val contentEquals = playerViewModel?.contentEquals(viewModel) ?: false
+ return (!contentEquals).also { playerViewModel = viewModel }
+ }
+
+ fun onMediaControlIsBound(artistName: CharSequence, titleName: CharSequence) {
+ interactor.logMediaControlIsBound(artistName, titleName)
+ }
private fun onDismissMediaData(
token: Token?,
uid: Int,
packageName: String,
- instanceId: InstanceId
+ instanceId: InstanceId,
) {
logger.logLongPressDismiss(uid, packageName, instanceId)
interactor.removeMediaControl(
@@ -88,30 +94,13 @@
instanceId,
MEDIA_PLAYER_ANIMATION_DELAY,
SMARTSPACE_CARD_DISMISS_EVENT,
- location
+ location,
)
}
- private suspend fun toViewModel(model: MediaControlModel): MediaPlayerViewModel? {
+ private fun toViewModel(model: MediaControlModel): MediaPlayerViewModel {
val mediaController = model.token?.let { MediaController(applicationContext, it) }
- val wallpaperColors =
- MediaArtworkHelper.getWallpaperColor(
- applicationContext,
- backgroundDispatcher,
- model.artwork,
- TAG
- )
- val scheme =
- wallpaperColors?.let { ColorScheme(it, true, Style.CONTENT) }
- ?: MediaArtworkHelper.getColorScheme(
- applicationContext,
- model.packageName,
- TAG,
- Style.CONTENT
- )
- ?: return null
-
- val gutsViewModel = toGutsViewModel(model, scheme)
+ val gutsViewModel = toGutsViewModel(model)
// Set playing state
val wasPlaying = isPlaying
@@ -131,7 +120,7 @@
R.string.controls_media_playing_item_description,
model.songName,
model.artistName,
- model.appName
+ model.appName,
)
}
},
@@ -142,8 +131,6 @@
artistName = model.artistName ?: "",
titleName = model.songName ?: "",
isExplicitVisible = model.showExplicit,
- shouldAddGradient = wallpaperColors != null,
- colorScheme = scheme,
canShowTime = canShowScrubbingTimeViews(model.semanticActionButtons),
playTurbulenceNoise = isPlaying && !wasPlaying && wasButtonClicked,
useSemanticActions = model.semanticActionButtons != null,
@@ -157,7 +144,7 @@
expandable,
clickIntent,
SMARTSPACE_CARD_CLICK_EVENT,
- location
+ location,
)
}
},
@@ -177,7 +164,7 @@
}
}
},
- onLocationChanged = { location = it }
+ onLocationChanged = { location = it },
)
}
@@ -191,7 +178,7 @@
device?.name?.let {
TextUtils.equals(
it,
- applicationContext.getString(R.string.broadcasting_description_is_broadcasting)
+ applicationContext.getString(R.string.broadcasting_description_is_broadcasting),
)
} ?: false
val useDisabledAlpha =
@@ -236,19 +223,19 @@
logger.logOpenBroadcastDialog(
model.uid,
model.packageName,
- model.instanceId
+ model.instanceId,
)
interactor.startBroadcastDialog(
expandable,
device?.name.toString(),
- model.packageName
+ model.packageName,
)
} else {
logger.logOpenOutputSwitcher(model.uid, model.packageName, model.instanceId)
interactor.startMediaOutputDialog(
expandable,
model.packageName,
- model.token
+ model.token,
)
}
} else {
@@ -257,27 +244,24 @@
?: interactor.startMediaOutputDialog(
expandable,
model.packageName,
- model.token
+ model.token,
)
}
- }
+ },
)
}
- private fun toGutsViewModel(model: MediaControlModel, scheme: ColorScheme): GutsViewModel {
+ private fun toGutsViewModel(model: MediaControlModel): GutsViewModel {
return GutsViewModel(
gutsText =
if (model.isDismissible) {
applicationContext.getString(
R.string.controls_media_close_session,
- model.appName
+ model.appName,
)
} else {
applicationContext.getString(R.string.controls_media_active_session)
},
- textPrimaryColor = textPrimaryFromScheme(scheme),
- accentPrimaryColor = accentPrimaryFromScheme(scheme),
- surfaceColor = surfaceFromScheme(scheme),
isDismissEnabled = model.isDismissible,
onDismissClicked = {
onDismissMediaData(model.token, model.uid, model.packageName, model.instanceId)
@@ -304,7 +288,7 @@
model,
mediaButton.getActionById(buttonId),
buttonId,
- isScrubbingTimeEnabled
+ isScrubbingTimeEnabled,
)
}
}
@@ -319,7 +303,7 @@
model: MediaControlModel,
mediaAction: MediaAction?,
buttonId: Int,
- canShowScrubbingTimeViews: Boolean
+ canShowScrubbingTimeViews: Boolean,
): MediaActionViewModel {
val showInCollapsed = SEMANTIC_ACTIONS_COMPACT.contains(buttonId)
val hideWhenScrubbing = SEMANTIC_ACTIONS_HIDE_WHEN_SCRUBBING.contains(buttonId)
@@ -353,7 +337,7 @@
private fun toNotifActionViewModel(
model: MediaControlModel,
mediaAction: MediaAction,
- index: Int
+ index: Int,
): MediaActionViewModel {
return MediaActionViewModel(
icon = mediaAction.icon,
@@ -375,7 +359,7 @@
uid: Int,
packageName: String,
instanceId: InstanceId,
- action: Runnable
+ action: Runnable,
) {
logger.logTapAction(id, uid, packageName, instanceId)
interactor.logSmartspaceUserEvent(SMARTSPACE_CARD_CLICK_EVENT, location)
@@ -424,7 +408,7 @@
R.id.actionPrev,
R.id.actionNext,
R.id.action0,
- R.id.action1
+ R.id.action1,
)
const val TURBULENCE_NOISE_PLAY_MS_DURATION = 7500L
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaOutputSwitcherViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaOutputSwitcherViewModel.kt
index 9df9bcc..2a47a5a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaOutputSwitcherViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaOutputSwitcherViewModel.kt
@@ -29,4 +29,15 @@
val alpha: Float,
val isVisible: Boolean,
val onClicked: (Expandable) -> Unit,
-)
+) {
+ fun contentEquals(other: MediaOutputSwitcherViewModel?): Boolean {
+ return (other?.let {
+ isTapEnabled == other.isTapEnabled &&
+ deviceString == other.deviceString &&
+ isCurrentBroadcastApp == other.isCurrentBroadcastApp &&
+ isIntentValid == other.isIntentValid &&
+ alpha == other.alpha &&
+ isVisible == other.isVisible
+ } ?: false)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaPlayerViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaPlayerViewModel.kt
index 96e7fc7..4aae72f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaPlayerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaPlayerViewModel.kt
@@ -18,7 +18,6 @@
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon
-import com.android.systemui.monet.ColorScheme
/** Models UI state for media player. */
data class MediaPlayerViewModel(
@@ -30,8 +29,6 @@
val artistName: CharSequence,
val titleName: CharSequence,
val isExplicitVisible: Boolean,
- val shouldAddGradient: Boolean,
- val colorScheme: ColorScheme,
val canShowTime: Boolean,
val playTurbulenceNoise: Boolean,
val useSemanticActions: Boolean,
@@ -43,4 +40,29 @@
val onSeek: () -> Unit,
val onBindSeekbar: (SeekBarViewModel) -> Unit,
val onLocationChanged: (Int) -> Unit,
-)
+) {
+ fun contentEquals(other: MediaPlayerViewModel?): Boolean {
+ return other?.let {
+ other.backgroundCover == backgroundCover &&
+ appIcon == other.appIcon &&
+ useGrayColorFilter == other.useGrayColorFilter &&
+ artistName == other.artistName &&
+ titleName == other.titleName &&
+ isExplicitVisible == other.isExplicitVisible &&
+ canShowTime == other.canShowTime &&
+ playTurbulenceNoise == other.playTurbulenceNoise &&
+ useSemanticActions == other.useSemanticActions &&
+ areActionsEqual(other.actionButtons) &&
+ outputSwitcher.contentEquals(other.outputSwitcher)
+ } ?: false
+ }
+
+ private fun areActionsEqual(other: List<MediaActionViewModel>): Boolean {
+ actionButtons.forEachIndexed { index, mediaActionViewModel ->
+ if (!mediaActionViewModel.contentEquals(other[index])) {
+ return false
+ }
+ }
+ return true
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecViewModel.kt
index 2f9fc9b..77add40 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecViewModel.kt
@@ -16,21 +16,18 @@
package com.android.systemui.media.controls.ui.viewmodel
-import android.annotation.ColorInt
import android.graphics.drawable.Drawable
+import android.graphics.drawable.Icon
import com.android.systemui.animation.Expandable
/** Models UI state for media recommendation item */
data class MediaRecViewModel(
val contentDescription: CharSequence,
val title: CharSequence = "",
- @ColorInt val titleColor: Int,
val subtitle: CharSequence = "",
- @ColorInt val subtitleColor: Int,
/** track progress [0 - 100] for the recommendation album. */
val progress: Int = 0,
- @ColorInt val progressColor: Int,
- val albumIcon: Drawable? = null,
- val appIcon: Drawable? = null,
+ val albumIcon: Icon? = null,
+ val appIcon: Drawable,
val onClicked: ((Expandable, Int) -> Unit),
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModel.kt
index 1fd9c4f0..a7bce77 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModel.kt
@@ -18,17 +18,10 @@
import android.content.Context
import android.content.Intent
-import android.graphics.Bitmap
-import android.graphics.Color
-import android.graphics.drawable.BitmapDrawable
-import android.graphics.drawable.ColorDrawable
+import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
-import android.graphics.drawable.GradientDrawable
-import android.graphics.drawable.Icon
-import android.graphics.drawable.LayerDrawable
import android.os.Process
import android.util.Log
-import androidx.appcompat.content.res.AppCompatResources
import com.android.internal.logging.InstanceId
import com.android.systemui.animation.Expandable
import com.android.systemui.dagger.SysUISingleton
@@ -38,18 +31,11 @@
import com.android.systemui.media.controls.shared.model.MediaRecModel
import com.android.systemui.media.controls.shared.model.MediaRecommendationsModel
import com.android.systemui.media.controls.shared.model.NUM_REQUIRED_RECOMMENDATIONS
-import com.android.systemui.media.controls.ui.animation.accentPrimaryFromScheme
-import com.android.systemui.media.controls.ui.animation.surfaceFromScheme
-import com.android.systemui.media.controls.ui.animation.textPrimaryFromScheme
-import com.android.systemui.media.controls.ui.animation.textSecondaryFromScheme
import com.android.systemui.media.controls.ui.controller.MediaViewController.Companion.GUTS_ANIMATION_DURATION
-import com.android.systemui.media.controls.ui.util.MediaArtworkHelper
import com.android.systemui.media.controls.util.MediaDataUtils
import com.android.systemui.media.controls.util.MediaSmartspaceLogger.Companion.SMARTSPACE_CARD_CLICK_EVENT
import com.android.systemui.media.controls.util.MediaSmartspaceLogger.Companion.SMARTSPACE_CARD_DISMISS_EVENT
import com.android.systemui.media.controls.util.MediaUiEventLogger
-import com.android.systemui.monet.ColorScheme
-import com.android.systemui.monet.Style
import com.android.systemui.res.R
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -59,7 +45,6 @@
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.withContext
/** Models UI state and handles user input for media recommendations */
@SysUISingleton
@@ -92,7 +77,7 @@
uid: Int,
packageName: String,
dismissIntent: Intent?,
- instanceId: InstanceId?
+ instanceId: InstanceId?,
) {
logger.logLongPressDismiss(uid, packageName, instanceId)
interactor.removeMediaRecommendations(
@@ -100,7 +85,7 @@
dismissIntent,
GUTS_DISMISS_DELAY_MS_DURATION,
SMARTSPACE_CARD_DISMISS_EVENT,
- location
+ location,
)
}
@@ -109,7 +94,7 @@
intent: Intent?,
packageName: String,
instanceId: InstanceId?,
- index: Int
+ index: Int,
) {
if (intent == null || intent.extras == null) {
Log.e(TAG, "No tap action can be set up")
@@ -131,7 +116,7 @@
SMARTSPACE_CARD_CLICK_EVENT,
location,
index,
- NUM_REQUIRED_RECOMMENDATIONS
+ NUM_REQUIRED_RECOMMENDATIONS,
)
}
@@ -145,22 +130,7 @@
return null
}
- val scheme =
- MediaArtworkHelper.getColorScheme(applicationContext, model.packageName, TAG)
- ?: return null
-
- // Capture width & height from views in foreground for artwork scaling in background
- val width =
- applicationContext.resources.getDimensionPixelSize(R.dimen.qs_media_rec_album_width)
- val height =
- applicationContext.resources.getDimensionPixelSize(
- R.dimen.qs_media_rec_album_height_expanded
- )
-
- val appIcon = applicationContext.packageManager.getApplicationIcon(model.packageName)
- val textPrimaryColor = textPrimaryFromScheme(scheme)
- val textSecondaryColor = textSecondaryFromScheme(scheme)
- val backgroundColor = surfaceFromScheme(scheme)
+ val appIcon = getIconFromApp(model.packageName) ?: return null
var areTitlesVisible = false
var areSubtitlesVisible = false
@@ -173,17 +143,9 @@
contentDescription =
setUpMediaRecContentDescription(mediaRecModel, model.appName),
title = mediaRecModel.title ?: "",
- titleColor = textPrimaryColor,
subtitle = mediaRecModel.subtitle ?: "",
- subtitleColor = textSecondaryColor,
progress = (progress * 100).toInt(),
- progressColor = textPrimaryColor,
- albumIcon =
- getRecCoverBackground(
- mediaRecModel.icon,
- width,
- height,
- ),
+ albumIcon = mediaRecModel.icon,
appIcon = appIcon,
onClicked = { expandable, index ->
onClicked(
@@ -193,7 +155,7 @@
model.instanceId,
index,
)
- }
+ },
)
}
// Subtitles should only be visible if titles are visible.
@@ -204,21 +166,19 @@
if (gutsVisible) {
applicationContext.getString(
R.string.controls_media_close_session,
- model.appName
+ model.appName,
)
} else {
applicationContext.getString(R.string.controls_media_smartspace_rec_header)
}
},
- cardColor = backgroundColor,
- cardTitleColor = textPrimaryColor,
onClicked = { expandable ->
onClicked(
expandable,
model.dismissIntent,
model.packageName,
model.instanceId,
- index = -1
+ index = -1,
)
},
onLongClicked = {
@@ -227,28 +187,22 @@
mediaRecs = mediaRecs,
areTitlesVisible = areTitlesVisible,
areSubtitlesVisible = areSubtitlesVisible,
- gutsMenu = toGutsViewModel(model, scheme),
- onLocationChanged = { location = it }
+ gutsMenu = toGutsViewModel(model),
+ onLocationChanged = { location = it },
)
}
- private fun toGutsViewModel(
- model: MediaRecommendationsModel,
- scheme: ColorScheme
- ): GutsViewModel {
+ private fun toGutsViewModel(model: MediaRecommendationsModel): GutsViewModel {
return GutsViewModel(
gutsText =
applicationContext.getString(R.string.controls_media_close_session, model.appName),
- textPrimaryColor = textPrimaryFromScheme(scheme),
- accentPrimaryColor = accentPrimaryFromScheme(scheme),
- surfaceColor = surfaceFromScheme(scheme),
onDismissClicked = {
onMediaRecommendationsDismissed(
model.key,
model.uid,
model.packageName,
model.dismissIntent,
- model.instanceId
+ model.instanceId,
)
},
cancelTextBackground =
@@ -260,56 +214,9 @@
)
}
- /** Returns the recommendation album cover of [width]x[height] size. */
- private suspend fun getRecCoverBackground(icon: Icon?, width: Int, height: Int): Drawable =
- withContext(backgroundDispatcher) {
- return@withContext MediaArtworkHelper.getWallpaperColor(
- applicationContext,
- backgroundDispatcher,
- icon,
- TAG,
- )
- ?.let { wallpaperColors ->
- addGradientToRecommendationAlbum(
- icon!!,
- ColorScheme(wallpaperColors, true, Style.CONTENT),
- width,
- height
- )
- } ?: ColorDrawable(Color.TRANSPARENT)
- }
-
- private fun addGradientToRecommendationAlbum(
- artworkIcon: Icon,
- mutableColorScheme: ColorScheme,
- width: Int,
- height: Int
- ): LayerDrawable {
- // First try scaling rec card using bitmap drawable.
- // If returns null, set drawable bounds.
- val albumArt =
- getScaledRecommendationCover(artworkIcon, width, height)
- ?: MediaArtworkHelper.getScaledBackground(
- applicationContext,
- artworkIcon,
- width,
- height
- )
- val gradient =
- AppCompatResources.getDrawable(applicationContext, R.drawable.qs_media_rec_scrim)
- ?.mutate() as GradientDrawable
- return MediaArtworkHelper.setUpGradientColorOnDrawable(
- albumArt,
- gradient,
- mutableColorScheme,
- MEDIA_REC_SCRIM_START_ALPHA,
- MEDIA_REC_SCRIM_END_ALPHA
- )
- }
-
private fun setUpMediaRecContentDescription(
mediaRec: MediaRecModel,
- appName: CharSequence?
+ appName: CharSequence?,
): CharSequence {
// Set up the accessibility label for the media item.
val artistName = mediaRec.extras?.getString(KEY_SMARTSPACE_ARTIST_NAME, "")
@@ -317,35 +224,23 @@
applicationContext.getString(
R.string.controls_media_smartspace_rec_item_no_artist_description,
mediaRec.title,
- appName
+ appName,
)
} else {
applicationContext.getString(
R.string.controls_media_smartspace_rec_item_description,
mediaRec.title,
artistName,
- appName
+ appName,
)
}
}
- /** Returns a [Drawable] of a given [artworkIcon] scaled to [width]x[height] size, . */
- private fun getScaledRecommendationCover(
- artworkIcon: Icon,
- width: Int,
- height: Int
- ): Drawable? {
- check(width > 0) { "Width must be a positive number but was $width" }
- check(height > 0) { "Height must be a positive number but was $height" }
-
- return if (
- artworkIcon.type == Icon.TYPE_BITMAP || artworkIcon.type == Icon.TYPE_ADAPTIVE_BITMAP
- ) {
- artworkIcon.bitmap?.let {
- val bitmap = Bitmap.createScaledBitmap(it, width, height, false)
- BitmapDrawable(applicationContext.resources, bitmap)
- }
- } else {
+ private fun getIconFromApp(packageName: String): Drawable? {
+ return try {
+ applicationContext.packageManager.getApplicationIcon(packageName)
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Cannot find icon for package $packageName", e)
null
}
}
@@ -353,8 +248,6 @@
companion object {
private const val TAG = "MediaRecommendationsViewModel"
private const val KEY_SMARTSPACE_ARTIST_NAME = "artist_name"
- private const val MEDIA_REC_SCRIM_START_ALPHA = 0.15f
- private const val MEDIA_REC_SCRIM_END_ALPHA = 1.0f
/**
* Delay duration is based on [GUTS_ANIMATION_DURATION], it should have 100 ms increase in
* order to let the animation end.
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecsCardViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecsCardViewModel.kt
index 5ecbcb2..f1f7dc2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecsCardViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecsCardViewModel.kt
@@ -16,14 +16,11 @@
package com.android.systemui.media.controls.ui.viewmodel
-import android.annotation.ColorInt
import com.android.systemui.animation.Expandable
/** Models UI state for media recommendations card. */
data class MediaRecsCardViewModel(
val contentDescription: (Boolean) -> CharSequence,
- @ColorInt val cardColor: Int,
- @ColorInt val cardTitleColor: Int,
val onClicked: (Expandable) -> Unit,
val onLongClicked: () -> Unit,
val mediaRecs: List<MediaRecViewModel>,
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 2cbc7575..f7b7353 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
@@ -157,7 +157,7 @@
@VisibleForTesting
boolean mNeedRefresh = false;
private MediaController mMediaController;
- private InputRouteManager mInputRouteManager;
+ @VisibleForTesting InputRouteManager mInputRouteManager;
@VisibleForTesting
Callback mCallback;
@VisibleForTesting
@@ -927,7 +927,18 @@
}
public List<MediaDevice> getSelectedMediaDevice() {
- return mLocalMediaManager.getSelectedMediaDevice();
+ if (!enableInputRouting()) {
+ return mLocalMediaManager.getSelectedMediaDevice();
+ }
+
+ // Add selected input device if input routing is supported.
+ List<MediaDevice> selectedDevices =
+ new ArrayList<>(mLocalMediaManager.getSelectedMediaDevice());
+ MediaDevice selectedInputDevice = mInputRouteManager.getSelectedInputDevice();
+ if (selectedInputDevice != null) {
+ selectedDevices.add(selectedInputDevice);
+ }
+ return selectedDevices;
}
List<MediaDevice> getDeselectableMediaDevice() {
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
index 6440205..544dbdd 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
@@ -16,6 +16,7 @@
package com.android.systemui.mediaprojection.appselector
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
import android.app.Activity
import android.content.ComponentName
import android.content.Context
@@ -133,7 +134,7 @@
@MediaProjectionAppSelector
@MediaProjectionAppSelectorScope
fun provideCoroutineScope(@Application applicationScope: CoroutineScope): CoroutineScope =
- CoroutineScope(applicationScope.coroutineContext + SupervisorJob())
+ CoroutineScope(applicationScope.coroutineContext + SupervisorJob() + createCoroutineTracingContext("MediaProjectionAppSelectorScope"))
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index 4251b81..8351597 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -34,6 +34,7 @@
import android.app.Activity;
import android.app.ActivityOptions.LaunchCookie;
import android.app.AlertDialog;
+import android.app.KeyguardManager;
import android.app.StatusBarManager;
import android.app.compat.CompatChanges;
import android.content.Context;
@@ -83,6 +84,7 @@
private final StatusBarManager mStatusBarManager;
private final MediaProjectionMetricsLogger mMediaProjectionMetricsLogger;
private final ScreenCaptureDisabledDialogDelegate mScreenCaptureDisabledDialogDelegate;
+ private final KeyguardManager mKeyguardManager;
private String mPackageName;
private int mUid;
@@ -101,11 +103,13 @@
FeatureFlags featureFlags,
Lazy<ScreenCaptureDevicePolicyResolver> screenCaptureDevicePolicyResolver,
StatusBarManager statusBarManager,
+ KeyguardManager keyguardManager,
MediaProjectionMetricsLogger mediaProjectionMetricsLogger,
ScreenCaptureDisabledDialogDelegate screenCaptureDisabledDialogDelegate) {
mFeatureFlags = featureFlags;
mScreenCaptureDevicePolicyResolver = screenCaptureDevicePolicyResolver;
mStatusBarManager = statusBarManager;
+ mKeyguardManager = keyguardManager;
mMediaProjectionMetricsLogger = mediaProjectionMetricsLogger;
mScreenCaptureDisabledDialogDelegate = screenCaptureDisabledDialogDelegate;
}
@@ -208,7 +212,14 @@
}
setUpDialog(mDialog);
- mDialog.show();
+
+ boolean shouldDismissKeyguard =
+ com.android.systemui.Flags.mediaProjectionDialogBehindLockscreen();
+ if (shouldDismissKeyguard && mKeyguardManager.isDeviceLocked()) {
+ requestDeviceUnlock();
+ } else {
+ mDialog.show();
+ }
if (savedInstanceState == null) {
mMediaProjectionMetricsLogger.notifyPermissionRequestDisplayed(mUid);
@@ -332,6 +343,16 @@
return false;
}
+ private void requestDeviceUnlock() {
+ mKeyguardManager.requestDismissKeyguard(this,
+ new KeyguardManager.KeyguardDismissCallback() {
+ @Override
+ public void onDismissSucceeded() {
+ mDialog.show();
+ }
+ });
+ }
+
private void grantMediaProjectionPermission(
int screenShareMode, boolean hasCastingCapabilities) {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index b3c697e..1216a88 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -551,6 +551,12 @@
}
@Override
+ public void appTransitionStarting(int displayId, long startTime, long duration,
+ boolean forced) {
+ appTransitionPending(false);
+ }
+
+ @Override
public void appTransitionCancelled(int displayId) {
appTransitionPending(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
index 44460ed..eff5fc0 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
@@ -75,7 +75,9 @@
* [NoteTaskController], ensure custom actions can be triggered (i.e., keyboard shortcut).
*/
private fun initializeHandleSystemKey() {
- commandQueue.addCallback(callbacks)
+ if (!useKeyGestureEventHandler()) {
+ commandQueue.addCallback(callbacks)
+ }
}
/**
@@ -130,6 +132,11 @@
InputManager.KeyGestureEventHandler {
override fun handleSystemKey(key: KeyEvent) {
+ if (useKeyGestureEventHandler()) {
+ throw IllegalStateException(
+ "handleSystemKey must not be used when KeyGestureEventHandler is used"
+ )
+ }
key.toNoteTaskEntryPointOrNull()?.let(controller::showNoteTask)
}
@@ -151,13 +158,13 @@
override fun handleKeyGestureEvent(
event: KeyGestureEvent,
- focusedToken: IBinder?
+ focusedToken: IBinder?,
): Boolean {
return [email protected](event)
}
override fun isKeyGestureSupported(gestureType: Int): Boolean {
- return [email protected](gestureType);
+ return [email protected](gestureType)
}
}
@@ -209,8 +216,20 @@
"handleKeyGestureEvent: Received OPEN_NOTES gesture event from keycodes: " +
event.keycodes.contentToString()
}
- backgroundExecutor.execute { controller.showNoteTask(KEYBOARD_SHORTCUT) }
- return true
+ if (
+ event.keycodes.contains(KEYCODE_N) &&
+ event.hasModifiers(KeyEvent.META_CTRL_ON or KeyEvent.META_META_ON)
+ ) {
+ debugLog { "Note task triggered by keyboard shortcut" }
+ backgroundExecutor.execute { controller.showNoteTask(KEYBOARD_SHORTCUT) }
+ return true
+ }
+ if (event.keycodes.size == 1 && event.keycodes[0] == KEYCODE_STYLUS_BUTTON_TAIL) {
+ debugLog { "Note task triggered by stylus tail button" }
+ backgroundExecutor.execute { controller.showNoteTask(TAIL_BUTTON) }
+ return true
+ }
+ return false
}
private fun isKeyGestureSupported(gestureType: Int): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index af167d4..c174038 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -26,7 +26,6 @@
import androidx.activity.OnBackPressedDispatcher
import androidx.activity.OnBackPressedDispatcherOwner
import androidx.activity.setViewTreeOnBackPressedDispatcherOwner
-import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -38,10 +37,14 @@
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.layout.positionInRoot
@@ -51,11 +54,18 @@
import androidx.compose.ui.semantics.CustomAccessibilityAction
import androidx.compose.ui.semantics.customActions
import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.round
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
+import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.SceneTransitionLayout
+import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.transitions
import com.android.compose.modifiers.height
import com.android.compose.modifiers.padding
import com.android.compose.modifiers.thenIf
@@ -70,11 +80,17 @@
import com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL
import com.android.systemui.plugins.qs.QS
import com.android.systemui.plugins.qs.QSContainerController
+import com.android.systemui.qs.composefragment.SceneKeys.QuickQuickSettings
+import com.android.systemui.qs.composefragment.SceneKeys.QuickSettings
+import com.android.systemui.qs.composefragment.SceneKeys.toIdleSceneKey
import com.android.systemui.qs.composefragment.ui.notificationScrimClip
+import com.android.systemui.qs.composefragment.ui.quickQuickSettingsToQuickSettings
import com.android.systemui.qs.composefragment.viewmodel.QSFragmentComposeViewModel
import com.android.systemui.qs.flags.QSComposeFragment
import com.android.systemui.qs.footer.ui.compose.FooterActions
import com.android.systemui.qs.panels.ui.compose.QuickQuickSettings
+import com.android.systemui.qs.shared.ui.ElementKeys
+import com.android.systemui.qs.ui.composable.QuickSettingsShade
import com.android.systemui.qs.ui.composable.QuickSettingsTheme
import com.android.systemui.qs.ui.composable.ShadeBody
import com.android.systemui.res.R
@@ -86,11 +102,13 @@
import java.util.function.Consumer
import javax.inject.Inject
import javax.inject.Named
+import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
@SuppressLint("ValidFragment")
@@ -166,33 +184,48 @@
setContent {
PlatformTheme {
val visible by viewModel.qsVisible.collectAsStateWithLifecycle()
- val qsState by viewModel.expansionState.collectAsStateWithLifecycle()
AnimatedVisibility(
visible = visible,
modifier =
- Modifier.windowInsetsPadding(WindowInsets.navigationBars).thenIf(
- notificationScrimClippingParams.isEnabled
- ) {
- Modifier.notificationScrimClip(
- notificationScrimClippingParams.leftInset,
- notificationScrimClippingParams.top,
- notificationScrimClippingParams.rightInset,
- notificationScrimClippingParams.bottom,
- notificationScrimClippingParams.radius,
- )
- },
+ Modifier.windowInsetsPadding(WindowInsets.navigationBars)
+ .thenIf(notificationScrimClippingParams.isEnabled) {
+ Modifier.notificationScrimClip(
+ notificationScrimClippingParams.leftInset,
+ notificationScrimClippingParams.top,
+ notificationScrimClippingParams.rightInset,
+ notificationScrimClippingParams.bottom,
+ notificationScrimClippingParams.radius,
+ )
+ }
+ .graphicsLayer { elevation = 4.dp.toPx() },
) {
- AnimatedContent(targetState = qsState) {
- when (it) {
- QSFragmentComposeViewModel.QSExpansionState.QQS -> {
- QuickQuickSettingsElement()
- }
- QSFragmentComposeViewModel.QSExpansionState.QS -> {
- QuickSettingsElement()
- }
- else -> {}
- }
+ val sceneState = remember {
+ MutableSceneTransitionLayoutState(
+ viewModel.expansionState.value.toIdleSceneKey(),
+ transitions =
+ transitions {
+ from(QuickQuickSettings, QuickSettings) {
+ quickQuickSettingsToQuickSettings()
+ }
+ },
+ )
+ }
+
+ LaunchedEffect(Unit) {
+ synchronizeQsState(
+ sceneState,
+ viewModel.expansionState.map { it.progress },
+ )
+ }
+
+ SceneTransitionLayout(
+ state = sceneState,
+ modifier = Modifier.fillMaxSize(),
+ ) {
+ scene(QuickSettings) { QuickSettingsElement() }
+
+ scene(QuickQuickSettings) { QuickQuickSettingsElement() }
}
}
}
@@ -420,7 +453,7 @@
}
@Composable
- private fun QuickQuickSettingsElement() {
+ private fun SceneScope.QuickQuickSettingsElement() {
val qqsPadding by viewModel.qqsHeaderHeight.collectAsStateWithLifecycle()
val bottomPadding = dimensionResource(id = R.dimen.qqs_layout_padding_bottom)
DisposableEffect(Unit) {
@@ -450,8 +483,15 @@
viewModel = viewModel.containerViewModel.quickQuickSettingsViewModel,
modifier =
Modifier.collapseExpandSemanticAction(
- stringResource(id = R.string.accessibility_quick_settings_expand)
- ),
+ stringResource(
+ id = R.string.accessibility_quick_settings_expand
+ )
+ )
+ .padding(
+ horizontal = {
+ QuickSettingsShade.Dimensions.Padding.roundToPx()
+ }
+ ),
)
}
}
@@ -460,7 +500,7 @@
}
@Composable
- private fun QuickSettingsElement() {
+ private fun SceneScope.QuickSettingsElement() {
val qqsPadding by viewModel.qqsHeaderHeight.collectAsStateWithLifecycle()
val qsExtraPadding = dimensionResource(R.dimen.qs_panel_padding_top)
Column(
@@ -471,7 +511,10 @@
) {
val qsEnabled by viewModel.qsEnabled.collectAsStateWithLifecycle()
if (qsEnabled) {
- Box(modifier = Modifier.fillMaxSize().weight(1f)) {
+ Box(
+ modifier =
+ Modifier.element(ElementKeys.QuickSettingsContent).fillMaxSize().weight(1f)
+ ) {
Column {
Spacer(
modifier = Modifier.height { qqsPadding + qsExtraPadding.roundToPx() }
@@ -483,7 +526,9 @@
FooterActions(
viewModel = viewModel.footerActionsViewModel,
qsVisibilityLifecycleOwner = this@QSFragmentCompose,
- modifier = Modifier.sysuiResTag("qs_footer_actions"),
+ modifier =
+ Modifier.sysuiResTag("qs_footer_actions")
+ .element(ElementKeys.FooterActions),
)
}
}
@@ -590,3 +635,85 @@
return currentId++
}
}
+
+object SceneKeys {
+ val QuickQuickSettings = SceneKey("QuickQuickSettingsScene")
+ val QuickSettings = SceneKey("QuickSettingsScene")
+
+ fun QSFragmentComposeViewModel.QSExpansionState.toIdleSceneKey(): SceneKey {
+ return when {
+ progress < 0.5f -> QuickQuickSettings
+ else -> QuickSettings
+ }
+ }
+}
+
+suspend fun synchronizeQsState(state: MutableSceneTransitionLayoutState, expansion: Flow<Float>) {
+ coroutineScope {
+ val animationScope = this
+
+ var currentTransition: ExpansionTransition? = null
+
+ fun snapTo(scene: SceneKey) {
+ state.snapToScene(scene)
+ currentTransition = null
+ }
+
+ expansion.collectLatest { progress ->
+ when (progress) {
+ 0f -> snapTo(QuickQuickSettings)
+ 1f -> snapTo(QuickSettings)
+ else -> {
+ val transition = currentTransition
+ if (transition != null) {
+ transition.progress = progress
+ return@collectLatest
+ }
+
+ val newTransition =
+ ExpansionTransition(progress).also { currentTransition = it }
+ state.startTransitionImmediately(
+ animationScope = animationScope,
+ transition = newTransition,
+ )
+ }
+ }
+ }
+ }
+}
+
+private class ExpansionTransition(currentProgress: Float) :
+ TransitionState.Transition.ChangeScene(
+ fromScene = QuickQuickSettings,
+ toScene = QuickSettings,
+ ) {
+ override val currentScene: SceneKey
+ get() {
+ // This should return the logical scene. If the QS STLState is only driven by
+ // synchronizeQSState() then it probably does not matter which one we return, this is
+ // only used to compute the current user actions of a STL.
+ return QuickQuickSettings
+ }
+
+ override var progress: Float by mutableFloatStateOf(currentProgress)
+
+ override val progressVelocity: Float
+ get() = 0f
+
+ override val isInitiatedByUserInput: Boolean
+ get() = true
+
+ override val isUserInputOngoing: Boolean
+ get() = true
+
+ private val finishCompletable = CompletableDeferred<Unit>()
+
+ override suspend fun run() {
+ // This transition runs until it is interrupted by another one.
+ finishCompletable.await()
+ }
+
+ override fun freezeAndAnimateToCurrentState() {
+ finishCompletable.complete(Unit)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/FromQuickQuickSettingsToQuickSettings.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/FromQuickQuickSettingsToQuickSettings.kt
new file mode 100644
index 0000000..1514986
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/FromQuickQuickSettingsToQuickSettings.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.qs.composefragment.ui
+
+import com.android.compose.animation.scene.TransitionBuilder
+import com.android.systemui.qs.shared.ui.ElementKeys
+
+fun TransitionBuilder.quickQuickSettingsToQuickSettings() {
+
+ fractionRange(start = 0.5f) { fade(ElementKeys.QuickSettingsContent) }
+
+ fractionRange(start = 0.9f) { fade(ElementKeys.FooterActions) }
+
+ anchoredTranslate(ElementKeys.QuickSettingsContent, ElementKeys.GridAnchor)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/GridAnchor.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/GridAnchor.kt
new file mode 100644
index 0000000..f0f46d3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/GridAnchor.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.qs.composefragment.ui
+
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import com.android.compose.animation.scene.SceneScope
+import com.android.systemui.qs.shared.ui.ElementKeys
+
+/**
+ * This composable is used at the start of the tiles in QQS and QS to anchor the expansion and be
+ * able to have relative anchor translation of elements that appear in QS.
+ */
+@Composable
+fun SceneScope.GridAnchor(modifier: Modifier = Modifier) {
+ // The size of this anchor does not matter, as the tiles don't change size on expansion.
+ Spacer(modifier.element(ElementKeys.GridAnchor))
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt
index 7ab11d2..7300ee1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt
@@ -147,7 +147,7 @@
.stateIn(
lifecycleScope,
SharingStarted.WhileSubscribed(),
- disableFlagsRepository.disableFlags.value.isQuickSettingsEnabled()
+ disableFlagsRepository.disableFlags.value.isQuickSettingsEnabled(),
)
private val _showCollapsedOnKeyguard = MutableStateFlow(false)
@@ -213,19 +213,11 @@
}
val expansionState: StateFlow<QSExpansionState> =
- combine(
- _stackScrollerOverscrolling,
- _qsExpanded,
- _qsExpansion,
- ) { args: Array<Any> ->
+ combine(_stackScrollerOverscrolling, _qsExpanded, _qsExpansion) { args: Array<Any> ->
val expansion = args[2] as Float
- if (expansion > 0.5f) {
- QSExpansionState.QS
- } else {
- QSExpansionState.QQS
- }
+ QSExpansionState(expansion.coerceIn(0f, 1f))
}
- .stateIn(lifecycleScope, SharingStarted.WhileSubscribed(), QSExpansionState.QQS)
+ .stateIn(lifecycleScope, SharingStarted.WhileSubscribed(), QSExpansionState(0f))
/**
* Accessibility action for collapsing/expanding QS. The provided runnable is responsible for
@@ -262,13 +254,6 @@
fun create(lifecycleScope: LifecycleCoroutineScope): QSFragmentComposeViewModel
}
- sealed interface QSExpansionState {
- data object QQS : QSExpansionState
-
- data object QS : QSExpansionState
-
- @JvmInline value class Expanding(val progress: Float) : QSExpansionState
-
- @JvmInline value class Collapsing(val progress: Float) : QSExpansionState
- }
+ // In the future, this will have other relevant elements like squishiness.
+ data class QSExpansionState(@FloatRange(0.0, 1.0) val progress: Float)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt
index 1f8a24a1..35faa97 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt
@@ -17,9 +17,10 @@
package com.android.systemui.qs.panels.ui.compose
import android.content.ClipData
+import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.draganddrop.dragAndDropSource
import androidx.compose.foundation.draganddrop.dragAndDropTarget
-import androidx.compose.foundation.gestures.detectTapGestures
+import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress
import androidx.compose.foundation.lazy.grid.LazyGridItemInfo
import androidx.compose.foundation.lazy.grid.LazyGridState
import androidx.compose.runtime.Composable
@@ -104,11 +105,10 @@
@Composable
fun Modifier.dragAndDropTileList(
gridState: LazyGridState,
- contentOffset: Offset,
+ contentOffset: () -> Offset,
dragAndDropState: DragAndDropState,
- onDrop: () -> Unit,
+ onDrop: (TileSpec) -> Unit,
): Modifier {
- val currentContentOffset by rememberUpdatedState(contentOffset)
val target =
remember(dragAndDropState) {
object : DragAndDropTarget {
@@ -118,7 +118,7 @@
override fun onMoved(event: DragAndDropEvent) {
// Drag offset relative to the list's top left corner
- val relativeDragOffset = event.dragOffsetRelativeTo(currentContentOffset)
+ val relativeDragOffset = event.dragOffsetRelativeTo(contentOffset())
val targetItem =
gridState.layoutInfo.visibleItemsInfo.firstOrNull { item ->
// Check if the drag is on this item
@@ -132,7 +132,7 @@
override fun onDrop(event: DragAndDropEvent): Boolean {
return dragAndDropState.draggedCell?.let {
- onDrop()
+ onDrop(it.tile.tileSpec)
dragAndDropState.onDrop()
true
} ?: false
@@ -158,36 +158,39 @@
return item.span != 1 && offset.x > itemCenter.x
}
+@OptIn(ExperimentalFoundationApi::class)
@Composable
fun Modifier.dragAndDropTileSource(
sizedTile: SizedTile<EditTileViewModel>,
dragAndDropState: DragAndDropState,
- onTap: (TileSpec) -> Unit,
- onDoubleTap: (TileSpec) -> Unit = {},
+ onDragStart: () -> Unit,
): Modifier {
- val state by rememberUpdatedState(dragAndDropState)
- return dragAndDropSource {
- detectTapGestures(
- onTap = { onTap(sizedTile.tile.tileSpec) },
- onDoubleTap = { onDoubleTap(sizedTile.tile.tileSpec) },
- onLongPress = {
- state.onStarted(sizedTile)
+ val dragState by rememberUpdatedState(dragAndDropState)
+ @Suppress("DEPRECATION") // b/368361871
+ return dragAndDropSource(
+ block = {
+ detectDragGesturesAfterLongPress(
+ onDrag = { _, _ -> },
+ onDragStart = {
+ dragState.onStarted(sizedTile)
+ onDragStart()
- // The tilespec from the ClipData transferred isn't actually needed as we're moving
- // a tile within the same application. We're using a custom MIME type to limit the
- // drag event to QS.
- startTransfer(
- DragAndDropTransferData(
- ClipData(
- QsDragAndDrop.CLIPDATA_LABEL,
- arrayOf(QsDragAndDrop.TILESPEC_MIME_TYPE),
- ClipData.Item(sizedTile.tile.tileSpec.spec),
+ // The tilespec from the ClipData transferred isn't actually needed as we're
+ // moving a tile within the same application. We're using a custom MIME type to
+ // limit the drag event to QS.
+ startTransfer(
+ DragAndDropTransferData(
+ ClipData(
+ QsDragAndDrop.CLIPDATA_LABEL,
+ arrayOf(QsDragAndDrop.TILESPEC_MIME_TYPE),
+ ClipData.Item(sizedTile.tile.tileSpec.spec),
+ )
)
)
- )
- },
- )
- }
+ },
+ )
+ }
+ )
}
private object QsDragAndDrop {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
index 4830ba7..a4f977b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
@@ -42,10 +42,8 @@
}
/** Holds the temporary state of the tile list during a drag movement where we move tiles around. */
-class EditTileListState(
- tiles: List<SizedTile<EditTileViewModel>>,
- private val columns: Int,
-) : DragAndDropState {
+class EditTileListState(tiles: List<SizedTile<EditTileViewModel>>, private val columns: Int) :
+ DragAndDropState {
private val _draggedCell = mutableStateOf<SizedTile<EditTileViewModel>?>(null)
override val draggedCell
get() = _draggedCell.value
@@ -91,7 +89,8 @@
regenerateGrid(includeSpacers = true)
_tiles.add(insertionIndex.coerceIn(0, _tiles.size), cell)
} else {
- // Add the tile with a temporary row which will get reassigned when regenerating spacers
+ // Add the tile with a temporary row which will get reassigned when
+ // regenerating spacers
_tiles.add(insertionIndex.coerceIn(0, _tiles.size), TileGridCell(draggedTile, 0))
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
index fd276c2..0c02b40 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
@@ -18,6 +18,7 @@
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import com.android.compose.animation.scene.SceneScope
import com.android.systemui.qs.panels.shared.model.SizedTile
import com.android.systemui.qs.panels.shared.model.TileRow
import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
@@ -27,7 +28,7 @@
/** A layout of tiles, indicating how they should be composed when showing in QS or in edit mode. */
interface GridLayout {
@Composable
- fun TileGrid(
+ fun SceneScope.TileGrid(
tiles: List<TileViewModel>,
modifier: Modifier,
editModeStart: () -> Unit,
@@ -66,7 +67,7 @@
*/
fun splitInRows(
tiles: List<SizedTile<TileViewModel>>,
- columns: Int
+ columns: Int,
): List<List<SizedTile<TileViewModel>>> {
val row = TileRow<TileViewModel>(columns)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
index 08a56bf..083f529 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
@@ -39,6 +39,7 @@
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.compose.animation.scene.SceneScope
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.qs.panels.dagger.PaginatedBaseLayoutType
import com.android.systemui.qs.panels.ui.compose.PaginatedGridLayout.Dimensions.FooterHeight
@@ -55,7 +56,7 @@
@PaginatedBaseLayoutType private val delegateGridLayout: PaginatableGridLayout,
) : GridLayout by delegateGridLayout {
@Composable
- override fun TileGrid(
+ override fun SceneScope.TileGrid(
tiles: List<TileViewModel>,
modifier: Modifier,
editModeStart: () -> Unit,
@@ -85,16 +86,16 @@
) {
val page = pages[it]
- delegateGridLayout.TileGrid(tiles = page, modifier = Modifier, editModeStart = {})
+ with(delegateGridLayout) {
+ TileGrid(tiles = page, modifier = Modifier, editModeStart = {})
+ }
}
- Box(
- modifier = Modifier.height(FooterHeight).fillMaxWidth(),
- ) {
+ Box(modifier = Modifier.height(FooterHeight).fillMaxWidth()) {
PagerDots(
pagerState = pagerState,
activeColor = MaterialTheme.colorScheme.primary,
nonActiveColor = MaterialTheme.colorScheme.surfaceVariant,
- modifier = Modifier.align(Alignment.Center)
+ modifier = Modifier.align(Alignment.Center),
)
CompositionLocalProvider(value = LocalContentColor provides Color.White) {
IconButton(
@@ -103,7 +104,7 @@
) {
Icon(
imageVector = Icons.Default.Edit,
- contentDescription = stringResource(id = R.string.qs_edit)
+ contentDescription = stringResource(id = R.string.qs_edit),
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
index f4acbec..8998a7f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
@@ -16,21 +16,28 @@
package com.android.systemui.qs.panels.ui.compose
-import androidx.compose.foundation.lazy.grid.GridCells
-import androidx.compose.foundation.lazy.grid.GridItemSpan
+import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.util.fastMap
import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.compose.animation.scene.SceneScope
import com.android.systemui.compose.modifiers.sysuiResTag
+import com.android.systemui.grid.ui.compose.VerticalSpannedGrid
+import com.android.systemui.qs.composefragment.ui.GridAnchor
import com.android.systemui.qs.panels.ui.compose.infinitegrid.Tile
-import com.android.systemui.qs.panels.ui.compose.infinitegrid.TileLazyGrid
import com.android.systemui.qs.panels.ui.viewmodel.QuickQuickSettingsViewModel
+import com.android.systemui.qs.shared.ui.ElementKeys.toElementKey
+import com.android.systemui.res.R
@Composable
-fun QuickQuickSettings(viewModel: QuickQuickSettingsViewModel, modifier: Modifier = Modifier) {
+fun SceneScope.QuickQuickSettings(
+ viewModel: QuickQuickSettingsViewModel,
+ modifier: Modifier = Modifier,
+) {
val sizedTiles by
viewModel.tileViewModels.collectAsStateWithLifecycle(initialValue = emptyList())
val tiles = sizedTiles.fastMap { it.tile }
@@ -41,20 +48,20 @@
onDispose { tiles.forEach { it.stopListening(token) } }
}
val columns by viewModel.columns.collectAsStateWithLifecycle()
-
- TileLazyGrid(
- modifier = modifier.sysuiResTag("qqs_tile_layout"),
- columns = GridCells.Fixed(columns),
- ) {
- items(
- sizedTiles.size,
- key = { index -> sizedTiles[index].tile.spec.spec },
- span = { index -> GridItemSpan(sizedTiles[index].width) },
- ) { index ->
+ Box(modifier = modifier) {
+ GridAnchor()
+ VerticalSpannedGrid(
+ columns = columns,
+ columnSpacing = dimensionResource(R.dimen.qs_tile_margin_horizontal),
+ rowSpacing = dimensionResource(R.dimen.qs_tile_margin_vertical),
+ spans = sizedTiles.fastMap { it.width },
+ modifier = Modifier.sysuiResTag("qqs_tile_layout"),
+ ) { spanIndex ->
+ val it = sizedTiles[spanIndex]
Tile(
- tile = sizedTiles[index].tile,
- iconOnly = sizedTiles[index].isIcon,
- modifier = Modifier,
+ tile = it.tile,
+ iconOnly = it.isIcon,
+ modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)),
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
index 8c57d41..1a5297b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
@@ -20,16 +20,17 @@
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.compose.animation.scene.SceneScope
import com.android.systemui.qs.panels.ui.viewmodel.TileGridViewModel
@Composable
-fun TileGrid(
+fun SceneScope.TileGrid(
viewModel: TileGridViewModel,
modifier: Modifier = Modifier,
- editModeStart: () -> Unit
+ editModeStart: () -> Unit,
) {
val gridLayout by viewModel.gridLayout.collectAsStateWithLifecycle()
val tiles by viewModel.tileViewModels.collectAsStateWithLifecycle(emptyList())
- gridLayout.TileGrid(tiles, modifier, editModeStart)
+ with(gridLayout) { TileGrid(tiles, modifier, editModeStart) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
index aeb6031..8c2fb25 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
@@ -127,13 +127,14 @@
}
@Composable
-private fun LargeTileLabels(
+fun LargeTileLabels(
label: String,
secondaryLabel: String?,
colors: TileColors,
+ modifier: Modifier = Modifier,
accessibilityUiState: AccessibilityUiState? = null,
) {
- Column(verticalArrangement = Arrangement.Center, modifier = Modifier.fillMaxHeight()) {
+ Column(verticalArrangement = Arrangement.Center, modifier = modifier.fillMaxHeight()) {
Text(label, color = colors.label, modifier = Modifier.tileMarquee())
if (!TextUtils.isEmpty(secondaryLabel)) {
Text(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
index a43b880..0e76e18 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
@@ -20,6 +20,9 @@
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.core.animateDpAsState
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.animation.core.animateIntAsState
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.ExperimentalFoundationApi
@@ -31,6 +34,7 @@
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
+import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
@@ -38,6 +42,7 @@
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.grid.GridCells
@@ -56,23 +61,34 @@
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
+import androidx.compose.ui.BiasAlignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.layout.positionInRoot
+import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.CustomAccessibilityAction
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.customActions
import androidx.compose.ui.semantics.onClick
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.stateDescription
@@ -82,7 +98,9 @@
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.util.fastMap
+import androidx.compose.ui.zIndex
import com.android.compose.modifiers.background
+import com.android.compose.modifiers.height
import com.android.systemui.common.ui.compose.load
import com.android.systemui.qs.panels.shared.model.SizedTile
import com.android.systemui.qs.panels.shared.model.SizedTileImpl
@@ -92,14 +110,23 @@
import com.android.systemui.qs.panels.ui.compose.dragAndDropTileList
import com.android.systemui.qs.panels.ui.compose.dragAndDropTileSource
import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileArrangementPadding
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.ToggleTargetSize
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.CurrentTilesGridPadding
+import com.android.systemui.qs.panels.ui.compose.selection.MutableSelectionState
+import com.android.systemui.qs.panels.ui.compose.selection.ResizingHandle
+import com.android.systemui.qs.panels.ui.compose.selection.TileWidths
+import com.android.systemui.qs.panels.ui.compose.selection.clearSelectionTile
+import com.android.systemui.qs.panels.ui.compose.selection.rememberSelectionState
+import com.android.systemui.qs.panels.ui.compose.selection.selectableTile
import com.android.systemui.qs.panels.ui.model.GridCell
import com.android.systemui.qs.panels.ui.model.SpacerGridCell
import com.android.systemui.qs.panels.ui.model.TileGridCell
import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
-import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.shared.model.groupAndSort
import com.android.systemui.res.R
+import kotlinx.coroutines.delay
object TileType
@@ -109,14 +136,11 @@
otherTiles: List<SizedTile<EditTileViewModel>>,
columns: Int,
modifier: Modifier,
- onAddTile: (TileSpec, Int) -> Unit,
onRemoveTile: (TileSpec) -> Unit,
onSetTiles: (List<TileSpec>) -> Unit,
onResize: (TileSpec) -> Unit,
) {
- val addTileToEnd: (TileSpec) -> Unit by rememberUpdatedState {
- onAddTile(it, CurrentTilesInteractor.POSITION_AT_END)
- }
+ val selectionState = rememberSelectionState()
CompositionLocalProvider(LocalOverscrollConfiguration provides null) {
Column(
@@ -138,7 +162,7 @@
}
}
- CurrentTilesGrid(currentListState, columns, onRemoveTile, onResize, onSetTiles)
+ CurrentTilesGrid(currentListState, selectionState, columns, onResize, onSetTiles)
// Hide available tiles when dragging
AnimatedVisibility(
@@ -153,7 +177,7 @@
) {
EditGridHeader { Text(text = "Hold and drag to add tiles.") }
- AvailableTileGrid(otherTiles, columns, addTileToEnd, currentListState)
+ AvailableTileGrid(otherTiles, selectionState, columns, currentListState)
}
}
@@ -201,61 +225,67 @@
}
@Composable
-private fun CurrentTilesContainer(content: @Composable () -> Unit) {
- Box(
- Modifier.fillMaxWidth()
- .border(
- width = 1.dp,
- color = MaterialTheme.colorScheme.onBackground.copy(alpha = .5f),
- shape = RoundedCornerShape(48.dp),
- )
- .padding(dimensionResource(R.dimen.qs_tile_margin_vertical))
- ) {
- content()
- }
-}
-
-@Composable
private fun CurrentTilesGrid(
listState: EditTileListState,
+ selectionState: MutableSelectionState,
columns: Int,
- onClick: (TileSpec) -> Unit,
onResize: (TileSpec) -> Unit,
onSetTiles: (List<TileSpec>) -> Unit,
) {
val currentListState by rememberUpdatedState(listState)
- val tilePadding = CommonTileDefaults.TileArrangementPadding
+ val tileHeight = CommonTileDefaults.TileHeight
+ val totalRows = listState.tiles.lastOrNull()?.row ?: 0
+ val totalHeight by
+ animateDpAsState(
+ gridHeight(totalRows + 1, tileHeight, TileArrangementPadding, CurrentTilesGridPadding),
+ label = "QSEditCurrentTilesGridHeight",
+ )
+ val gridState = rememberLazyGridState()
+ var gridContentOffset by remember { mutableStateOf(Offset(0f, 0f)) }
+ var droppedSpec by remember { mutableStateOf<TileSpec?>(null) }
- CurrentTilesContainer {
- val tileHeight = CommonTileDefaults.TileHeight
- val totalRows = listState.tiles.lastOrNull()?.row ?: 0
- val totalHeight = gridHeight(totalRows + 1, tileHeight, tilePadding)
- val gridState = rememberLazyGridState()
- var gridContentOffset by remember { mutableStateOf(Offset(0f, 0f)) }
+ // Select the tile that was dropped. A delay is introduced to avoid clipping issues on the
+ // selected border and resizing handle, as well as letting the selection animation play.
+ LaunchedEffect(droppedSpec) {
+ droppedSpec?.let {
+ delay(200)
+ selectionState.select(it)
- TileLazyGrid(
- state = gridState,
- modifier =
- Modifier.height(totalHeight)
- .dragAndDropTileList(gridState, gridContentOffset, listState) {
- onSetTiles(currentListState.tileSpecs())
- }
- .onGloballyPositioned { coordinates ->
- gridContentOffset = coordinates.positionInRoot()
- }
- .testTag(CURRENT_TILES_GRID_TEST_TAG),
- columns = GridCells.Fixed(columns),
- ) {
- EditTiles(listState.tiles, onClick, listState, onResize = onResize)
+ // Reset droppedSpec in case a tile is dropped twice in a row
+ droppedSpec = null
}
}
+
+ TileLazyGrid(
+ state = gridState,
+ columns = GridCells.Fixed(columns),
+ contentPadding = PaddingValues(CurrentTilesGridPadding),
+ modifier =
+ Modifier.fillMaxWidth()
+ .height { totalHeight.roundToPx() }
+ .border(
+ width = 1.dp,
+ color = MaterialTheme.colorScheme.onBackground.copy(alpha = .5f),
+ shape = RoundedCornerShape(48.dp),
+ )
+ .dragAndDropTileList(gridState, { gridContentOffset }, listState) { spec ->
+ onSetTiles(currentListState.tileSpecs())
+ droppedSpec = spec
+ }
+ .onGloballyPositioned { coordinates ->
+ gridContentOffset = coordinates.positionInRoot()
+ }
+ .testTag(CURRENT_TILES_GRID_TEST_TAG),
+ ) {
+ EditTiles(listState.tiles, listState, selectionState, onResize)
+ }
}
@Composable
private fun AvailableTileGrid(
tiles: List<SizedTile<EditTileViewModel>>,
+ selectionState: MutableSelectionState,
columns: Int,
- onClick: (TileSpec) -> Unit,
dragAndDropState: DragAndDropState,
) {
// Available tiles aren't visible during drag and drop, so the row isn't needed
@@ -292,7 +322,7 @@
cell = tileGridCell,
index = index,
dragAndDropState = dragAndDropState,
- onClick = onClick,
+ selectionState = selectionState,
modifier = Modifier.weight(1f).fillMaxHeight(),
)
}
@@ -305,8 +335,8 @@
}
}
-fun gridHeight(rows: Int, tileHeight: Dp, padding: Dp): Dp {
- return ((tileHeight + padding) * rows) - padding
+fun gridHeight(rows: Int, tileHeight: Dp, tilePadding: Dp, gridPadding: Dp): Dp {
+ return ((tileHeight + tilePadding) * rows) - tilePadding + gridPadding * 2
}
private fun GridCell.key(index: Int, dragAndDropState: DragAndDropState): Any {
@@ -320,9 +350,9 @@
fun LazyGridScope.EditTiles(
cells: List<GridCell>,
- onClick: (TileSpec) -> Unit,
dragAndDropState: DragAndDropState,
- onResize: (TileSpec) -> Unit = {},
+ selectionState: MutableSelectionState,
+ onResize: (TileSpec) -> Unit,
) {
items(
count = cells.size,
@@ -347,7 +377,7 @@
cell = cell,
index = index,
dragAndDropState = dragAndDropState,
- onClick = onClick,
+ selectionState = selectionState,
onResize = onResize,
)
}
@@ -361,28 +391,171 @@
cell: TileGridCell,
index: Int,
dragAndDropState: DragAndDropState,
- onClick: (TileSpec) -> Unit,
- onResize: (TileSpec) -> Unit = {},
+ selectionState: MutableSelectionState,
+ onResize: (TileSpec) -> Unit,
) {
- val onClickActionName = stringResource(id = R.string.accessibility_qs_edit_remove_tile_action)
+ val selected = selectionState.isSelected(cell.tile.tileSpec)
val stateDescription = stringResource(id = R.string.accessibility_qs_edit_position, index + 1)
+ val selectionAlpha by
+ animateFloatAsState(
+ targetValue = if (selected) 1f else 0f,
+ label = "QSEditTileSelectionAlpha",
+ )
- EditTile(
- tileViewModel = cell.tile,
- iconOnly = cell.isIcon,
- modifier =
- Modifier.animateItem()
- .semantics(mergeDescendants = true) {
- onClick(onClickActionName) { false }
- this.stateDescription = stateDescription
+ val modifier =
+ Modifier.animateItem()
+ .semantics(mergeDescendants = true) {
+ this.stateDescription = stateDescription
+ contentDescription = cell.tile.label.text
+ customActions =
+ listOf(
+ // TODO(b/367748260): Add final accessibility actions
+ CustomAccessibilityAction("Toggle size") {
+ onResize(cell.tile.tileSpec)
+ true
+ }
+ )
+ }
+ .height(CommonTileDefaults.TileHeight)
+ .fillMaxWidth()
+
+ val content =
+ @Composable {
+ EditTile(
+ tileViewModel = cell.tile,
+ iconOnly = cell.isIcon,
+ selectionAlpha = { selectionAlpha },
+ modifier =
+ Modifier.fillMaxSize()
+ .selectableTile(cell.tile.tileSpec, selectionState)
+ .dragAndDropTileSource(
+ SizedTileImpl(cell.tile, cell.width),
+ dragAndDropState,
+ selectionState::unSelect,
+ ),
+ )
+ }
+
+ if (selected) {
+ SelectedTile(
+ tileSpec = cell.tile.tileSpec,
+ isIcon = cell.isIcon,
+ selectionAlpha = { selectionAlpha },
+ selectionState = selectionState,
+ onResize = onResize,
+ modifier = modifier.zIndex(2f), // 2f to display this tile over neighbors when dragged
+ content = content,
+ )
+ } else {
+ UnselectedTile(
+ selectionAlpha = { selectionAlpha },
+ selectionState = selectionState,
+ modifier = modifier,
+ content = content,
+ )
+ }
+}
+
+@Composable
+private fun SelectedTile(
+ tileSpec: TileSpec,
+ isIcon: Boolean,
+ selectionAlpha: () -> Float,
+ selectionState: MutableSelectionState,
+ onResize: (TileSpec) -> Unit,
+ modifier: Modifier = Modifier,
+ content: @Composable () -> Unit,
+) {
+ // Current base, min and max width of this tile
+ var tileWidths: TileWidths? by remember { mutableStateOf(null) }
+
+ // Animated diff between the current width and the resized width of the tile. We can't use
+ // animateContentSize here as the tile is sometimes unbounded.
+ val remainingOffset by
+ animateIntAsState(
+ selectionState.resizingState?.let { tileWidths?.base?.minus(it.width) ?: 0 } ?: 0,
+ label = "QSEditTileWidthOffset",
+ )
+
+ val padding = with(LocalDensity.current) { TileArrangementPadding.roundToPx() }
+ Box(
+ modifier.onSizeChanged {
+ val min = if (isIcon) it.width else (it.width - padding) / 2
+ val max = if (isIcon) (it.width * 2) + padding else it.width
+ tileWidths = TileWidths(it.width, min, max)
+ }
+ ) {
+ val handle =
+ @Composable {
+ ResizingHandle(
+ enabled = true,
+ selectionState = selectionState,
+ transition = selectionAlpha,
+ tileWidths = { tileWidths },
+ ) {
+ onResize(tileSpec)
}
- .dragAndDropTileSource(
- SizedTileImpl(cell.tile, cell.width),
- dragAndDropState,
- onClick,
- onResize,
- ),
- )
+ }
+
+ Layout(contents = listOf(content, handle)) {
+ (contentMeasurables, handleMeasurables),
+ constraints ->
+ // Grab the width from the resizing state if a resize is in progress, otherwise fill the
+ // max width
+ val width =
+ selectionState.resizingState?.width ?: (constraints.maxWidth - remainingOffset)
+ val contentPlaceable =
+ contentMeasurables.first().measure(constraints.copy(maxWidth = width))
+ val handlePlaceable = handleMeasurables.first().measure(constraints)
+
+ // Place the dot vertically centered on the right edge
+ val handleX = contentPlaceable.width - (handlePlaceable.width / 2)
+ val handleY = (contentPlaceable.height / 2) - (handlePlaceable.height / 2)
+
+ layout(constraints.maxWidth, constraints.maxHeight) {
+ contentPlaceable.place(0, 0)
+ handlePlaceable.place(handleX, handleY)
+ }
+ }
+ }
+}
+
+@Composable
+private fun UnselectedTile(
+ selectionAlpha: () -> Float,
+ selectionState: MutableSelectionState,
+ modifier: Modifier = Modifier,
+ content: @Composable () -> Unit,
+) {
+ val handle =
+ @Composable {
+ ResizingHandle(
+ enabled = false,
+ selectionState = selectionState,
+ transition = selectionAlpha,
+ )
+ }
+
+ Box(modifier) {
+ Layout(contents = listOf(content, handle)) {
+ (contentMeasurables, handleMeasurables),
+ constraints ->
+ val contentPlaceable =
+ contentMeasurables
+ .first()
+ .measure(constraints.copy(maxWidth = constraints.maxWidth))
+ val handlePlaceable = handleMeasurables.first().measure(constraints)
+
+ // Place the dot vertically centered on the right edge
+ val handleX = contentPlaceable.width - (handlePlaceable.width / 2)
+ val handleY = (contentPlaceable.height / 2) - (handlePlaceable.height / 2)
+
+ layout(constraints.maxWidth, constraints.maxHeight) {
+ contentPlaceable.place(0, 0)
+ handlePlaceable.place(handleX, handleY)
+ }
+ }
+ }
}
@Composable
@@ -390,8 +563,8 @@
cell: TileGridCell,
index: Int,
dragAndDropState: DragAndDropState,
+ selectionState: MutableSelectionState,
modifier: Modifier = Modifier,
- onClick: (TileSpec) -> Unit,
) {
val onClickActionName = stringResource(id = R.string.accessibility_qs_edit_tile_add_action)
val stateDescription = stringResource(id = R.string.accessibility_qs_edit_position, index + 1)
@@ -403,21 +576,27 @@
verticalArrangement = spacedBy(CommonTileDefaults.TilePadding, Alignment.Top),
modifier = modifier,
) {
- EditTile(
- tileViewModel = cell.tile,
- iconOnly = true,
+ EditTileContainer(
colors = colors,
modifier =
- Modifier.semantics(mergeDescendants = true) {
+ Modifier.fillMaxWidth()
+ .height(CommonTileDefaults.TileHeight)
+ .clearSelectionTile(selectionState)
+ .semantics(mergeDescendants = true) {
onClick(onClickActionName) { false }
this.stateDescription = stateDescription
}
- .dragAndDropTileSource(
- SizedTileImpl(cell.tile, cell.width),
- dragAndDropState,
- onTap = onClick,
- ),
- )
+ .dragAndDropTileSource(SizedTileImpl(cell.tile, cell.width), dragAndDropState) {
+ selectionState.unSelect()
+ },
+ ) {
+ // Icon
+ SmallTileContent(
+ icon = cell.tile.icon,
+ color = colors.icon,
+ modifier = Modifier.align(Alignment.Center),
+ )
+ }
Box(Modifier.fillMaxSize()) {
Text(
cell.tile.label.text,
@@ -434,7 +613,7 @@
@Composable
private fun SpacerGridCell(modifier: Modifier = Modifier) {
// By default, spacers are invisible and exist purely to catch drag movements
- Box(modifier.height(CommonTileDefaults.TileHeight).fillMaxWidth().tilePadding())
+ Box(modifier.height(CommonTileDefaults.TileHeight).fillMaxWidth())
}
@Composable
@@ -443,20 +622,35 @@
iconOnly: Boolean,
modifier: Modifier = Modifier,
colors: TileColors = EditModeTileDefaults.editTileColors(),
+ selectionAlpha: () -> Float = { 1f },
) {
- EditTileContainer(colors = colors, modifier = modifier) {
- if (iconOnly) {
+ // Animated horizontal alignment from center (0f) to start (-1f)
+ val alignmentValue by
+ animateFloatAsState(
+ targetValue = if (iconOnly) 0f else -1f,
+ label = "QSEditTileContentAlignment",
+ )
+ val alignment by remember {
+ derivedStateOf { BiasAlignment(horizontalBias = alignmentValue, verticalBias = 0f) }
+ }
+
+ EditTileContainer(colors = colors, selectionAlpha = selectionAlpha, modifier = modifier) {
+ // Icon
+ Box(Modifier.size(ToggleTargetSize).align(alignment)) {
SmallTileContent(
icon = tileViewModel.icon,
color = colors.icon,
modifier = Modifier.align(Alignment.Center),
)
- } else {
- LargeTileContent(
+ }
+
+ // Labels, positioned after the icon
+ AnimatedVisibility(visible = !iconOnly, enter = fadeIn(), exit = fadeOut()) {
+ LargeTileLabels(
label = tileViewModel.label.text,
secondaryLabel = tileViewModel.appName?.text,
- icon = tileViewModel.icon,
colors = colors,
+ modifier = Modifier.padding(start = ToggleTargetSize + TileArrangementPadding),
)
}
}
@@ -466,27 +660,41 @@
private fun EditTileContainer(
colors: TileColors,
modifier: Modifier = Modifier,
- content: @Composable BoxScope.() -> Unit,
+ selectionAlpha: () -> Float = { 0f },
+ selectionColor: Color = MaterialTheme.colorScheme.primary,
+ content: @Composable BoxScope.() -> Unit = {},
) {
Box(
- modifier =
- modifier
- .height(CommonTileDefaults.TileHeight)
- .fillMaxWidth()
- .drawBehind {
- drawRoundRect(
- SolidColor(colors.background),
- cornerRadius = CornerRadius(InactiveCornerRadius.toPx()),
- )
- }
- .tilePadding(),
- content = content,
- )
+ Modifier.wrapContentSize().drawWithContent {
+ drawContent()
+ drawRoundRect(
+ SolidColor(selectionColor),
+ cornerRadius = CornerRadius(InactiveCornerRadius.toPx()),
+ style = Stroke(EditModeTileDefaults.SelectedBorderWidth.toPx()),
+ alpha = selectionAlpha(),
+ )
+ }
+ ) {
+ Box(
+ modifier =
+ modifier
+ .drawBehind {
+ drawRoundRect(
+ SolidColor(colors.background),
+ cornerRadius = CornerRadius(InactiveCornerRadius.toPx()),
+ )
+ }
+ .tilePadding(),
+ content = content,
+ )
+ }
}
private object EditModeTileDefaults {
const val PLACEHOLDER_ALPHA = .3f
val EditGridHeaderHeight = 60.dp
+ val SelectedBorderWidth = 2.dp
+ val CurrentTilesGridPadding = 8.dp
@Composable
fun editTileColors(): TileColors =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
index f96c27d..8a96065 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
@@ -16,15 +16,17 @@
package com.android.systemui.qs.panels.ui.compose.infinitegrid
-import androidx.compose.foundation.lazy.grid.GridCells
-import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.util.fastMap
import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.compose.animation.scene.SceneScope
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.grid.ui.compose.VerticalSpannedGrid
import com.android.systemui.qs.panels.shared.model.SizedTileImpl
import com.android.systemui.qs.panels.ui.compose.PaginatableGridLayout
import com.android.systemui.qs.panels.ui.compose.rememberEditListState
@@ -33,6 +35,8 @@
import com.android.systemui.qs.panels.ui.viewmodel.IconTilesViewModel
import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.shared.ui.ElementKeys.toElementKey
+import com.android.systemui.res.R
import javax.inject.Inject
@SysUISingleton
@@ -44,7 +48,7 @@
) : PaginatableGridLayout {
@Composable
- override fun TileGrid(
+ override fun SceneScope.TileGrid(
tiles: List<TileViewModel>,
modifier: Modifier,
editModeStart: () -> Unit,
@@ -57,15 +61,18 @@
val columns by gridSizeViewModel.columns.collectAsStateWithLifecycle()
val sizedTiles = tiles.map { SizedTileImpl(it, it.spec.width()) }
- TileLazyGrid(modifier = modifier, columns = GridCells.Fixed(columns)) {
- items(sizedTiles.size, span = { index -> GridItemSpan(sizedTiles[index].width) }) {
- index ->
- Tile(
- tile = sizedTiles[index].tile,
- iconOnly = iconTilesViewModel.isIconTile(sizedTiles[index].tile.spec),
- modifier = Modifier,
- )
- }
+ VerticalSpannedGrid(
+ columns = columns,
+ columnSpacing = dimensionResource(R.dimen.qs_tile_margin_horizontal),
+ rowSpacing = dimensionResource(R.dimen.qs_tile_margin_vertical),
+ spans = sizedTiles.fastMap { it.width },
+ ) { spanIndex ->
+ val it = sizedTiles[spanIndex]
+ Tile(
+ tile = it.tile,
+ iconOnly = iconTilesViewModel.isIconTile(it.tile.spec),
+ modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)),
+ )
}
}
@@ -98,7 +105,6 @@
otherTiles = otherTiles,
columns = columns,
modifier = modifier,
- onAddTile = onAddTile,
onRemoveTile = onRemoveTile,
onSetTiles = onSetTiles,
onResize = iconTilesViewModel::resize,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
index aa6c08e..afcbed6d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
@@ -29,6 +29,7 @@
import androidx.compose.foundation.layout.Arrangement.spacedBy
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
@@ -82,6 +83,7 @@
columns: GridCells,
modifier: Modifier = Modifier,
state: LazyGridState = rememberLazyGridState(),
+ contentPadding: PaddingValues = PaddingValues(0.dp),
content: LazyGridScope.() -> Unit,
) {
LazyVerticalGrid(
@@ -89,6 +91,7 @@
columns = columns,
verticalArrangement = spacedBy(CommonTileDefaults.TileArrangementPadding),
horizontalArrangement = spacedBy(CommonTileDefaults.TileArrangementPadding),
+ contentPadding = contentPadding,
modifier = modifier,
content = content,
)
@@ -140,6 +143,7 @@
}
},
onLongClick = { tile.onLongClick(expandable) },
+ accessibilityUiState = uiState.accessibilityUiState,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
new file mode 100644
index 0000000..2ea32e6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.ui.compose.selection
+
+import androidx.compose.foundation.gestures.detectTapGestures
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.pointer.pointerInput
+import com.android.systemui.qs.pipeline.shared.TileSpec
+
+/** Creates the state of the current selected tile that is remembered across compositions. */
+@Composable
+fun rememberSelectionState(): MutableSelectionState {
+ return remember { MutableSelectionState() }
+}
+
+/** Holds the state of the current selection. */
+class MutableSelectionState {
+ private var _selectedTile = mutableStateOf<TileSpec?>(null)
+ private var _resizingState = mutableStateOf<ResizingState?>(null)
+
+ /** The [ResizingState] of the selected tile is currently being resized, null if not. */
+ val resizingState by _resizingState
+
+ fun isSelected(tileSpec: TileSpec): Boolean {
+ return _selectedTile.value?.let { it == tileSpec } ?: false
+ }
+
+ fun select(tileSpec: TileSpec) {
+ _selectedTile.value = tileSpec
+ }
+
+ fun unSelect() {
+ _selectedTile.value = null
+ onResizingDragEnd()
+ }
+
+ fun onResizingDrag(offset: Float) {
+ _resizingState.value?.onDrag(offset)
+ }
+
+ fun onResizingDragStart(tileWidths: TileWidths, onResize: () -> Unit) {
+ if (_selectedTile.value == null) return
+
+ _resizingState.value = ResizingState(tileWidths, onResize)
+ }
+
+ fun onResizingDragEnd() {
+ _resizingState.value = null
+ }
+}
+
+/**
+ * Listens for click events to select/unselect the given [TileSpec]. Use this on current tiles as
+ * they can be selected.
+ */
+@Composable
+fun Modifier.selectableTile(tileSpec: TileSpec, selectionState: MutableSelectionState): Modifier {
+ return pointerInput(Unit) {
+ detectTapGestures(
+ onTap = {
+ if (selectionState.isSelected(tileSpec)) {
+ selectionState.unSelect()
+ } else {
+ selectionState.select(tileSpec)
+ }
+ }
+ )
+ }
+}
+
+/**
+ * Listens for click events to unselect any tile. Use this on available tiles as they can't be
+ * selected.
+ */
+@Composable
+fun Modifier.clearSelectionTile(selectionState: MutableSelectionState): Modifier {
+ return pointerInput(Unit) { detectTapGestures(onTap = { selectionState.unSelect() }) }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingState.kt
new file mode 100644
index 0000000..a084bc2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingState.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.ui.compose.selection
+
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.setValue
+import com.android.systemui.qs.panels.ui.compose.selection.ResizingDefaults.RESIZING_THRESHOLD
+
+class ResizingState(private val widths: TileWidths, private val onResize: () -> Unit) {
+ // Total drag offset of this resize operation
+ private var totalOffset = 0f
+
+ /** Width in pixels of the resizing tile. */
+ var width by mutableIntStateOf(widths.base)
+
+ // Whether the tile is currently over the threshold and should be a large tile
+ private var passedThreshold: Boolean = passedThreshold(calculateProgression(width))
+
+ fun onDrag(offset: Float) {
+ totalOffset += offset
+ width = (widths.base + totalOffset).toInt().coerceIn(widths.min, widths.max)
+
+ passedThreshold(calculateProgression(width)).let {
+ // Resize if we went over the threshold
+ if (passedThreshold != it) {
+ passedThreshold = it
+ onResize()
+ }
+ }
+ }
+
+ private fun passedThreshold(progression: Float): Boolean {
+ return progression >= RESIZING_THRESHOLD
+ }
+
+ /** The progression of the resizing tile between an icon tile (0f) and a large tile (1f) */
+ private fun calculateProgression(width: Int): Float {
+ return ((width - widths.min) / (widths.max - widths.min).toFloat()).coerceIn(0f, 1f)
+ }
+}
+
+/** Holds the width of a tile as well as its min and max widths */
+data class TileWidths(val base: Int, val min: Int, val max: Int) {
+ init {
+ check(max > min) { "The max width needs to be larger than the min width." }
+ }
+}
+
+private object ResizingDefaults {
+ const val RESIZING_THRESHOLD = .25f
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
new file mode 100644
index 0000000..e3acf38
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
@@ -0,0 +1,88 @@
+/*
+ * 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.qs.panels.ui.compose.selection
+
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.gestures.detectHorizontalDragGestures
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.LocalMinimumInteractiveComponentSize
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.unit.dp
+import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.ResizingDotSize
+
+/**
+ * Dot handling resizing drag events. Use this on the selected tile to resize it
+ *
+ * @param enabled whether resizing drag events should be handled
+ * @param selectionState the [MutableSelectionState] on the grid
+ * @param transition the animated value for the dot, used for its alpha and scale
+ * @param tileWidths the [TileWidths] of the selected tile
+ * @param onResize the callback when the drag passes the resizing threshold
+ */
+@Composable
+fun ResizingHandle(
+ enabled: Boolean,
+ selectionState: MutableSelectionState,
+ transition: () -> Float,
+ tileWidths: () -> TileWidths? = { null },
+ onResize: () -> Unit = {},
+) {
+ if (enabled) {
+ // Manually creating the touch target around the resizing dot to ensure that the next tile
+ // does
+ // not receive the touch input accidentally.
+ val minTouchTargetSize = LocalMinimumInteractiveComponentSize.current
+ Box(
+ Modifier.size(minTouchTargetSize).pointerInput(Unit) {
+ detectHorizontalDragGestures(
+ onHorizontalDrag = { _, offset -> selectionState.onResizingDrag(offset) },
+ onDragStart = {
+ tileWidths()?.let { selectionState.onResizingDragStart(it, onResize) }
+ },
+ onDragEnd = selectionState::onResizingDragEnd,
+ onDragCancel = selectionState::onResizingDragEnd,
+ )
+ }
+ ) {
+ ResizingDot(transition = transition, modifier = Modifier.align(Alignment.Center))
+ }
+ } else {
+ ResizingDot(transition = transition)
+ }
+}
+
+@Composable
+private fun ResizingDot(
+ transition: () -> Float,
+ modifier: Modifier = Modifier,
+ color: Color = MaterialTheme.colorScheme.primary,
+) {
+ Canvas(modifier = modifier.size(ResizingDotSize)) {
+ val v = transition()
+ drawCircle(color = color, radius = (ResizingDotSize / 2).toPx() * v, alpha = v)
+ }
+}
+
+private object SelectionDefaults {
+ val ResizingDotSize = 16.dp
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/shared/ui/ElementKeys.kt b/packages/SystemUI/src/com/android/systemui/qs/shared/ui/ElementKeys.kt
new file mode 100644
index 0000000..625459d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/shared/ui/ElementKeys.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.shared.ui
+
+import com.android.compose.animation.scene.ElementKey
+import com.android.systemui.qs.pipeline.shared.TileSpec
+
+/** Element keys to be used by the compose implementation of QS for animations. */
+object ElementKeys {
+ val QuickSettingsContent = ElementKey("QuickSettingsContent")
+ val GridAnchor = ElementKey("QuickSettingsGridAnchor")
+ val FooterActions = ElementKey("FooterActions")
+
+ class TileElementKey(spec: TileSpec, val position: Int) : ElementKey(spec.spec, spec.spec)
+
+ fun TileSpec.toElementKey(positionInGrid: Int) = TileElementKey(this, positionInGrid)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt
index d0437a7..b8f4ab4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.base.viewmodel
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
import com.android.systemui.dagger.qualifiers.Application
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -27,5 +28,5 @@
constructor(@Application private val applicationScope: CoroutineScope) {
fun create(): CoroutineScope =
- CoroutineScope(applicationScope.coroutineContext + SupervisorJob())
+ CoroutineScope(applicationScope.coroutineContext + SupervisorJob() + createCoroutineTracingContext("QSTileScope"))
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt
index 246fe38..ae56c2a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.qs.tiles.dialog
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
import android.util.Log
import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.animation.DialogCuj
@@ -62,7 +63,7 @@
}
return
} else {
- coroutineScope = CoroutineScope(bgDispatcher)
+ coroutineScope = CoroutineScope(bgDispatcher + createCoroutineTracingContext("InternetDialogScope"))
dialog =
dialogFactory
.create(aboveStatusBar, canConfigMobileData, canConfigWifi, coroutineScope)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/interactor/LocationTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/interactor/LocationTileUserActionInteractor.kt
index cca947f..ac75932 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/interactor/LocationTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/interactor/LocationTileUserActionInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.impl.location.domain.interactor
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
import android.content.Intent
import android.provider.Settings
import com.android.systemui.dagger.qualifiers.Application
@@ -52,7 +53,7 @@
val wasEnabled: Boolean = input.data.isEnabled
if (keyguardController.isMethodSecure() && keyguardController.isShowing()) {
activityStarter.postQSRunnableDismissingKeyguard {
- CoroutineScope(applicationScope.coroutineContext).launch {
+ CoroutineScope(applicationScope.coroutineContext + createCoroutineTracingContext("LocationTileScope")).launch {
locationController.setLocationEnabled(!wasEnabled)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt
index b25c61c..468e180 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.impl.saver.domain
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
import android.content.Context
import android.content.DialogInterface
import android.content.SharedPreferences
@@ -44,7 +45,7 @@
setTitle(R.string.data_saver_enable_title)
setMessage(R.string.data_saver_description)
setPositiveButton(R.string.data_saver_enable_button) { _: DialogInterface?, _ ->
- CoroutineScope(backgroundContext).launch {
+ CoroutineScope(backgroundContext + createCoroutineTracingContext("DataSaverDialogScope")).launch {
dataSaverController.setDataSaverEnabled(true)
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index b7e2cf2..286cac1 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -193,22 +193,16 @@
// We are in a session if either Shade or QuickSettings is on the back stack
.map { backStack ->
backStack.asIterable().any {
+ // TODO(b/356596436): Include overlays in the back stack as well.
it == Scenes.Shade || it == Scenes.QuickSettings
}
}
.distinctUntilChanged(),
- sceneInteractor.transitionState
- .mapNotNull { state ->
- // We are also in a session if either Shade or QuickSettings is the
- // current scene
- when (state) {
- is ObservableTransitionState.Idle -> state.currentScene
- is ObservableTransitionState.Transition -> state.fromContent
- }.let { it == Scenes.Shade || it == Scenes.QuickSettings }
- }
- .distinctUntilChanged(),
- ) { inBackStack, isCurrentScene ->
- inBackStack || isCurrentScene
+ // We are also in a session if either Notifications Shade or QuickSettings Shade
+ // is currently shown (whether idle or animating).
+ shadeInteractor.isAnyExpanded,
+ ) { inBackStack, isShadeShown ->
+ inBackStack || isShadeShown
}
// Once a session has ended, clear the session storage.
.filter { inSession -> !inSession }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotController.java
index f69b0cb..7724abd4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotController.java
@@ -505,8 +505,8 @@
return;
}
// delay starting scroll capture to make sure scrim is up before the app moves
- mViewProxy.prepareScrollingTransition(response, mScreenBitmap, newScreenshot,
- mScreenshotTakenInPortrait, () -> executeBatchScrollCapture(response, owner));
+ mViewProxy.prepareScrollingTransition(response, newScreenshot, mScreenshotTakenInPortrait,
+ () -> executeBatchScrollCapture(response, owner));
}
private void executeBatchScrollCapture(ScrollCaptureResponse response, UserHandle owner) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
deleted file mode 100644
index fe58bc9..0000000
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ /dev/null
@@ -1,663 +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.screenshot;
-
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-
-import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
-import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
-import static com.android.systemui.screenshot.LogConfig.DEBUG_INPUT;
-import static com.android.systemui.screenshot.LogConfig.DEBUG_UI;
-import static com.android.systemui.screenshot.LogConfig.DEBUG_WINDOW;
-import static com.android.systemui.screenshot.LogConfig.logTag;
-import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_DISMISSED_OTHER;
-import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.graphics.Insets;
-import android.graphics.Rect;
-import android.net.Uri;
-import android.os.Process;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.Display;
-import android.view.ScrollCaptureResponse;
-import android.view.ViewRootImpl;
-import android.view.WindowManager;
-import android.widget.Toast;
-import android.window.WindowContext;
-
-import com.android.internal.logging.UiEventLogger;
-import com.android.settingslib.applications.InterestingConfigChanges;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.broadcast.BroadcastSender;
-import com.android.systemui.clipboardoverlay.ClipboardOverlayController;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.res.R;
-import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback;
-import com.android.systemui.screenshot.scroll.ScrollCaptureExecutor;
-import com.android.systemui.util.Assert;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-import dagger.assisted.Assisted;
-import dagger.assisted.AssistedFactory;
-import dagger.assisted.AssistedInject;
-
-import kotlin.Unit;
-
-import java.util.UUID;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.function.Consumer;
-
-import javax.inject.Provider;
-
-/**
- * Controls the state and flow for screenshots.
- */
-public class ScreenshotController implements InteractiveScreenshotHandler {
- private static final String TAG = logTag(ScreenshotController.class);
-
- // From WizardManagerHelper.java
- private static final String SETTINGS_SECURE_USER_SETUP_COMPLETE = "user_setup_complete";
-
- static final int SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS = 6000;
-
- private final WindowContext mContext;
- private final FeatureFlags mFlags;
- private final ScreenshotShelfViewProxy mViewProxy;
- private final ScreenshotNotificationsController mNotificationsController;
- private final ScreenshotSmartActions mScreenshotSmartActions;
- private final UiEventLogger mUiEventLogger;
- private final ImageExporter mImageExporter;
- private final ImageCapture mImageCapture;
- private final Executor mMainExecutor;
- private final ExecutorService mBgExecutor;
- private final BroadcastSender mBroadcastSender;
- private final BroadcastDispatcher mBroadcastDispatcher;
- private final ScreenshotActionsController mActionsController;
-
- @Nullable
- private final ScreenshotSoundController mScreenshotSoundController;
- private final ScreenshotWindow mWindow;
- private final Display mDisplay;
- private final ScrollCaptureExecutor mScrollCaptureExecutor;
- private final ScreenshotNotificationSmartActionsProvider
- mScreenshotNotificationSmartActionsProvider;
- private final TimeoutHandler mScreenshotHandler;
- private final UserManager mUserManager;
- private final AssistContentRequester mAssistContentRequester;
- private final ActionExecutor mActionExecutor;
-
-
- private final MessageContainerController mMessageContainerController;
- private final AnnouncementResolver mAnnouncementResolver;
- private Bitmap mScreenBitmap;
- private boolean mScreenshotTakenInPortrait;
- private Animator mScreenshotAnimation;
- private RequestCallback mCurrentRequestCallback;
- private String mPackageName = "";
- private final BroadcastReceiver mCopyBroadcastReceiver;
-
- /** Tracks config changes that require re-creating UI */
- private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
- ActivityInfo.CONFIG_ORIENTATION
- | ActivityInfo.CONFIG_LAYOUT_DIRECTION
- | ActivityInfo.CONFIG_LOCALE
- | ActivityInfo.CONFIG_UI_MODE
- | ActivityInfo.CONFIG_SCREEN_LAYOUT
- | ActivityInfo.CONFIG_ASSETS_PATHS);
-
-
- @AssistedInject
- ScreenshotController(
- Context context,
- ScreenshotWindow.Factory screenshotWindowFactory,
- FeatureFlags flags,
- ScreenshotShelfViewProxy.Factory viewProxyFactory,
- ScreenshotSmartActions screenshotSmartActions,
- ScreenshotNotificationsController.Factory screenshotNotificationsControllerFactory,
- UiEventLogger uiEventLogger,
- ImageExporter imageExporter,
- ImageCapture imageCapture,
- @Main Executor mainExecutor,
- ScrollCaptureExecutor scrollCaptureExecutor,
- TimeoutHandler timeoutHandler,
- BroadcastSender broadcastSender,
- BroadcastDispatcher broadcastDispatcher,
- ScreenshotNotificationSmartActionsProvider screenshotNotificationSmartActionsProvider,
- ScreenshotActionsController.Factory screenshotActionsControllerFactory,
- ActionExecutor.Factory actionExecutorFactory,
- UserManager userManager,
- AssistContentRequester assistContentRequester,
- MessageContainerController messageContainerController,
- Provider<ScreenshotSoundController> screenshotSoundController,
- AnnouncementResolver announcementResolver,
- @Assisted Display display
- ) {
- mScreenshotSmartActions = screenshotSmartActions;
- mNotificationsController = screenshotNotificationsControllerFactory.create(
- display.getDisplayId());
- mUiEventLogger = uiEventLogger;
- mImageExporter = imageExporter;
- mImageCapture = imageCapture;
- mMainExecutor = mainExecutor;
- mScrollCaptureExecutor = scrollCaptureExecutor;
- mScreenshotNotificationSmartActionsProvider = screenshotNotificationSmartActionsProvider;
- mBgExecutor = Executors.newSingleThreadExecutor();
- mBroadcastSender = broadcastSender;
- mBroadcastDispatcher = broadcastDispatcher;
-
- mScreenshotHandler = timeoutHandler;
- mScreenshotHandler.setDefaultTimeoutMillis(SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS);
-
- mDisplay = display;
- mWindow = screenshotWindowFactory.create(mDisplay);
- mContext = mWindow.getContext();
- mFlags = flags;
- mUserManager = userManager;
- mMessageContainerController = messageContainerController;
- mAssistContentRequester = assistContentRequester;
- mAnnouncementResolver = announcementResolver;
-
- mViewProxy = viewProxyFactory.getProxy(mContext, mDisplay.getDisplayId());
-
- mScreenshotHandler.setOnTimeoutRunnable(() -> {
- if (DEBUG_UI) {
- Log.d(TAG, "Corner timeout hit");
- }
- mViewProxy.requestDismissal(SCREENSHOT_INTERACTION_TIMEOUT);
- });
-
- mConfigChanges.applyNewConfig(context.getResources());
- reloadAssets();
-
- mActionExecutor = actionExecutorFactory.create(mWindow.getWindow(), mViewProxy,
- () -> {
- finishDismiss();
- return Unit.INSTANCE;
- });
- mActionsController = screenshotActionsControllerFactory.getController(mActionExecutor);
-
-
- // Sound is only reproduced from the controller of the default display.
- if (mDisplay.getDisplayId() == Display.DEFAULT_DISPLAY) {
- mScreenshotSoundController = screenshotSoundController.get();
- } else {
- mScreenshotSoundController = null;
- }
-
- mCopyBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (ClipboardOverlayController.COPY_OVERLAY_ACTION.equals(intent.getAction())) {
- mViewProxy.requestDismissal(SCREENSHOT_DISMISSED_OTHER);
- }
- }
- };
- mBroadcastDispatcher.registerReceiver(mCopyBroadcastReceiver, new IntentFilter(
- ClipboardOverlayController.COPY_OVERLAY_ACTION), null, null,
- Context.RECEIVER_NOT_EXPORTED, ClipboardOverlayController.SELF_PERMISSION);
- }
-
- @Override
- public void handleScreenshot(ScreenshotData screenshot, Consumer<Uri> finisher,
- RequestCallback requestCallback) {
- Assert.isMainThread();
-
- mCurrentRequestCallback = requestCallback;
- if (screenshot.getType() == WindowManager.TAKE_SCREENSHOT_FULLSCREEN
- && screenshot.getBitmap() == null) {
- Rect bounds = getFullScreenRect();
- screenshot.setBitmap(mImageCapture.captureDisplay(mDisplay.getDisplayId(), bounds));
- screenshot.setScreenBounds(bounds);
- }
-
- if (screenshot.getBitmap() == null) {
- Log.e(TAG, "handleScreenshot: Screenshot bitmap was null");
- mNotificationsController.notifyScreenshotError(
- R.string.screenshot_failed_to_capture_text);
- if (mCurrentRequestCallback != null) {
- mCurrentRequestCallback.reportError();
- }
- return;
- }
-
- mScreenBitmap = screenshot.getBitmap();
- String oldPackageName = mPackageName;
- mPackageName = screenshot.getPackageNameString();
-
- if (!isUserSetupComplete(Process.myUserHandle())) {
- Log.w(TAG, "User setup not complete, displaying toast only");
- // User setup isn't complete, so we don't want to show any UI beyond a toast, as editing
- // and sharing shouldn't be exposed to the user.
- saveScreenshotAndToast(screenshot, finisher);
- return;
- }
-
- mBroadcastSender.sendBroadcast(new Intent(ClipboardOverlayController.SCREENSHOT_ACTION),
- ClipboardOverlayController.SELF_PERMISSION);
-
- mScreenshotTakenInPortrait =
- mContext.getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT;
-
- // Optimizations
- mScreenBitmap.setHasAlpha(false);
- mScreenBitmap.prepareToDraw();
-
- prepareViewForNewScreenshot(screenshot, oldPackageName);
-
- final UUID requestId;
- requestId = mActionsController.setCurrentScreenshot(screenshot);
- saveScreenshotInBackground(screenshot, requestId, finisher, result -> {
- if (result.uri != null) {
- ScreenshotSavedResult savedScreenshot = new ScreenshotSavedResult(
- result.uri, screenshot.getUserOrDefault(), result.timestamp);
- mActionsController.setCompletedScreenshot(requestId, savedScreenshot);
- }
- });
-
- if (screenshot.getTaskId() >= 0) {
- mAssistContentRequester.requestAssistContent(
- screenshot.getTaskId(),
- assistContent ->
- mActionsController.onAssistContent(requestId, assistContent));
- } else {
- mActionsController.onAssistContent(requestId, null);
- }
-
- // The window is focusable by default
- mWindow.setFocusable(true);
- mViewProxy.requestFocus();
-
- enqueueScrollCaptureRequest(requestId, screenshot.getUserHandle());
-
- mWindow.attachWindow();
-
- boolean showFlash;
- if (screenshot.getType() == WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE) {
- if (screenshot.getScreenBounds() != null
- && aspectRatiosMatch(screenshot.getBitmap(), screenshot.getInsets(),
- screenshot.getScreenBounds())) {
- showFlash = false;
- } else {
- showFlash = true;
- screenshot.setInsets(Insets.NONE);
- screenshot.setScreenBounds(new Rect(0, 0, screenshot.getBitmap().getWidth(),
- screenshot.getBitmap().getHeight()));
- }
- } else {
- showFlash = true;
- }
-
- mViewProxy.prepareEntranceAnimation(
- () -> startAnimation(screenshot.getScreenBounds(), showFlash,
- () -> mMessageContainerController.onScreenshotTaken(screenshot)));
-
- mViewProxy.setScreenshot(screenshot);
-
- }
-
- void prepareViewForNewScreenshot(@NonNull ScreenshotData screenshot, String oldPackageName) {
- mWindow.whenWindowAttached(() -> {
- mAnnouncementResolver.getScreenshotAnnouncement(
- screenshot.getUserHandle().getIdentifier(),
- announcement -> {
- mViewProxy.announceForAccessibility(announcement);
- });
- });
-
- mViewProxy.reset();
-
- if (mViewProxy.isAttachedToWindow()) {
- // if we didn't already dismiss for another reason
- if (!mViewProxy.isDismissing()) {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_REENTERED, 0,
- oldPackageName);
- }
- if (DEBUG_WINDOW) {
- Log.d(TAG, "saveScreenshot: screenshotView is already attached, resetting. "
- + "(dismissing=" + mViewProxy.isDismissing() + ")");
- }
- }
-
- mViewProxy.setPackageName(mPackageName);
- }
-
- /**
- * Requests the view to dismiss the current screenshot (may be ignored, if screenshot is already
- * being dismissed)
- */
- @Override
- public void requestDismissal(ScreenshotEvent event) {
- mViewProxy.requestDismissal(event);
- }
-
- @Override
- public boolean isPendingSharedTransition() {
- return mActionExecutor.isPendingSharedTransition();
- }
-
- // Any cleanup needed when the service is being destroyed.
- @Override
- public void onDestroy() {
- removeWindow();
- releaseMediaPlayer();
- releaseContext();
- mBgExecutor.shutdown();
- }
-
- /**
- * Release the constructed window context.
- */
- private void releaseContext() {
- mBroadcastDispatcher.unregisterReceiver(mCopyBroadcastReceiver);
- mContext.release();
- }
-
- private void releaseMediaPlayer() {
- if (mScreenshotSoundController == null) return;
- mScreenshotSoundController.releaseScreenshotSoundAsync();
- }
-
- /**
- * Update resources on configuration change. Reinflate for theme/color changes.
- */
- private void reloadAssets() {
- if (DEBUG_UI) {
- Log.d(TAG, "reloadAssets()");
- }
-
- mMessageContainerController.setView(mViewProxy.getView());
- mViewProxy.setCallbacks(new ScreenshotShelfViewProxy.ScreenshotViewCallback() {
- @Override
- public void onUserInteraction() {
- if (DEBUG_INPUT) {
- Log.d(TAG, "onUserInteraction");
- }
- mScreenshotHandler.resetTimeout();
- }
-
- @Override
- public void onDismiss() {
- finishDismiss();
- }
-
- @Override
- public void onTouchOutside() {
- // TODO(159460485): Remove this when focus is handled properly in the system
- mWindow.setFocusable(false);
- }
- });
-
- if (DEBUG_WINDOW) {
- Log.d(TAG, "setContentView: " + mViewProxy.getView());
- }
- mWindow.setContentView(mViewProxy.getView());
- }
-
- private void enqueueScrollCaptureRequest(UUID requestId, UserHandle owner) {
- // Wait until this window is attached to request because it is
- // the reference used to locate the target window (below).
- mWindow.whenWindowAttached(() -> {
- requestScrollCapture(requestId, owner);
- mWindow.setActivityConfigCallback(
- new ViewRootImpl.ActivityConfigCallback() {
- @Override
- public void onConfigurationChanged(Configuration overrideConfig,
- int newDisplayId) {
- if (mConfigChanges.applyNewConfig(mContext.getResources())) {
- // Hide the scroll chip until we know it's available in this
- // orientation
- mActionsController.onScrollChipInvalidated();
- // Delay scroll capture eval a bit to allow the underlying activity
- // to set up in the new orientation.
- mScreenshotHandler.postDelayed(
- () -> requestScrollCapture(requestId, owner), 150);
- mViewProxy.updateInsets(mWindow.getWindowInsets());
- // Screenshot animation calculations won't be valid anymore,
- // so just end
- if (mScreenshotAnimation != null
- && mScreenshotAnimation.isRunning()) {
- mScreenshotAnimation.end();
- }
- }
- }
- });
- });
- }
-
- private void requestScrollCapture(UUID requestId, UserHandle owner) {
- mScrollCaptureExecutor.requestScrollCapture(
- mDisplay.getDisplayId(),
- mWindow.getWindowToken(),
- (response) -> {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_IMPRESSION,
- 0, response.getPackageName());
- mActionsController.onScrollChipReady(requestId,
- () -> onScrollButtonClicked(owner, response));
- return Unit.INSTANCE;
- }
- );
- }
-
- private void onScrollButtonClicked(UserHandle owner, ScrollCaptureResponse response) {
- if (DEBUG_INPUT) {
- Log.d(TAG, "scroll chip tapped");
- }
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_REQUESTED, 0,
- response.getPackageName());
- Bitmap newScreenshot = mImageCapture.captureDisplay(mDisplay.getDisplayId(),
- getFullScreenRect());
- if (newScreenshot == null) {
- Log.e(TAG, "Failed to capture current screenshot for scroll transition!");
- return;
- }
- // delay starting scroll capture to make sure scrim is up before the app moves
- mViewProxy.prepareScrollingTransition(response, mScreenBitmap, newScreenshot,
- mScreenshotTakenInPortrait, () -> executeBatchScrollCapture(response, owner));
- }
-
- private void executeBatchScrollCapture(ScrollCaptureResponse response, UserHandle owner) {
- mScrollCaptureExecutor.executeBatchScrollCapture(response,
- () -> {
- final Intent intent = ActionIntentCreator.INSTANCE.createLongScreenshotIntent(
- owner, mContext);
- mContext.startActivity(intent);
- },
- mViewProxy::restoreNonScrollingUi,
- mViewProxy::startLongScreenshotTransition);
- }
-
- @Override
- public void removeWindow() {
- mWindow.removeWindow();
- mViewProxy.stopInputListening();
- }
-
- private void playCameraSoundIfNeeded() {
- if (mScreenshotSoundController == null) return;
- // the controller is not-null only on the default display controller
- mScreenshotSoundController.playScreenshotSoundAsync();
- }
-
- /**
- * Save the bitmap but don't show the normal screenshot UI.. just a toast (or notification on
- * failure).
- */
- private void saveScreenshotAndToast(ScreenshotData screenshot, Consumer<Uri> finisher) {
- // Play the shutter sound to notify that we've taken a screenshot
- playCameraSoundIfNeeded();
-
- saveScreenshotInBackground(screenshot, UUID.randomUUID(), finisher, result -> {
- if (result.uri != null) {
- mScreenshotHandler.post(() -> Toast.makeText(mContext,
- R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show());
- }
- });
- }
-
- /**
- * Starts the animation after taking the screenshot
- */
- private void startAnimation(Rect screenRect, boolean showFlash, Runnable onAnimationComplete) {
- if (mScreenshotAnimation != null && mScreenshotAnimation.isRunning()) {
- mScreenshotAnimation.cancel();
- }
-
- mScreenshotAnimation =
- mViewProxy.createScreenshotDropInAnimation(screenRect, showFlash);
- if (onAnimationComplete != null) {
- mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- onAnimationComplete.run();
- }
- });
- }
-
- // Play the shutter sound to notify that we've taken a screenshot
- playCameraSoundIfNeeded();
-
- if (DEBUG_ANIM) {
- Log.d(TAG, "starting post-screenshot animation");
- }
- mScreenshotAnimation.start();
- }
-
- /** Reset screenshot view and then call onCompleteRunnable */
- private void finishDismiss() {
- Log.d(TAG, "finishDismiss");
- mActionsController.endScreenshotSession();
- mScrollCaptureExecutor.close();
- if (mCurrentRequestCallback != null) {
- mCurrentRequestCallback.onFinish();
- mCurrentRequestCallback = null;
- }
- mViewProxy.reset();
- removeWindow();
- mScreenshotHandler.cancelTimeout();
- }
-
- private void saveScreenshotInBackground(ScreenshotData screenshot, UUID requestId,
- Consumer<Uri> finisher, Consumer<ImageExporter.Result> onResult) {
- ListenableFuture<ImageExporter.Result> future = mImageExporter.export(mBgExecutor,
- requestId, screenshot.getBitmap(), screenshot.getUserOrDefault(),
- mDisplay.getDisplayId());
- future.addListener(() -> {
- try {
- ImageExporter.Result result = future.get();
- Log.d(TAG, "Saved screenshot: " + result);
- logScreenshotResultStatus(result.uri, screenshot.getUserHandle());
- onResult.accept(result);
- if (DEBUG_CALLBACK) {
- Log.d(TAG, "finished background processing, Calling (Consumer<Uri>) "
- + "finisher.accept(\"" + result.uri + "\"");
- }
- finisher.accept(result.uri);
- } catch (Exception e) {
- Log.d(TAG, "Failed to store screenshot", e);
- if (DEBUG_CALLBACK) {
- Log.d(TAG, "Calling (Consumer<Uri>) finisher.accept(null)");
- }
- finisher.accept(null);
- }
- }, mMainExecutor);
- }
-
- /**
- * Logs success/failure of the screenshot saving task, and shows an error if it failed.
- */
- private void logScreenshotResultStatus(Uri uri, UserHandle owner) {
- if (uri == null) {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED, 0, mPackageName);
- mNotificationsController.notifyScreenshotError(
- R.string.screenshot_failed_to_save_text);
- } else {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED, 0, mPackageName);
- if (mUserManager.isManagedProfile(owner.getIdentifier())) {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED_TO_WORK_PROFILE, 0,
- mPackageName);
- }
- }
- }
-
- private boolean isUserSetupComplete(UserHandle owner) {
- return Settings.Secure.getInt(mContext.createContextAsUser(owner, 0)
- .getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
- }
-
- private Rect getFullScreenRect() {
- DisplayMetrics displayMetrics = new DisplayMetrics();
- mDisplay.getRealMetrics(displayMetrics);
- return new Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels);
- }
-
- /** Does the aspect ratio of the bitmap with insets removed match the bounds. */
- private static boolean aspectRatiosMatch(Bitmap bitmap, Insets bitmapInsets,
- Rect screenBounds) {
- int insettedWidth = bitmap.getWidth() - bitmapInsets.left - bitmapInsets.right;
- int insettedHeight = bitmap.getHeight() - bitmapInsets.top - bitmapInsets.bottom;
-
- if (insettedHeight == 0 || insettedWidth == 0 || bitmap.getWidth() == 0
- || bitmap.getHeight() == 0) {
- if (DEBUG_UI) {
- Log.e(TAG, "Provided bitmap and insets create degenerate region: "
- + bitmap.getWidth() + "x" + bitmap.getHeight() + " " + bitmapInsets);
- }
- return false;
- }
-
- float insettedBitmapAspect = ((float) insettedWidth) / insettedHeight;
- float boundsAspect = ((float) screenBounds.width()) / screenBounds.height();
-
- boolean matchWithinTolerance = Math.abs(insettedBitmapAspect - boundsAspect) < 0.1f;
- if (DEBUG_UI) {
- Log.d(TAG, "aspectRatiosMatch: don't match bitmap: " + insettedBitmapAspect
- + ", bounds: " + boundsAspect);
- }
- return matchWithinTolerance;
- }
-
- /** Injectable factory to create screenshot controller instances for a specific display. */
- @AssistedFactory
- public interface Factory extends InteractiveScreenshotHandler.Factory {
- /**
- * Creates an instance of the controller for that specific display.
- *
- * @param display display to capture
- */
- ScreenshotController create(Display display);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.kt
new file mode 100644
index 0000000..29208f8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.kt
@@ -0,0 +1,632 @@
+/*
+ * 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.screenshot
+
+import android.animation.Animator
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.ActivityInfo
+import android.content.res.Configuration
+import android.graphics.Bitmap
+import android.graphics.Insets
+import android.graphics.Rect
+import android.net.Uri
+import android.os.Process
+import android.os.UserHandle
+import android.os.UserManager
+import android.provider.Settings
+import android.util.DisplayMetrics
+import android.util.Log
+import android.view.Display
+import android.view.ScrollCaptureResponse
+import android.view.ViewRootImpl.ActivityConfigCallback
+import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
+import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
+import android.widget.Toast
+import android.window.WindowContext
+import androidx.core.animation.doOnEnd
+import com.android.internal.logging.UiEventLogger
+import com.android.settingslib.applications.InterestingConfigChanges
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.broadcast.BroadcastSender
+import com.android.systemui.clipboardoverlay.ClipboardOverlayController
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.res.R
+import com.android.systemui.screenshot.ActionIntentCreator.createLongScreenshotIntent
+import com.android.systemui.screenshot.ScreenshotShelfViewProxy.ScreenshotViewCallback
+import com.android.systemui.screenshot.scroll.ScrollCaptureController.LongScreenshot
+import com.android.systemui.screenshot.scroll.ScrollCaptureExecutor
+import com.android.systemui.util.Assert
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import java.util.UUID
+import java.util.concurrent.Executor
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+import java.util.function.Consumer
+import javax.inject.Provider
+import kotlin.math.abs
+
+/** Controls the state and flow for screenshots. */
+class ScreenshotController
+@AssistedInject
+internal constructor(
+ appContext: Context,
+ screenshotWindowFactory: ScreenshotWindow.Factory,
+ viewProxyFactory: ScreenshotShelfViewProxy.Factory,
+ screenshotNotificationsControllerFactory: ScreenshotNotificationsController.Factory,
+ screenshotActionsControllerFactory: ScreenshotActionsController.Factory,
+ actionExecutorFactory: ActionExecutor.Factory,
+ screenshotSoundControllerProvider: Provider<ScreenshotSoundController?>,
+ private val uiEventLogger: UiEventLogger,
+ private val imageExporter: ImageExporter,
+ private val imageCapture: ImageCapture,
+ private val scrollCaptureExecutor: ScrollCaptureExecutor,
+ private val screenshotHandler: TimeoutHandler,
+ private val broadcastSender: BroadcastSender,
+ private val broadcastDispatcher: BroadcastDispatcher,
+ private val userManager: UserManager,
+ private val assistContentRequester: AssistContentRequester,
+ private val messageContainerController: MessageContainerController,
+ private val announcementResolver: AnnouncementResolver,
+ @Main private val mainExecutor: Executor,
+ @Assisted private val display: Display,
+) : InteractiveScreenshotHandler {
+ private val context: WindowContext
+ private val viewProxy: ScreenshotShelfViewProxy
+ private val notificationController =
+ screenshotNotificationsControllerFactory.create(display.displayId)
+ private val bgExecutor: ExecutorService = Executors.newSingleThreadExecutor()
+ private val actionsController: ScreenshotActionsController
+ private val window: ScreenshotWindow
+ private val actionExecutor: ActionExecutor
+ private val copyBroadcastReceiver: BroadcastReceiver
+
+ private var screenshotSoundController: ScreenshotSoundController? = null
+ private var screenBitmap: Bitmap? = null
+ private var screenshotTakenInPortrait = false
+ private var screenshotAnimation: Animator? = null
+ private var currentRequestCallback: TakeScreenshotService.RequestCallback? = null
+ private var packageName = ""
+
+ /** Tracks config changes that require re-creating UI */
+ private val configChanges =
+ InterestingConfigChanges(
+ ActivityInfo.CONFIG_ORIENTATION or
+ ActivityInfo.CONFIG_LAYOUT_DIRECTION or
+ ActivityInfo.CONFIG_LOCALE or
+ ActivityInfo.CONFIG_UI_MODE or
+ ActivityInfo.CONFIG_SCREEN_LAYOUT or
+ ActivityInfo.CONFIG_ASSETS_PATHS
+ )
+
+ init {
+ screenshotHandler.defaultTimeoutMillis = SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS
+
+ window = screenshotWindowFactory.create(display)
+ context = window.getContext()
+
+ viewProxy = viewProxyFactory.getProxy(context, display.displayId)
+
+ screenshotHandler.setOnTimeoutRunnable {
+ if (LogConfig.DEBUG_UI) {
+ Log.d(TAG, "Corner timeout hit")
+ }
+ viewProxy.requestDismissal(ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT)
+ }
+
+ configChanges.applyNewConfig(appContext.resources)
+ reloadAssets()
+
+ actionExecutor = actionExecutorFactory.create(window.window, viewProxy) { finishDismiss() }
+ actionsController = screenshotActionsControllerFactory.getController(actionExecutor)
+
+ // Sound is only reproduced from the controller of the default display.
+ screenshotSoundController =
+ if (display.displayId == Display.DEFAULT_DISPLAY) {
+ screenshotSoundControllerProvider.get()
+ } else {
+ null
+ }
+
+ copyBroadcastReceiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (ClipboardOverlayController.COPY_OVERLAY_ACTION == intent.action) {
+ viewProxy.requestDismissal(ScreenshotEvent.SCREENSHOT_DISMISSED_OTHER)
+ }
+ }
+ }
+ broadcastDispatcher.registerReceiver(
+ copyBroadcastReceiver,
+ IntentFilter(ClipboardOverlayController.COPY_OVERLAY_ACTION),
+ null,
+ null,
+ Context.RECEIVER_NOT_EXPORTED,
+ ClipboardOverlayController.SELF_PERMISSION,
+ )
+ }
+
+ override fun handleScreenshot(
+ screenshot: ScreenshotData,
+ finisher: Consumer<Uri?>,
+ requestCallback: TakeScreenshotService.RequestCallback,
+ ) {
+ Assert.isMainThread()
+
+ currentRequestCallback = requestCallback
+ if (screenshot.type == TAKE_SCREENSHOT_FULLSCREEN && screenshot.bitmap == null) {
+ val bounds = fullScreenRect
+ screenshot.bitmap = imageCapture.captureDisplay(display.displayId, bounds)
+ screenshot.screenBounds = bounds
+ }
+
+ val currentBitmap = screenshot.bitmap
+ if (currentBitmap == null) {
+ Log.e(TAG, "handleScreenshot: Screenshot bitmap was null")
+ notificationController.notifyScreenshotError(R.string.screenshot_failed_to_capture_text)
+ currentRequestCallback?.reportError()
+ return
+ }
+
+ screenBitmap = currentBitmap
+ val oldPackageName = packageName
+ packageName = screenshot.packageNameString
+
+ if (!isUserSetupComplete(Process.myUserHandle())) {
+ Log.w(TAG, "User setup not complete, displaying toast only")
+ // User setup isn't complete, so we don't want to show any UI beyond a toast, as editing
+ // and sharing shouldn't be exposed to the user.
+ saveScreenshotAndToast(screenshot, finisher)
+ return
+ }
+
+ broadcastSender.sendBroadcast(
+ Intent(ClipboardOverlayController.SCREENSHOT_ACTION),
+ ClipboardOverlayController.SELF_PERMISSION,
+ )
+
+ screenshotTakenInPortrait =
+ context.resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
+
+ // Optimizations
+ currentBitmap.setHasAlpha(false)
+ currentBitmap.prepareToDraw()
+
+ prepareViewForNewScreenshot(screenshot, oldPackageName)
+ val requestId = actionsController.setCurrentScreenshot(screenshot)
+ saveScreenshotInBackground(screenshot, requestId, finisher) { result ->
+ if (result.uri != null) {
+ val savedScreenshot =
+ ScreenshotSavedResult(
+ result.uri,
+ screenshot.getUserOrDefault(),
+ result.timestamp,
+ )
+ actionsController.setCompletedScreenshot(requestId, savedScreenshot)
+ }
+ }
+
+ if (screenshot.taskId >= 0) {
+ assistContentRequester.requestAssistContent(screenshot.taskId) { assistContent ->
+ actionsController.onAssistContent(requestId, assistContent)
+ }
+ } else {
+ actionsController.onAssistContent(requestId, null)
+ }
+
+ // The window is focusable by default
+ window.setFocusable(true)
+ viewProxy.requestFocus()
+
+ enqueueScrollCaptureRequest(requestId, screenshot.userHandle!!)
+
+ window.attachWindow()
+
+ val showFlash: Boolean
+ if (screenshot.type == TAKE_SCREENSHOT_PROVIDED_IMAGE) {
+ if (aspectRatiosMatch(currentBitmap, screenshot.insets, screenshot.screenBounds)) {
+ showFlash = false
+ } else {
+ showFlash = true
+ screenshot.insets = Insets.NONE
+ screenshot.screenBounds = Rect(0, 0, currentBitmap.width, currentBitmap.height)
+ }
+ } else {
+ showFlash = true
+ }
+
+ // screenshot.screenBounds is expected to be non-null in all cases at this point
+ val bounds =
+ screenshot.screenBounds ?: Rect(0, 0, currentBitmap.width, currentBitmap.height)
+
+ viewProxy.prepareEntranceAnimation {
+ startAnimation(bounds, showFlash) {
+ messageContainerController.onScreenshotTaken(screenshot)
+ }
+ }
+
+ viewProxy.screenshot = screenshot
+ }
+
+ private fun prepareViewForNewScreenshot(screenshot: ScreenshotData, oldPackageName: String?) {
+ window.whenWindowAttached {
+ announcementResolver.getScreenshotAnnouncement(screenshot.userHandle!!.identifier) {
+ viewProxy.announceForAccessibility(it)
+ }
+ }
+
+ viewProxy.reset()
+
+ if (viewProxy.isAttachedToWindow) {
+ // if we didn't already dismiss for another reason
+ if (!viewProxy.isDismissing) {
+ uiEventLogger.log(ScreenshotEvent.SCREENSHOT_REENTERED, 0, oldPackageName)
+ }
+ if (LogConfig.DEBUG_WINDOW) {
+ Log.d(
+ TAG,
+ "saveScreenshot: screenshotView is already attached, resetting. " +
+ "(dismissing=${viewProxy.isDismissing})",
+ )
+ }
+ }
+
+ viewProxy.packageName = packageName
+ }
+
+ /**
+ * Requests the view to dismiss the current screenshot (may be ignored, if screenshot is already
+ * being dismissed)
+ */
+ override fun requestDismissal(event: ScreenshotEvent) {
+ viewProxy.requestDismissal(event)
+ }
+
+ override fun isPendingSharedTransition(): Boolean {
+ return actionExecutor.isPendingSharedTransition
+ }
+
+ // Any cleanup needed when the service is being destroyed.
+ override fun onDestroy() {
+ removeWindow()
+ releaseMediaPlayer()
+ releaseContext()
+ bgExecutor.shutdown()
+ }
+
+ /** Release the constructed window context. */
+ private fun releaseContext() {
+ broadcastDispatcher.unregisterReceiver(copyBroadcastReceiver)
+ context.release()
+ }
+
+ private fun releaseMediaPlayer() {
+ screenshotSoundController?.releaseScreenshotSoundAsync()
+ }
+
+ /** Update resources on configuration change. Reinflate for theme/color changes. */
+ private fun reloadAssets() {
+ if (LogConfig.DEBUG_UI) {
+ Log.d(TAG, "reloadAssets()")
+ }
+
+ messageContainerController.setView(viewProxy.view)
+ viewProxy.callbacks =
+ object : ScreenshotViewCallback {
+ override fun onUserInteraction() {
+ if (LogConfig.DEBUG_INPUT) {
+ Log.d(TAG, "onUserInteraction")
+ }
+ screenshotHandler.resetTimeout()
+ }
+
+ override fun onDismiss() {
+ finishDismiss()
+ }
+
+ override fun onTouchOutside() {
+ // TODO(159460485): Remove this when focus is handled properly in the system
+ window.setFocusable(false)
+ }
+ }
+
+ if (LogConfig.DEBUG_WINDOW) {
+ Log.d(TAG, "setContentView: " + viewProxy.view)
+ }
+ window.setContentView(viewProxy.view)
+ }
+
+ private fun enqueueScrollCaptureRequest(requestId: UUID, owner: UserHandle) {
+ // Wait until this window is attached to request because it is
+ // the reference used to locate the target window (below).
+ window.whenWindowAttached {
+ requestScrollCapture(requestId, owner)
+ window.setActivityConfigCallback(
+ object : ActivityConfigCallback {
+ override fun onConfigurationChanged(
+ overrideConfig: Configuration,
+ newDisplayId: Int,
+ ) {
+ if (configChanges.applyNewConfig(context.resources)) {
+ // Hide the scroll chip until we know it's available in this
+ // orientation
+ actionsController.onScrollChipInvalidated()
+ // Delay scroll capture eval a bit to allow the underlying activity
+ // to set up in the new orientation.
+ screenshotHandler.postDelayed(
+ { requestScrollCapture(requestId, owner) },
+ 150,
+ )
+ viewProxy.updateInsets(window.getWindowInsets())
+ // Screenshot animation calculations won't be valid anymore, so just end
+ screenshotAnimation?.let { currentAnimation ->
+ if (currentAnimation.isRunning) {
+ currentAnimation.end()
+ }
+ }
+ }
+ }
+ }
+ )
+ }
+ }
+
+ private fun requestScrollCapture(requestId: UUID, owner: UserHandle) {
+ scrollCaptureExecutor.requestScrollCapture(display.displayId, window.getWindowToken()) {
+ response: ScrollCaptureResponse ->
+ uiEventLogger.log(
+ ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_IMPRESSION,
+ 0,
+ response.packageName,
+ )
+ actionsController.onScrollChipReady(requestId) {
+ onScrollButtonClicked(owner, response)
+ }
+ }
+ }
+
+ private fun onScrollButtonClicked(owner: UserHandle, response: ScrollCaptureResponse) {
+ if (LogConfig.DEBUG_INPUT) {
+ Log.d(TAG, "scroll chip tapped")
+ }
+ uiEventLogger.log(
+ ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_REQUESTED,
+ 0,
+ response.packageName,
+ )
+ val newScreenshot = imageCapture.captureDisplay(display.displayId, null)
+ if (newScreenshot == null) {
+ Log.e(TAG, "Failed to capture current screenshot for scroll transition!")
+ return
+ }
+ // delay starting scroll capture to make sure scrim is up before the app moves
+ viewProxy.prepareScrollingTransition(response, newScreenshot, screenshotTakenInPortrait) {
+ executeBatchScrollCapture(response, owner)
+ }
+ }
+
+ private fun executeBatchScrollCapture(response: ScrollCaptureResponse, owner: UserHandle) {
+ scrollCaptureExecutor.executeBatchScrollCapture(
+ response,
+ {
+ val intent = createLongScreenshotIntent(owner, context)
+ context.startActivity(intent)
+ },
+ { viewProxy.restoreNonScrollingUi() },
+ { transitionDestination: Rect, onTransitionEnd: Runnable, longScreenshot: LongScreenshot
+ ->
+ viewProxy.startLongScreenshotTransition(
+ transitionDestination,
+ onTransitionEnd,
+ longScreenshot,
+ )
+ },
+ )
+ }
+
+ override fun removeWindow() {
+ window.removeWindow()
+ viewProxy.stopInputListening()
+ }
+
+ private fun playCameraSoundIfNeeded() {
+ // the controller is not-null only on the default display controller
+ screenshotSoundController?.playScreenshotSoundAsync()
+ }
+
+ /**
+ * Save the bitmap but don't show the normal screenshot UI.. just a toast (or notification on
+ * failure).
+ */
+ private fun saveScreenshotAndToast(screenshot: ScreenshotData, finisher: Consumer<Uri?>) {
+ // Play the shutter sound to notify that we've taken a screenshot
+ playCameraSoundIfNeeded()
+
+ saveScreenshotInBackground(screenshot, UUID.randomUUID(), finisher) {
+ result: ImageExporter.Result ->
+ if (result.uri != null) {
+ screenshotHandler.post {
+ Toast.makeText(context, R.string.screenshot_saved_title, Toast.LENGTH_SHORT)
+ .show()
+ }
+ }
+ }
+ }
+
+ /** Starts the animation after taking the screenshot */
+ private fun startAnimation(
+ screenRect: Rect,
+ showFlash: Boolean,
+ onAnimationComplete: Runnable?,
+ ) {
+ screenshotAnimation?.let { currentAnimation ->
+ if (currentAnimation.isRunning) {
+ currentAnimation.cancel()
+ }
+ }
+
+ screenshotAnimation =
+ viewProxy.createScreenshotDropInAnimation(screenRect, showFlash).apply {
+ doOnEnd { onAnimationComplete?.run() }
+ // Play the shutter sound to notify that we've taken a screenshot
+ playCameraSoundIfNeeded()
+ if (LogConfig.DEBUG_ANIM) {
+ Log.d(TAG, "starting post-screenshot animation")
+ }
+ start()
+ }
+ }
+
+ /** Reset screenshot view and then call onCompleteRunnable */
+ private fun finishDismiss() {
+ Log.d(TAG, "finishDismiss")
+ actionsController.endScreenshotSession()
+ scrollCaptureExecutor.close()
+ currentRequestCallback?.onFinish()
+ currentRequestCallback = null
+ viewProxy.reset()
+ removeWindow()
+ screenshotHandler.cancelTimeout()
+ }
+
+ private fun saveScreenshotInBackground(
+ screenshot: ScreenshotData,
+ requestId: UUID,
+ finisher: Consumer<Uri?>,
+ onResult: Consumer<ImageExporter.Result>,
+ ) {
+ val future =
+ imageExporter.export(
+ bgExecutor,
+ requestId,
+ screenshot.bitmap,
+ screenshot.getUserOrDefault(),
+ display.displayId,
+ )
+ future.addListener(
+ {
+ try {
+ val result = future.get()
+ Log.d(TAG, "Saved screenshot: $result")
+ logScreenshotResultStatus(result.uri, screenshot.userHandle!!)
+ onResult.accept(result)
+ if (LogConfig.DEBUG_CALLBACK) {
+ Log.d(TAG, "finished bg processing, calling back with uri: ${result.uri}")
+ }
+ finisher.accept(result.uri)
+ } catch (e: Exception) {
+ Log.d(TAG, "Failed to store screenshot", e)
+ if (LogConfig.DEBUG_CALLBACK) {
+ Log.d(TAG, "calling back with uri: null")
+ }
+ finisher.accept(null)
+ }
+ },
+ mainExecutor,
+ )
+ }
+
+ /** Logs success/failure of the screenshot saving task, and shows an error if it failed. */
+ private fun logScreenshotResultStatus(uri: Uri?, owner: UserHandle) {
+ if (uri == null) {
+ uiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED, 0, packageName)
+ notificationController.notifyScreenshotError(R.string.screenshot_failed_to_save_text)
+ } else {
+ uiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED, 0, packageName)
+ if (userManager.isManagedProfile(owner.identifier)) {
+ uiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED_TO_WORK_PROFILE, 0, packageName)
+ }
+ }
+ }
+
+ private fun isUserSetupComplete(owner: UserHandle): Boolean {
+ return Settings.Secure.getInt(
+ context.createContextAsUser(owner, 0).contentResolver,
+ SETTINGS_SECURE_USER_SETUP_COMPLETE,
+ 0,
+ ) == 1
+ }
+
+ private val fullScreenRect: Rect
+ get() {
+ val displayMetrics = DisplayMetrics()
+ display.getRealMetrics(displayMetrics)
+ return Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels)
+ }
+
+ /** Injectable factory to create screenshot controller instances for a specific display. */
+ @AssistedFactory
+ interface Factory : InteractiveScreenshotHandler.Factory {
+ /**
+ * Creates an instance of the controller for that specific display.
+ *
+ * @param display display to capture
+ */
+ override fun create(display: Display): ScreenshotController
+ }
+
+ companion object {
+ private val TAG: String = LogConfig.logTag(ScreenshotController::class.java)
+
+ // From WizardManagerHelper.java
+ private const val SETTINGS_SECURE_USER_SETUP_COMPLETE = "user_setup_complete"
+
+ const val SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS: Int = 6000
+
+ /** Does the aspect ratio of the bitmap with insets removed match the bounds. */
+ private fun aspectRatiosMatch(
+ bitmap: Bitmap,
+ bitmapInsets: Insets,
+ screenBounds: Rect?,
+ ): Boolean {
+ if (screenBounds == null) {
+ return false
+ }
+ val insettedWidth = bitmap.width - bitmapInsets.left - bitmapInsets.right
+ val insettedHeight = bitmap.height - bitmapInsets.top - bitmapInsets.bottom
+
+ if (
+ insettedHeight == 0 || insettedWidth == 0 || bitmap.width == 0 || bitmap.height == 0
+ ) {
+ if (LogConfig.DEBUG_UI) {
+ Log.e(
+ TAG,
+ "Provided bitmap and insets create degenerate region: " +
+ "${bitmap.width} x ${bitmap.height} $bitmapInsets",
+ )
+ }
+ return false
+ }
+
+ val insettedBitmapAspect = insettedWidth.toFloat() / insettedHeight
+ val boundsAspect = screenBounds.width().toFloat() / screenBounds.height()
+
+ val matchWithinTolerance = abs((insettedBitmapAspect - boundsAspect).toDouble()) < 0.1f
+ if (LogConfig.DEBUG_UI) {
+ Log.d(
+ TAG,
+ "aspectRatiosMatch: don't match bitmap: " +
+ "$insettedBitmapAspect, bounds: $boundsAspect",
+ )
+ }
+ return matchWithinTolerance
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
index 50215af..c1ea3ad 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
@@ -67,7 +67,7 @@
shelfViewBinder: ScreenshotShelfViewBinder,
private val thumbnailObserver: ThumbnailObserver,
@Assisted private val context: Context,
- @Assisted private val displayId: Int
+ @Assisted private val displayId: Int,
) {
interface ScreenshotViewCallback {
@@ -117,7 +117,7 @@
animationController,
LayoutInflater.from(context),
onDismissalRequested = { event, velocity -> requestDismissal(event, velocity) },
- onUserInteraction = { callbacks?.onUserInteraction() }
+ onUserInteraction = { callbacks?.onUserInteraction() },
)
view.updateInsets(windowManager.currentWindowMetrics.windowInsets)
addPredictiveBackListener { requestDismissal(SCREENSHOT_DISMISSED_OTHER) }
@@ -130,7 +130,7 @@
screenshotPreview = view.screenshotPreview
thumbnailObserver.setViews(
view.blurredScreenshotPreview,
- view.requireViewById(R.id.screenshot_preview_border)
+ view.requireViewById(R.id.screenshot_preview_border),
)
view.addOnAttachStateChangeListener(
object : View.OnAttachStateChangeListener {
@@ -204,7 +204,6 @@
fun prepareScrollingTransition(
response: ScrollCaptureResponse,
- screenBitmap: Bitmap, // unused
newScreenshot: Bitmap,
screenshotTakenInPortrait: Boolean,
onTransitionPrepared: Runnable,
@@ -224,7 +223,7 @@
0,
0,
context.resources.displayMetrics.widthPixels,
- context.resources.displayMetrics.heightPixels
+ context.resources.displayMetrics.heightPixels,
)
)
return r
@@ -239,7 +238,7 @@
animationController.runLongScreenshotTransition(
transitionDestination,
longScreenshot,
- onTransitionEnd
+ onTransitionEnd,
)
transitionAnimation.doOnEnd { callbacks?.onDismiss() }
transitionAnimation.start()
@@ -295,7 +294,7 @@
.findOnBackInvokedDispatcher()
?.registerOnBackInvokedCallback(
OnBackInvokedDispatcher.PRIORITY_DEFAULT,
- onBackInvokedCallback
+ onBackInvokedCallback,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
index 7fa9926..2e67277 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -108,7 +108,7 @@
fun dispatchTouchEvent(
ev: MotionEvent?,
- disallowInterceptConsumer: Consumer<Boolean>?
+ disallowInterceptConsumer: Consumer<Boolean>?,
): Boolean {
disallowInterceptConsumer?.apply { consumers.add(this) }
@@ -252,9 +252,7 @@
*
* @throws RuntimeException if the view is already initialized
*/
- fun initView(
- context: Context,
- ): View {
+ fun initView(context: Context): View {
return initView(
ComposeView(context).apply {
repeatWhenAttached {
@@ -310,40 +308,26 @@
communalContainerView = containerView
- val topEdgeSwipeRegionWidth =
- containerView.resources.getDimensionPixelSize(
- R.dimen.communal_top_edge_swipe_region_height
- )
- val bottomEdgeSwipeRegionWidth =
- containerView.resources.getDimensionPixelSize(
- R.dimen.communal_bottom_edge_swipe_region_height
- )
+ if (!Flags.hubmodeFullscreenVerticalSwipeFix()) {
+ val topEdgeSwipeRegionWidth =
+ containerView.resources.getDimensionPixelSize(
+ R.dimen.communal_top_edge_swipe_region_height
+ )
+ val bottomEdgeSwipeRegionWidth =
+ containerView.resources.getDimensionPixelSize(
+ R.dimen.communal_bottom_edge_swipe_region_height
+ )
- // BouncerSwipeTouchHandler has a larger gesture area than we want, set an exclusion area so
- // the gesture area doesn't overlap with widgets.
- // TODO(b/323035776): adjust gesture area for portrait mode
- containerView.repeatWhenAttached {
- // Run when the touch handling lifecycle is RESUMED, meaning the hub is visible and not
- // occluded.
- lifecycleRegistry.repeatOnLifecycle(Lifecycle.State.RESUMED) {
- val ltr = containerView.layoutDirection == View.LAYOUT_DIRECTION_LTR
-
- val backGestureInset =
- Rect(
- 0,
- 0,
- if (ltr) 0 else containerView.right,
- containerView.bottom,
- )
-
- containerView.systemGestureExclusionRects =
- if (Flags.hubmodeFullscreenVerticalSwipeFix()) {
- listOf(
- // Disable back gestures on the left side of the screen, to avoid
- // conflicting with scene transitions.
- backGestureInset
- )
- } else {
+ // BouncerSwipeTouchHandler has a larger gesture area than we want, set an exclusion
+ // area so
+ // the gesture area doesn't overlap with widgets.
+ // TODO(b/323035776): adjust gesture area for portrait mode
+ containerView.repeatWhenAttached {
+ // Run when the touch handling lifecycle is RESUMED, meaning the hub is visible and
+ // not
+ // occluded.
+ lifecycleRegistry.repeatOnLifecycle(Lifecycle.State.RESUMED) {
+ containerView.systemGestureExclusionRects =
listOf(
// Only allow swipe up to bouncer and swipe down to shade in the very
// top/bottom to avoid conflicting with widgets in the hub grid.
@@ -351,15 +335,13 @@
0,
topEdgeSwipeRegionWidth,
containerView.right,
- containerView.bottom - bottomEdgeSwipeRegionWidth
- ),
- // Disable back gestures on the left side of the screen, to avoid
- // conflicting with scene transitions.
- backGestureInset
+ containerView.bottom - bottomEdgeSwipeRegionWidth,
+ )
)
+
+ logger.d({ "Insets updated: $str1" }) {
+ str1 = containerView.systemGestureExclusionRects.toString()
}
- logger.d({ "Insets updated: $str1" }) {
- str1 = containerView.systemGestureExclusionRects.toString()
}
}
}
@@ -372,7 +354,7 @@
containerView,
anyOf(
keyguardInteractor.primaryBouncerShowing,
- keyguardInteractor.alternateBouncerShowing
+ keyguardInteractor.alternateBouncerShowing,
),
{
anyBouncerShowing = it
@@ -380,12 +362,12 @@
logger.d({ "New value for anyBouncerShowing: $bool1" }) { bool1 = it }
}
updateTouchHandlingState()
- }
+ },
)
collectFlow(
containerView,
keyguardTransitionInteractor.isFinishedIn(KeyguardState.LOCKSCREEN),
- { onLockscreen = it }
+ { onLockscreen = it },
)
collectFlow(
containerView,
@@ -393,7 +375,7 @@
{
hubShowing = it
updateTouchHandlingState()
- }
+ },
)
collectFlow(
containerView,
@@ -404,12 +386,12 @@
communalInteractor.editActivityShowing,
keyguardTransitionInteractor.isInTransition(
Edge.create(KeyguardState.GONE, KeyguardState.GLANCEABLE_HUB)
- )
+ ),
),
{
inEditModeTransition = it
updateTouchHandlingState()
- }
+ },
)
collectFlow(
containerView,
@@ -417,7 +399,7 @@
shadeInteractor.isAnyFullyExpanded,
shadeInteractor.isUserInteracting,
shadeInteractor.isShadeFullyCollapsed,
- ::Triple
+ ::Triple,
),
{ (isFullyExpanded, isUserInteracting, isShadeFullyCollapsed) ->
shadeConsumingTouches = isUserInteracting
@@ -441,7 +423,7 @@
}
}
updateTouchHandlingState()
- }
+ },
)
collectFlow(containerView, keyguardInteractor.isDreaming, { isDreaming = it })
@@ -628,7 +610,7 @@
powerManager.userActivity(
SystemClock.uptimeMillis(),
PowerManager.USER_ACTIVITY_EVENT_TOUCH,
- 0
+ 0,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index f76c5fd..0c05dbd 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -2220,6 +2220,7 @@
@VisibleForTesting
void onFlingEnd(boolean cancelled) {
mIsFlinging = false;
+ mExpectingSynthesizedDown = false;
// No overshoot when the animation ends
setOverExpansionInternal(0, false /* isFromGesture */);
setAnimator(null);
@@ -2352,7 +2353,6 @@
return;
}
if (mExpectingSynthesizedDown) {
- mExpectingSynthesizedDown = false;
// Window never will receive touch events that typically trigger haptic on open.
maybeVibrateOnOpening(false /* openingWithTouch */);
fling(velocity > 1f ? 1000f * velocity : 0 /* expand */);
@@ -3994,6 +3994,9 @@
}
mExpandedFraction = Math.min(1f,
maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
+ if (mExpandedFraction > 0f && mExpectingSynthesizedDown) {
+ mExpectingSynthesizedDown = false;
+ }
mShadeRepository.setLegacyShadeExpansion(mExpandedFraction);
mQsController.setShadeExpansion(mExpandedHeight, mExpandedFraction);
mExpansionDragDownAmountPx = h;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index 3f3ad13..4f47536 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -28,6 +28,7 @@
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
import android.graphics.Region;
import android.os.Binder;
import android.os.Build;
@@ -987,6 +988,19 @@
@Override
public void onConfigChanged(Configuration newConfig) {
+ // If the shade window is not visible, the bounds will not update until it becomes visible.
+ // Touches that should invoke shade expansion but are not within those incorrect bounds
+ // (because the shape of the shade window remains portrait after flipping to landscape) will
+ // be dropped, causing the shade expansion to fail silently. Since the shade doesn't open,
+ // it doesn't become visible, and the bounds will never update. Therefore, we must detect
+ // the incorrect bounds here and force the update so that touches are routed correctly.
+ if (SceneContainerFlag.isEnabled() && mWindowRootView.getVisibility() == View.INVISIBLE) {
+ Rect bounds = newConfig.windowConfiguration.getBounds();
+ if (mWindowRootView.getWidth() != bounds.width()) {
+ mLogger.logConfigChangeWidthAdjust(mWindowRootView.getWidth(), bounds.width());
+ updateRootViewBounds(bounds);
+ }
+ }
final boolean newScreenRotationAllowed = mKeyguardStateController
.isKeyguardScreenRotationAllowed();
@@ -996,6 +1010,16 @@
}
}
+ private void updateRootViewBounds(Rect bounds) {
+ int originalMlpWidth = mLp.width;
+ int originalMlpHeight = mLp.height;
+ mLp.width = bounds.width();
+ mLp.height = bounds.height();
+ mWindowManager.updateViewLayout(mWindowRootView, mLp);
+ mLp.width = originalMlpWidth;
+ mLp.height = originalMlpHeight;
+ }
+
/**
* When keyguard will be dismissed but didn't start animation yet.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 1c223db..5473af3 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -30,6 +30,8 @@
import android.view.View;
import android.view.ViewGroup;
+import androidx.core.view.ViewKt;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.AuthKeyguardMessageArea;
import com.android.keyguard.KeyguardUnfoldTransition;
@@ -38,6 +40,7 @@
import com.android.systemui.animation.ActivityTransitionAnimator;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
+import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags;
import com.android.systemui.bouncer.ui.binder.BouncerViewBinder;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.SysUISingleton;
@@ -51,6 +54,7 @@
import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.model.Edge;
+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.res.R;
@@ -111,6 +115,7 @@
private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
private final AlternateBouncerInteractor mAlternateBouncerInteractor;
private final QuickSettingsController mQuickSettingsController;
+ private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
private final GlanceableHubContainerController
mGlanceableHubContainerController;
private GestureDetector mPulsingWakeupGestureHandler;
@@ -140,6 +145,7 @@
private final PanelExpansionInteractor mPanelExpansionInteractor;
private final ShadeExpansionStateManager mShadeExpansionStateManager;
+ private ViewGroup mBouncerParentView;
/**
* If {@code true}, an external touch sent in {@link #handleExternalTouch(MotionEvent)} has been
* intercepted and all future touch events for the gesture should be processed by this view.
@@ -217,6 +223,7 @@
mPulsingGestureListener = pulsingGestureListener;
mLockscreenHostedDreamGestureListener = lockscreenHostedDreamGestureListener;
mNotificationInsetsController = notificationInsetsController;
+ mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mGlanceableHubContainerController = glanceableHubContainerController;
mFeatureFlagsClassic = featureFlagsClassic;
mSysUIKeyEventHandler = sysUIKeyEventHandler;
@@ -227,7 +234,7 @@
// This view is not part of the newly inflated expanded status bar.
mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
mDisableSubpixelTextTransitionListener = new DisableSubpixelTextTransitionListener(mView);
- bouncerViewBinder.bind(mView.findViewById(R.id.keyguard_bouncer_container));
+ bindBouncer(bouncerViewBinder);
collectFlow(mView, keyguardTransitionInteractor.transition(
Edge.create(LOCKSCREEN, DREAMING)),
@@ -256,6 +263,36 @@
dumpManager.registerDumpable(this);
}
+ private void bindBouncer(BouncerViewBinder bouncerViewBinder) {
+ mBouncerParentView = mView.findViewById(R.id.keyguard_bouncer_container);
+ bouncerViewBinder.bind(mBouncerParentView);
+ if (ComposeBouncerFlags.INSTANCE.isOnlyComposeBouncerEnabled()) {
+ collectFlow(mView, mKeyguardTransitionInteractor.transition(
+ new Edge.StateToState(KeyguardState.PRIMARY_BOUNCER, null)),
+ this::onTransitionAwayFromBouncer);
+ collectFlow(mView, mKeyguardTransitionInteractor.transition(
+ new Edge.StateToState(null, KeyguardState.PRIMARY_BOUNCER)),
+ this::onTransitionToBouncer);
+ collectFlow(mView, mPrimaryBouncerInteractor.isShowing(),
+ (showing) -> ViewKt.setVisible(mBouncerParentView, showing));
+ }
+ }
+
+ private void onTransitionToBouncer(TransitionStep transitionStep) {
+ if (transitionStep.getTransitionState() == TransitionState.STARTED) {
+ if (mView.indexOfChild(mBouncerParentView) != -1) {
+ mView.removeView(mBouncerParentView);
+ }
+ mView.addView(mBouncerParentView);
+ }
+ }
+
+ private void onTransitionAwayFromBouncer(TransitionStep transitionStep) {
+ if (transitionStep.getTransitionState() == TransitionState.FINISHED) {
+ mView.removeView(mBouncerParentView);
+ }
+ }
+
/**
* @return Location where to place the KeyguardMessageArea
*/
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
index e7a397b..1693e62 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
@@ -31,18 +31,13 @@
ConstantStringsLogger by ConstantStringsLoggerImpl(buffer, TAG) {
fun logNewState(state: Any) {
- buffer.log(
- TAG,
- DEBUG,
- { str1 = state.toString() },
- { "Applying new state: $str1" }
- )
+ buffer.log(TAG, DEBUG, { str1 = state.toString() }, { "Applying new state: $str1" })
}
private inline fun log(
logLevel: LogLevel,
initializer: LogMessage.() -> Unit,
- noinline printer: LogMessage.() -> String
+ noinline printer: LogMessage.() -> String,
) {
buffer.log(TAG, logLevel, initializer, printer)
}
@@ -52,7 +47,8 @@
TAG,
DEBUG,
{ bool1 = visible },
- { "Updating visibility, should be visible : $bool1" })
+ { "Updating visibility, should be visible : $bool1" },
+ )
}
fun logIsExpanded(
@@ -65,7 +61,7 @@
headsUpNotificationShowing: Boolean,
scrimsVisibilityNotTransparent: Boolean,
backgroundBlurRadius: Boolean,
- launchingActivityFromNotification: Boolean
+ launchingActivityFromNotification: Boolean,
) {
buffer.log(
TAG,
@@ -82,11 +78,13 @@
long2 = if (backgroundBlurRadius) 1 else 0
double1 = if (launchingActivityFromNotification) 1.0 else 0.0
},
- { "Setting isExpanded to $str1: forceWindowCollapsed $bool1, " +
+ {
+ "Setting isExpanded to $str1: forceWindowCollapsed $bool1, " +
"isKeyguardShowingAndNotOccluded $bool2, panelVisible $bool3, " +
"keyguardFadingAway $bool4, bouncerShowing $int1," +
"headsUpNotificationShowing $int2, scrimsVisibilityNotTransparent $long1," +
- "backgroundBlurRadius $long2, launchingActivityFromNotification $double1"}
+ "backgroundBlurRadius $long2, launchingActivityFromNotification $double1"
+ },
)
}
@@ -95,7 +93,7 @@
TAG,
DEBUG,
{ bool1 = visible },
- { "Updating shade, should be visible and focusable: $bool1" }
+ { "Updating shade, should be visible and focusable: $bool1" },
)
}
@@ -104,7 +102,19 @@
TAG,
DEBUG,
{ bool1 = focusable },
- { "Updating shade, should be focusable : $bool1" }
+ { "Updating shade, should be focusable : $bool1" },
+ )
+ }
+
+ fun logConfigChangeWidthAdjust(originalWidth: Int, newWidth: Int) {
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = originalWidth
+ int2 = newWidth
+ },
+ { "Config changed. SceneWindowRootView width updating from $int1 to $int2." },
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
index 4056e7b..975b92e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
@@ -16,11 +16,12 @@
package com.android.systemui.statusbar.core
import android.app.Fragment
-import com.android.systemui.res.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.fragments.FragmentHostManager
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewInitializedListener
+import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewUpdatedListener
import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions
-import com.android.systemui.statusbar.phone.PhoneStatusBarView
import com.android.systemui.statusbar.phone.PhoneStatusBarViewController
import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment
import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent
@@ -33,31 +34,60 @@
* Responsible for creating the status bar window and initializing the root components of that
* window (see [CollapsedStatusBarFragment])
*/
-@SysUISingleton
-class StatusBarInitializer @Inject constructor(
- private val windowController: StatusBarWindowController,
- private val collapsedStatusBarFragmentProvider: Provider<CollapsedStatusBarFragment>,
- private val creationListeners: Set<@JvmSuppressWildcards OnStatusBarViewInitializedListener>,
-) {
+interface StatusBarInitializer {
- var statusBarViewUpdatedListener: OnStatusBarViewUpdatedListener? = null
+ var statusBarViewUpdatedListener: OnStatusBarViewUpdatedListener?
/**
* Creates the status bar window and root views, and initializes the component.
*
* TODO(b/277764509): Initialize the status bar via [CoreStartable#start].
*/
- fun initializeStatusBar() {
- windowController.fragmentHostManager.addTagListener(
+ fun initializeStatusBar()
+
+ interface OnStatusBarViewInitializedListener {
+
+ /**
+ * The status bar view has been initialized.
+ *
+ * @param component Dagger component that is created when the status bar view is created.
+ * Can be used to retrieve dependencies from that scope, including the status bar root
+ * view.
+ */
+ fun onStatusBarViewInitialized(component: StatusBarFragmentComponent)
+ }
+
+ interface OnStatusBarViewUpdatedListener {
+ fun onStatusBarViewUpdated(
+ statusBarViewController: PhoneStatusBarViewController,
+ statusBarTransitions: PhoneStatusBarTransitions,
+ )
+ }
+}
+
+@SysUISingleton
+class StatusBarInitializerImpl
+@Inject
+constructor(
+ private val windowController: StatusBarWindowController,
+ private val collapsedStatusBarFragmentProvider: Provider<CollapsedStatusBarFragment>,
+ private val creationListeners: Set<@JvmSuppressWildcards OnStatusBarViewInitializedListener>,
+) : StatusBarInitializer {
+
+ override var statusBarViewUpdatedListener: OnStatusBarViewUpdatedListener? = null
+
+ override fun initializeStatusBar() {
+ windowController.fragmentHostManager
+ .addTagListener(
CollapsedStatusBarFragment.TAG,
object : FragmentHostManager.FragmentListener {
override fun onFragmentViewCreated(tag: String, fragment: Fragment) {
- val statusBarFragmentComponent = (fragment as CollapsedStatusBarFragment)
- .statusBarFragmentComponent ?: throw IllegalStateException()
+ val statusBarFragmentComponent =
+ (fragment as CollapsedStatusBarFragment).statusBarFragmentComponent
+ ?: throw IllegalStateException()
statusBarViewUpdatedListener?.onStatusBarViewUpdated(
- statusBarFragmentComponent.phoneStatusBarView,
statusBarFragmentComponent.phoneStatusBarViewController,
- statusBarFragmentComponent.phoneStatusBarTransitions
+ statusBarFragmentComponent.phoneStatusBarTransitions,
)
creationListeners.forEach { listener ->
listener.onStatusBarViewInitialized(statusBarFragmentComponent)
@@ -67,33 +97,15 @@
override fun onFragmentViewDestroyed(tag: String?, fragment: Fragment?) {
// nop
}
- }
- ).fragmentManager
- .beginTransaction()
- .replace(
- R.id.status_bar_container,
- collapsedStatusBarFragmentProvider.get(),
- CollapsedStatusBarFragment.TAG
- )
- .commit()
- }
-
- interface OnStatusBarViewInitializedListener {
-
- /**
- * The status bar view has been initialized.
- *
- * @param component Dagger component that is created when the status bar view is created.
- * Can be used to retrieve dependencies from that scope, including the status bar root view.
- */
- fun onStatusBarViewInitialized(component: StatusBarFragmentComponent)
- }
-
- interface OnStatusBarViewUpdatedListener {
- fun onStatusBarViewUpdated(
- statusBarView: PhoneStatusBarView,
- statusBarViewController: PhoneStatusBarViewController,
- statusBarTransitions: PhoneStatusBarTransitions
- )
+ },
+ )
+ .fragmentManager
+ .beginTransaction()
+ .replace(
+ R.id.status_bar_container,
+ collapsedStatusBarFragmentProvider.get(),
+ CollapsedStatusBarFragment.TAG,
+ )
+ .commit()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/shared/StatusBarRonChips.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarSimpleFragment.kt
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/statusbar/chips/shared/StatusBarRonChips.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarSimpleFragment.kt
index 4c0c461..2141513 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/shared/StatusBarRonChips.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarSimpleFragment.kt
@@ -14,17 +14,16 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.chips.shared
+package com.android.systemui.statusbar.core
import com.android.systemui.Flags
import com.android.systemui.flags.FlagToken
import com.android.systemui.flags.RefactorFlagUtils
-/** Helper for reading or using the status bar ron chips flag state. */
-@Suppress("NOTHING_TO_INLINE")
-object StatusBarRonChips {
- /** The aconfig flag name */
- const val FLAG_NAME = Flags.FLAG_STATUS_BAR_RON_CHIPS
+/** Helper for reading and using the status bar simple fragment flag state */
+object StatusBarSimpleFragment {
+ /** Aconfig flag for removing the fragment */
+ const val FLAG_NAME = Flags.FLAG_STATUS_BAR_SIMPLE_FRAGMENT
/** A token used for dependency declaration */
val token: FlagToken
@@ -33,7 +32,7 @@
/** Is the refactor enabled */
@JvmStatic
inline val isEnabled
- get() = Flags.statusBarRonChips()
+ get() = Flags.statusBarSimpleFragment()
/**
* Called to ensure code is only run when the flag is enabled. This protects users from the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
index 406a66449f..55943a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
@@ -16,16 +16,22 @@
package com.android.systemui.statusbar.dagger
+import android.content.Context
+import com.android.app.viewcapture.ViewCaptureAwareWindowManager
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.statusbar.core.StatusBarInitializer
+import com.android.systemui.statusbar.core.StatusBarInitializerImpl
import com.android.systemui.statusbar.data.StatusBarDataLayerModule
import com.android.systemui.statusbar.phone.LightBarController
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLog
import com.android.systemui.statusbar.ui.SystemBarUtilsProxyImpl
+import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowControllerImpl
import dagger.Binds
import dagger.Module
import dagger.Provides
@@ -57,7 +63,20 @@
@ClassKey(StatusBarSignalPolicy::class)
abstract fun bindStatusBarSignalPolicy(impl: StatusBarSignalPolicy): CoreStartable
+ @Binds abstract fun statusBarInitializer(impl: StatusBarInitializerImpl): StatusBarInitializer
+
companion object {
+
+ @Provides
+ @SysUISingleton
+ fun statusBarWindowController(
+ context: Context?,
+ viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager?,
+ factory: StatusBarWindowControllerImpl.Factory,
+ ): StatusBarWindowController {
+ return factory.create(context, viewCaptureAwareWindowManager)
+ }
+
@Provides
@SysUISingleton
@OngoingCallLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt
index 2bb47652..ce25cf5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt
@@ -17,8 +17,12 @@
import android.app.StatusBarManager.DISABLE2_NONE
import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
+import android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS
+import android.app.StatusBarManager.DISABLE_CLOCK
import android.app.StatusBarManager.DISABLE_NONE
import android.app.StatusBarManager.DISABLE_NOTIFICATION_ALERTS
+import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
+import android.app.StatusBarManager.DISABLE_SYSTEM_INFO
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
@@ -27,12 +31,14 @@
* Model for the disable flags that come from [IStatusBar].
*
* For clients of the disable flags: do *not* refer to the disable integers directly. Instead,
- * re-use or define a helper method that internally processes the flags. (We want to hide the
- * bitwise logic here so no one else has to worry about it.)
+ * re-use or define a helper method or property that internally processes the flags. (We want to
+ * hide the bitwise logic here so no one else has to worry about it.)
*/
data class DisableFlagsModel(
private val disable1: Int = DISABLE_NONE,
private val disable2: Int = DISABLE2_NONE,
+ /** True if we should animate any view visibility changes and false otherwise. */
+ val animate: Boolean = false,
) {
/** Returns true if notification alerts are allowed based on the flags. */
fun areNotificationAlertsEnabled(): Boolean {
@@ -49,6 +55,13 @@
return (disable2 and DISABLE2_QUICK_SETTINGS) == 0
}
+ val isClockEnabled = (disable1 and DISABLE_CLOCK) == 0
+
+ val areNotificationIconsEnabled = (disable1 and DISABLE_NOTIFICATION_ICONS) == 0
+
+ val isSystemInfoEnabled =
+ (disable1 and DISABLE_SYSTEM_INFO) == 0 && (disable2 and DISABLE2_SYSTEM_ICONS) == 0
+
/** Logs the change to the provided buffer. */
fun logChange(buffer: LogBuffer, disableFlagsLogger: DisableFlagsLogger) {
buffer.log(
@@ -60,9 +73,9 @@
},
{
disableFlagsLogger.getDisableFlagsString(
- new = DisableFlagsLogger.DisableState(int1, int2),
+ new = DisableFlagsLogger.DisableState(int1, int2)
)
- }
+ },
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt
index 13b74b4..9004e5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt
@@ -72,6 +72,7 @@
// [QuickSettingsInteractor]-type class. However, that's out of
// scope for the CentralSurfaces removal project.
remoteInputQuickSettingsDisabler.adjustDisableFlags(state2),
+ animate,
)
)
}
@@ -82,5 +83,5 @@
.distinctUntilChanged()
.onEach { it.logChange(logBuffer, disableFlagsLogger) }
// Use Eagerly because we always need to know about disable flags
- .stateIn(scope, SharingStarted.Eagerly, DisableFlagsModel())
+ .stateIn(scope, SharingStarted.Eagerly, DisableFlagsModel(animate = false))
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java
index 02a29e2..9b96931 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java
@@ -103,7 +103,8 @@
private boolean mTrackingHeadsUp;
private final HashSet<String> mSwipedOutKeys = new HashSet<>();
private final HashSet<NotificationEntry> mEntriesToRemoveAfterExpand = new HashSet<>();
- private final ArraySet<NotificationEntry> mEntriesToRemoveWhenReorderingAllowed
+ @VisibleForTesting
+ public final ArraySet<NotificationEntry> mEntriesToRemoveWhenReorderingAllowed
= new ArraySet<>();
private boolean mIsExpanded;
private int mStatusBarState;
@@ -417,7 +418,7 @@
for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) {
if (isHeadsUpEntry(entry.getKey())) {
// Maybe the heads-up was removed already
- removeEntry(entry.getKey(), "mOnReorderingAllowedListener");
+ removeEntry(entry.getKey(), "allowReorder");
}
}
mEntriesToRemoveWhenReorderingAllowed.clear();
@@ -617,11 +618,8 @@
super.setEntry(entry, removeRunnable);
if (NotificationThrottleHun.isEnabled()) {
- if (!mVisualStabilityProvider.isReorderingAllowed()
- // We don't want to allow reordering while pulsing, but headsup need to
- // time out anyway
- && !entry.showingPulsing()) {
- mEntriesToRemoveWhenReorderingAllowed.add(entry);
+ mEntriesToRemoveWhenReorderingAllowed.add(entry);
+ if (!mVisualStabilityProvider.isReorderingAllowed()) {
entry.setSeenInShade(true);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 50e9249..59533b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -372,7 +372,6 @@
private final Point mCurrentDisplaySize = new Point();
- protected PhoneStatusBarView mStatusBarView;
private PhoneStatusBarViewController mPhoneStatusBarViewController;
private PhoneStatusBarTransitions mStatusBarTransitions;
private final AuthRippleController mAuthRippleController;
@@ -1191,8 +1190,7 @@
// Set up CollapsedStatusBarFragment and PhoneStatusBarView
mStatusBarInitializer.setStatusBarViewUpdatedListener(
- (statusBarView, statusBarViewController, statusBarTransitions) -> {
- mStatusBarView = statusBarView;
+ (statusBarViewController, statusBarTransitions) -> {
mPhoneStatusBarViewController = statusBarViewController;
mStatusBarTransitions = statusBarTransitions;
getNotificationShadeWindowViewController()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 659cee3..a8b4728 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -55,8 +55,9 @@
import com.android.systemui.statusbar.OperatorNameView;
import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.chips.shared.StatusBarRonChips;
-import com.android.systemui.statusbar.disableflags.DisableFlagsLogger.DisableState;
+import com.android.systemui.statusbar.chips.ron.shared.StatusBarRonChips;
+import com.android.systemui.statusbar.core.StatusBarSimpleFragment;
+import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder;
@@ -366,8 +367,10 @@
mPrimaryOngoingActivityChip = mStatusBar.findViewById(R.id.ongoing_activity_chip_primary);
mSecondaryOngoingActivityChip =
mStatusBar.findViewById(R.id.ongoing_activity_chip_secondary);
- showEndSideContent(false);
- showClock(false);
+ if (!StatusBarSimpleFragment.isEnabled()) {
+ showEndSideContent(false);
+ showClock(false);
+ }
initOperatorName();
initNotificationIconArea();
mSystemEventAnimator = getSystemEventAnimator();
@@ -455,7 +458,9 @@
super.onPause();
mCommandQueue.removeCallback(this);
mStatusBarStateController.removeCallback(this);
- mOngoingCallController.removeCallback(mOngoingCallListener);
+ if (!StatusBarSimpleFragment.isEnabled()) {
+ mOngoingCallController.removeCallback(mOngoingCallListener);
+ }
mAnimationScheduler.removeCallback(this);
mSecureSettings.unregisterContentObserverSync(mVolumeSettingObserver);
}
@@ -490,7 +495,9 @@
mNotificationIconAreaInner = notificationIcons;
mNicBindingDisposable = mNicViewBinder.bindWhileAttached(notificationIcons);
- updateNotificationIconAreaAndOngoingActivityChip(/* animate= */ false);
+ if (!StatusBarSimpleFragment.isEnabled()) {
+ updateNotificationIconAreaAndOngoingActivityChip(/* animate= */ false);
+ }
Trace.endSection();
}
@@ -509,11 +516,17 @@
new StatusBarVisibilityChangeListener() {
@Override
public void onStatusBarVisibilityMaybeChanged() {
+ if (StatusBarSimpleFragment.isEnabled()) {
+ return;
+ }
updateStatusBarVisibilities(/* animate= */ true);
}
@Override
public void onTransitionFromLockscreenToDreamStarted() {
+ if (StatusBarSimpleFragment.isEnabled()) {
+ return;
+ }
mTransitionFromLockscreenToDreamStarted = true;
}
@@ -522,6 +535,9 @@
boolean hasPrimaryOngoingActivity,
boolean hasSecondaryOngoingActivity,
boolean shouldAnimate) {
+ if (StatusBarSimpleFragment.isEnabled()) {
+ return;
+ }
mHasPrimaryOngoingActivity = hasPrimaryOngoingActivity;
mHasSecondaryOngoingActivity = hasSecondaryOngoingActivity;
updateStatusBarVisibilities(shouldAnimate);
@@ -530,6 +546,9 @@
@Override
public void onIsHomeStatusBarAllowedBySceneChanged(
boolean isHomeStatusBarAllowedByScene) {
+ if (StatusBarSimpleFragment.isEnabled()) {
+ return;
+ }
mHomeStatusBarAllowedByScene = isHomeStatusBarAllowedByScene;
updateStatusBarVisibilities(/* animate= */ true);
}
@@ -537,17 +556,22 @@
@Override
public void disable(int displayId, int state1, int state2, boolean animate) {
+ if (StatusBarSimpleFragment.isEnabled()) {
+ return;
+ }
if (displayId != getContext().getDisplayId()) {
return;
}
mCollapsedStatusBarFragmentLogger
- .logDisableFlagChange(new DisableState(state1, state2));
+ .logDisableFlagChange(new DisableFlagsLogger.DisableState(state1, state2));
mLastSystemVisibility =
StatusBarVisibilityModel.createModelFromFlags(state1, state2);
updateStatusBarVisibilities(animate);
}
private void updateStatusBarVisibilities(boolean animate) {
+ StatusBarSimpleFragment.assertInLegacyMode();
+
StatusBarVisibilityModel previousModel = mLastModifiedVisibility;
StatusBarVisibilityModel newModel = calculateInternalModel(mLastSystemVisibility);
mCollapsedStatusBarFragmentLogger.logVisibilityModel(newModel);
@@ -587,6 +611,8 @@
private StatusBarVisibilityModel calculateInternalModel(
StatusBarVisibilityModel externalModel) {
+ StatusBarSimpleFragment.assertInLegacyMode();
+
// TODO(b/328393714) use HeadsUpNotificationInteractor.showHeadsUpStatusBar instead.
boolean headsUpVisible =
mStatusBarFragmentComponent.getHeadsUpAppearanceController().shouldBeVisible();
@@ -639,6 +665,8 @@
* mLastModifiedVisibility.
*/
private void updateNotificationIconAreaAndOngoingActivityChip(boolean animate) {
+ StatusBarSimpleFragment.assertInLegacyMode();
+
StatusBarVisibilityModel visibilityModel = mLastModifiedVisibility;
boolean disableNotifications = !visibilityModel.getShowNotificationIcons();
boolean hasOngoingActivity = visibilityModel.getShowPrimaryOngoingActivityChip();
@@ -674,6 +702,8 @@
}
private boolean shouldHideStatusBar() {
+ StatusBarSimpleFragment.assertInLegacyMode();
+
if (!mShadeExpansionStateManager.isClosed()
&& mPanelExpansionInteractor.shouldHideStatusBarIconsWhenExpanded()) {
return true;
@@ -728,6 +758,7 @@
}
private void hideEndSideContent(boolean animate) {
+ StatusBarSimpleFragment.assertInLegacyMode();
if (!animate || !mAnimationsEnabled) {
mEndSideAlphaController.setAlpha(/*alpha*/ 0f, SOURCE_OTHER);
} else {
@@ -737,6 +768,7 @@
}
private void showEndSideContent(boolean animate) {
+ StatusBarSimpleFragment.assertInLegacyMode();
if (!animate || !mAnimationsEnabled) {
mEndSideAlphaController.setAlpha(1f, SOURCE_OTHER);
return;
@@ -753,15 +785,18 @@
}
private void hideClock(boolean animate) {
+ StatusBarSimpleFragment.assertInLegacyMode();
animateHiddenState(mClockView, clockHiddenMode(), animate);
}
private void showClock(boolean animate) {
+ StatusBarSimpleFragment.assertInLegacyMode();
animateShow(mClockView, animate);
}
/** Hides the primary ongoing activity chip. */
private void hidePrimaryOngoingActivityChip(boolean animate) {
+ StatusBarSimpleFragment.assertInLegacyMode();
animateHiddenState(mPrimaryOngoingActivityChip, View.GONE, animate);
}
@@ -773,15 +808,18 @@
* activities. See b/332662551.
*/
private void showPrimaryOngoingActivityChip(boolean animate) {
+ StatusBarSimpleFragment.assertInLegacyMode();
animateShow(mPrimaryOngoingActivityChip, animate);
}
private void hideSecondaryOngoingActivityChip(boolean animate) {
+ StatusBarSimpleFragment.assertInLegacyMode();
animateHiddenState(mSecondaryOngoingActivityChip, View.GONE, animate);
}
private void showSecondaryOngoingActivityChip(boolean animate) {
StatusBarRonChips.assertInNewMode();
+ StatusBarSimpleFragment.assertInLegacyMode();
animateShow(mSecondaryOngoingActivityChip, animate);
}
@@ -790,6 +828,7 @@
* don't set the clock GONE otherwise it'll mess up the animation.
*/
private int clockHiddenMode() {
+ StatusBarSimpleFragment.assertInLegacyMode();
if (!mShadeExpansionStateManager.isClosed() && !mKeyguardStateController.isShowing()
&& !mStatusBarStateController.isDozing()) {
return View.INVISIBLE;
@@ -798,20 +837,24 @@
}
public void hideNotificationIconArea(boolean animate) {
+ StatusBarSimpleFragment.assertInLegacyMode();
animateHide(mNotificationIconAreaInner, animate);
}
public void showNotificationIconArea(boolean animate) {
+ StatusBarSimpleFragment.assertInLegacyMode();
animateShow(mNotificationIconAreaInner, animate);
}
public void hideOperatorName(boolean animate) {
+ StatusBarSimpleFragment.assertInLegacyMode();
if (mOperatorNameViewController != null) {
animateHide(mOperatorNameViewController.getView(), animate);
}
}
public void showOperatorName(boolean animate) {
+ StatusBarSimpleFragment.assertInLegacyMode();
if (mOperatorNameViewController != null) {
animateShow(mOperatorNameViewController.getView(), animate);
}
@@ -821,6 +864,7 @@
* Animate a view to INVISIBLE or GONE
*/
private void animateHiddenState(final View v, int state, boolean animate) {
+ StatusBarSimpleFragment.assertInLegacyMode();
v.animate().cancel();
if (!animate || !mAnimationsEnabled) {
v.setAlpha(0f);
@@ -840,6 +884,7 @@
* Hides a view.
*/
private void animateHide(final View v, boolean animate) {
+ StatusBarSimpleFragment.assertInLegacyMode();
animateHiddenState(v, View.INVISIBLE, animate);
}
@@ -847,6 +892,7 @@
* Shows a view, and synchronizes the animation with Keyguard exit animations, if applicable.
*/
private void animateShow(View v, boolean animate) {
+ StatusBarSimpleFragment.assertInLegacyMode();
v.animate().cancel();
v.setVisibility(View.VISIBLE);
if (!animate || !mAnimationsEnabled) {
@@ -883,13 +929,17 @@
mOperatorNameViewController.init();
// This view should not be visible on lock-screen
if (mKeyguardStateController.isShowing()) {
- hideOperatorName(false);
+ if (!StatusBarSimpleFragment.isEnabled()) {
+ hideOperatorName(false);
+ }
}
}
}
private void initOngoingCallChip() {
- mOngoingCallController.addCallback(mOngoingCallListener);
+ if (!StatusBarSimpleFragment.isEnabled()) {
+ mOngoingCallController.addCallback(mOngoingCallListener);
+ }
// TODO(b/364653005): Do we also need to set the secondary activity chip?
mOngoingCallController.setChipView(mPrimaryOngoingActivityChip);
}
@@ -899,6 +949,9 @@
@Override
public void onDozingChanged(boolean isDozing) {
+ if (StatusBarSimpleFragment.isEnabled()) {
+ return;
+ }
updateStatusBarVisibilities(/* animate= */ false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaController.kt
index c8836e4..eaf15a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaController.kt
@@ -20,6 +20,7 @@
import androidx.core.animation.Interpolator
import androidx.core.animation.ValueAnimator
import com.android.app.animation.InterpolatorsAndroidX
+import com.android.systemui.statusbar.core.StatusBarSimpleFragment
/**
* A controller that keeps track of multiple sources applying alpha value changes to a view. It will
@@ -48,7 +49,7 @@
sourceId: Int,
duration: Long,
interpolator: Interpolator = InterpolatorsAndroidX.ALPHA_IN,
- startDelay: Long = 0
+ startDelay: Long = 0,
) {
animators[sourceId]?.cancel()
val animator = ValueAnimator.ofFloat(getMinAlpha(), alpha)
@@ -74,8 +75,10 @@
private fun applyAlphaToView() {
val minAlpha = getMinAlpha()
- view.visibility = if (minAlpha != 0f) View.VISIBLE else View.INVISIBLE
- view.alpha = minAlpha
+ if (!StatusBarSimpleFragment.isEnabled) {
+ view.visibility = if (minAlpha != 0f) View.VISIBLE else View.INVISIBLE
+ view.alpha = minAlpha
+ }
}
private fun getMinAlpha() = alphas.minOfOrNull { it.value } ?: initialAlpha
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
index c0e36b2..f026b99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
@@ -27,7 +27,6 @@
import com.android.systemui.statusbar.phone.PhoneStatusBarView;
import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
import com.android.systemui.statusbar.phone.StatusBarLocation;
-import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.statusbar.window.StatusBarWindowController;
@@ -114,14 +113,6 @@
/** */
@Provides
@StatusBarFragmentScope
- static StatusBarUserSwitcherContainer provideStatusBarUserSwitcherContainer(
- @RootView PhoneStatusBarView view) {
- return view.findViewById(R.id.user_switcher_container);
- }
-
- /** */
- @Provides
- @StatusBarFragmentScope
static PhoneStatusBarViewController providePhoneStatusBarViewController(
PhoneStatusBarViewController.Factory phoneStatusBarViewControllerFactory,
@RootView PhoneStatusBarView phoneStatusBarView) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
index deae576..bad6f80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
import androidx.annotation.VisibleForTesting
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -29,6 +30,7 @@
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
@@ -114,7 +116,7 @@
private fun createViewModel(subId: Int): Pair<MobileIconViewModel, CoroutineScope> {
// Create a child scope so we can cancel it
- val vmScope = scope.createChildScope()
+ val vmScope = scope.createChildScope(createCoroutineTracingContext("MobileIconViewModel"))
val vm =
MobileIconViewModel(
subId,
@@ -128,8 +130,8 @@
return Pair(vm, vmScope)
}
- private fun CoroutineScope.createChildScope() =
- CoroutineScope(coroutineContext + Job(coroutineContext[Job]))
+ private fun CoroutineScope.createChildScope(extraContext: CoroutineContext) =
+ CoroutineScope(coroutineContext + Job(coroutineContext[Job]) + extraContext)
private fun invalidateCaches(subIds: List<Int>) {
reuseCache.keys
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt
new file mode 100644
index 0000000..9164da7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.pipeline.shared.domain.model.StatusBarDisableFlagsVisibilityModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/**
+ * Interactor for the home screen status bar (aka
+ * [com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment]).
+ */
+@SysUISingleton
+class CollapsedStatusBarInteractor
+@Inject
+constructor(disableFlagsRepository: DisableFlagsRepository) {
+ /**
+ * The visibilities of various status bar child views, based only on the information we received
+ * from disable flags.
+ */
+ val visibilityViaDisableFlags: Flow<StatusBarDisableFlagsVisibilityModel> =
+ disableFlagsRepository.disableFlags.map {
+ StatusBarDisableFlagsVisibilityModel(
+ isClockAllowed = it.isClockEnabled,
+ areNotificationIconsAllowed = it.areNotificationIconsEnabled,
+ isSystemInfoAllowed = it.isSystemInfoEnabled,
+ animate = it.animate,
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/model/StatusBarDisableFlagsVisibilityModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/model/StatusBarDisableFlagsVisibilityModel.kt
new file mode 100644
index 0000000..69e9746
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/model/StatusBarDisableFlagsVisibilityModel.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared.domain.model
+
+/**
+ * Represents the visibilities of various status bar child views, based only on the information we
+ * received from disable flags.
+ */
+data class StatusBarDisableFlagsVisibilityModel(
+ /** True if the clock is allowed to be shown. */
+ val isClockAllowed: Boolean,
+ /** True if the notification icons are allowed to be shown. */
+ val areNotificationIconsAllowed: Boolean,
+ /** True if the system information (wifi, mobile, etc.) is allowed to be shown. */
+ val isSystemInfoAllowed: Boolean,
+ /** True if we should animate any view visibility changes and false otherwise. */
+ val animate: Boolean,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
index 49eabba..4cb66c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
@@ -21,6 +21,7 @@
import android.view.View
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.animation.Interpolators
import com.android.systemui.Flags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.repeatWhenAttached
@@ -28,7 +29,9 @@
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.statusbar.chips.ui.binder.OngoingActivityChipBinder
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.core.StatusBarSimpleFragment
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
+import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel
import javax.inject.Inject
import kotlinx.coroutines.launch
@@ -134,6 +137,29 @@
}
}
}
+
+ if (StatusBarSimpleFragment.isEnabled) {
+ val clockView = view.requireViewById<View>(R.id.clock)
+ launch { viewModel.isClockVisible.collect { clockView.adjustVisibility(it) } }
+
+ val notificationIconsArea = view.requireViewById<View>(R.id.notificationIcons)
+ launch {
+ viewModel.isNotificationIconContainerVisible.collect {
+ notificationIconsArea.adjustVisibility(it)
+ }
+ }
+
+ val systemInfoView =
+ view.requireViewById<View>(R.id.status_bar_end_side_content)
+ // TODO(b/364360986): Also handle operator name view.
+ launch {
+ viewModel.isSystemInfoVisible.collect {
+ systemInfoView.adjustVisibility(it)
+ // TODO(b/364360986): The system info view has a custom alpha controller
+ // in CollapsedStatusBarFragment.
+ }
+ }
+ }
}
}
}
@@ -167,6 +193,54 @@
)
.start()
}
+
+ private fun View.adjustVisibility(model: CollapsedStatusBarViewModel.VisibilityModel) {
+ if (model.visibility == View.VISIBLE) {
+ this.show(model.shouldAnimateChange)
+ } else {
+ this.hide(model.visibility, model.shouldAnimateChange)
+ }
+ }
+
+ // See CollapsedStatusBarFragment#hide.
+ private fun View.hide(state: Int = View.INVISIBLE, shouldAnimateChange: Boolean) {
+ val v = this
+ v.animate().cancel()
+ if (!shouldAnimateChange) {
+ v.alpha = 0f
+ v.visibility = state
+ return
+ }
+
+ v.animate()
+ .alpha(0f)
+ .setDuration(CollapsedStatusBarFragment.FADE_OUT_DURATION.toLong())
+ .setStartDelay(0)
+ .setInterpolator(Interpolators.ALPHA_OUT)
+ .withEndAction { v.visibility = state }
+ }
+
+ // See CollapsedStatusBarFragment#show.
+ private fun View.show(shouldAnimateChange: Boolean) {
+ val v = this
+ v.animate().cancel()
+ v.visibility = View.VISIBLE
+ if (!shouldAnimateChange) {
+ v.alpha = 1f
+ return
+ }
+ v.animate()
+ .alpha(1f)
+ .setDuration(CollapsedStatusBarFragment.FADE_IN_DURATION.toLong())
+ .setInterpolator(Interpolators.ALPHA_IN)
+ .setStartDelay(CollapsedStatusBarFragment.FADE_IN_DELAY.toLong())
+ // We need to clean up any pending end action from animateHide if we call both hide and
+ // show in the same frame before the animation actually gets started.
+ // cancel() doesn't really remove the end action.
+ .withEndAction(null)
+
+ // TODO(b/364360986): Synchronize the motion with the Keyguard fading if necessary.
+ }
}
/** Listener for various events that may affect the status bar's visibility. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
index 9cce2b8..692e0e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
@@ -16,23 +16,29 @@
package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
+import android.view.View
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
import com.android.systemui.statusbar.phone.domain.interactor.LightsOutInteractor
+import com.android.systemui.statusbar.pipeline.shared.domain.interactor.CollapsedStatusBarInteractor
+import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel.VisibilityModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
@@ -80,9 +86,18 @@
/**
* True if the current scene can show the home status bar (aka this status bar), and false if
* the current scene should never show the home status bar.
+ *
+ * TODO(b/364360986): Once the is<SomeChildView>Visible flows are fully enabled, we shouldn't
+ * need this flow anymore.
*/
val isHomeStatusBarAllowedByScene: StateFlow<Boolean>
+ val isClockVisible: Flow<VisibilityModel>
+ val isNotificationIconContainerVisible: Flow<VisibilityModel>
+ val isSystemInfoVisible: Flow<VisibilityModel>
+
+ // TODO(b/364360986): Add isOngoingActivityChipVisible: Flow<VisibilityModel>
+
/**
* Apps can request a low profile mode [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE] where
* status bar and navigation icons dim. In this mode, a notification dot appears where the
@@ -93,17 +108,26 @@
* [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE].
*/
fun areNotificationsLightsOut(displayId: Int): Flow<Boolean>
+
+ /** Models the current visibility for a specific child view of status bar. */
+ data class VisibilityModel(
+ @View.Visibility val visibility: Int,
+ /** True if a visibility change should be animated. */
+ val shouldAnimateChange: Boolean,
+ )
}
@SysUISingleton
class CollapsedStatusBarViewModelImpl
@Inject
constructor(
+ collapsedStatusBarInteractor: CollapsedStatusBarInteractor,
private val lightsOutInteractor: LightsOutInteractor,
private val notificationsInteractor: ActiveNotificationsInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
sceneInteractor: SceneInteractor,
sceneContainerOcclusionInteractor: SceneContainerOcclusionInteractor,
+ shadeInteractor: ShadeInteractor,
ongoingActivityChipsViewModel: OngoingActivityChipsViewModel,
@Application coroutineScope: CoroutineScope,
) : CollapsedStatusBarViewModel {
@@ -148,4 +172,59 @@
}
.distinctUntilChanged()
}
+
+ /**
+ * True if the current SysUI state can show the home status bar (aka this status bar), and false
+ * if we shouldn't be showing any part of the home status bar.
+ */
+ private val isHomeScreenStatusBarAllowedLegacy: Flow<Boolean> =
+ combine(
+ keyguardTransitionInteractor.currentKeyguardState,
+ shadeInteractor.isAnyFullyExpanded,
+ ) { currentKeyguardState, isShadeExpanded ->
+ (currentKeyguardState == GONE || currentKeyguardState == OCCLUDED) && !isShadeExpanded
+ // TODO(b/364360986): Add edge cases, like secure camera launch.
+ }
+
+ private val isHomeScreenStatusBarAllowed: Flow<Boolean> =
+ if (SceneContainerFlag.isEnabled) {
+ isHomeStatusBarAllowedByScene
+ } else {
+ isHomeScreenStatusBarAllowedLegacy
+ }
+
+ override val isClockVisible: Flow<VisibilityModel> =
+ combine(
+ isHomeScreenStatusBarAllowed,
+ collapsedStatusBarInteractor.visibilityViaDisableFlags,
+ ) { isStatusBarAllowed, visibilityViaDisableFlags ->
+ val showClock = isStatusBarAllowed && visibilityViaDisableFlags.isClockAllowed
+ // TODO(b/364360986): Take CollapsedStatusBarFragment.clockHiddenMode into account.
+ VisibilityModel(showClock.toVisibilityInt(), visibilityViaDisableFlags.animate)
+ }
+ override val isNotificationIconContainerVisible: Flow<VisibilityModel> =
+ combine(
+ isHomeScreenStatusBarAllowed,
+ collapsedStatusBarInteractor.visibilityViaDisableFlags,
+ ) { isStatusBarAllowed, visibilityViaDisableFlags ->
+ val showNotificationIconContainer =
+ isStatusBarAllowed && visibilityViaDisableFlags.areNotificationIconsAllowed
+ VisibilityModel(
+ showNotificationIconContainer.toVisibilityInt(),
+ visibilityViaDisableFlags.animate
+ )
+ }
+ override val isSystemInfoVisible: Flow<VisibilityModel> =
+ combine(
+ isHomeScreenStatusBarAllowed,
+ collapsedStatusBarInteractor.visibilityViaDisableFlags,
+ ) { isStatusBarAllowed, visibilityViaDisableFlags ->
+ val showSystemInfo = isStatusBarAllowed && visibilityViaDisableFlags.isSystemInfoAllowed
+ VisibilityModel(showSystemInfo.toVisibilityInt(), visibilityViaDisableFlags.animate)
+ }
+
+ @View.Visibility
+ private fun Boolean.toVisibilityInt(): Int {
+ return if (this) View.VISIBLE else View.GONE
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
index 5ba5c06..caf09a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
@@ -46,6 +46,8 @@
private val tag = "AvalancheController"
private val debug = Compile.IS_DEBUG && Log.isLoggable(tag, Log.DEBUG)
+ var baseEntryMapStr : () -> String = { "baseEntryMapStr not initialized" }
+
var enableAtRuntime = true
set(value) {
if (!value) {
@@ -116,32 +118,43 @@
val key = getKey(entry)
if (runnable == null) {
- headsUpManagerLogger.logAvalancheUpdate(caller, isEnabled, key, "Runnable NULL, stop")
+ headsUpManagerLogger.logAvalancheUpdate(
+ caller, isEnabled, key,
+ "Runnable NULL, stop. ${getStateStr()}"
+ )
return
}
if (!isEnabled) {
- headsUpManagerLogger.logAvalancheUpdate(caller, isEnabled, key,
- "NOT ENABLED, run runnable")
+ headsUpManagerLogger.logAvalancheUpdate(
+ caller, isEnabled, key,
+ "NOT ENABLED, run runnable. ${getStateStr()}"
+ )
runnable.run()
return
}
if (entry == null) {
- headsUpManagerLogger.logAvalancheUpdate(caller, isEnabled, key, "Entry NULL, stop")
+ headsUpManagerLogger.logAvalancheUpdate(
+ caller, isEnabled, key,
+ "Entry NULL, stop. ${getStateStr()}"
+ )
return
}
if (debug) {
debugRunnableLabelMap[runnable] = caller
}
- var outcome = ""
+ var stateAfter = ""
if (isShowing(entry)) {
- outcome = "update showing"
runnable.run()
+ stateAfter = "update showing"
+
} else if (entry in nextMap) {
- outcome = "update next"
nextMap[entry]?.add(runnable)
+ stateAfter = "update next"
+
} else if (headsUpEntryShowing == null) {
- outcome = "show now"
showNow(entry, arrayListOf(runnable))
+ stateAfter = "show now"
+
} else {
// Clean up invalid state when entry is in list but not map and vice versa
if (entry in nextMap) nextMap.remove(entry)
@@ -162,8 +175,8 @@
)
}
}
- outcome += getStateStr()
- headsUpManagerLogger.logAvalancheUpdate(caller, isEnabled, key, outcome)
+ stateAfter += getStateStr()
+ headsUpManagerLogger.logAvalancheUpdate(caller, isEnabled = true, key, stateAfter)
}
@VisibleForTesting
@@ -181,32 +194,40 @@
val key = getKey(entry)
if (runnable == null) {
- headsUpManagerLogger.logAvalancheDelete(caller, isEnabled, key, "Runnable NULL, stop")
+ headsUpManagerLogger.logAvalancheDelete(
+ caller, isEnabled, key,
+ "Runnable NULL, stop. ${getStateStr()}"
+ )
return
}
if (!isEnabled) {
- headsUpManagerLogger.logAvalancheDelete(caller, isEnabled, key,
- "NOT ENABLED, run runnable")
runnable.run()
+ headsUpManagerLogger.logAvalancheDelete(
+ caller, isEnabled = false, key,
+ "NOT ENABLED, run runnable. ${getStateStr()}"
+ )
return
}
if (entry == null) {
- headsUpManagerLogger.logAvalancheDelete(caller, isEnabled, key,
- "Entry NULL, run runnable")
runnable.run()
+ headsUpManagerLogger.logAvalancheDelete(
+ caller, isEnabled = true, key,
+ "Entry NULL, run runnable. ${getStateStr()}"
+ )
return
}
- var outcome = ""
+ val stateAfter: String
if (entry in nextMap) {
- outcome = "remove from next"
if (entry in nextMap) nextMap.remove(entry)
if (entry in nextList) nextList.remove(entry)
uiEventLogger.log(ThrottleEvent.AVALANCHE_THROTTLING_HUN_REMOVED)
+ stateAfter = "remove from next. ${getStateStr()}"
+
} else if (entry in debugDropSet) {
- outcome = "remove from dropset"
debugDropSet.remove(entry)
+ stateAfter = "remove from dropset. ${getStateStr()}"
+
} else if (isShowing(entry)) {
- outcome = "remove showing"
previousHunKey = getKey(headsUpEntryShowing)
// Show the next HUN before removing this one, so that we don't tell listeners
// onHeadsUpPinnedModeChanged, which causes
@@ -214,11 +235,13 @@
// HUN is animating out, resulting in a flicker.
showNext()
runnable.run()
+ stateAfter = "remove showing. ${getStateStr()}"
+
} else {
- outcome = "run runnable for untracked shown"
runnable.run()
+ stateAfter = "run runnable for untracked shown HUN. ${getStateStr()}"
}
- headsUpManagerLogger.logAvalancheDelete(caller, isEnabled(), getKey(entry), outcome)
+ headsUpManagerLogger.logAvalancheDelete(caller, isEnabled(), getKey(entry), stateAfter)
}
/**
@@ -400,12 +423,14 @@
}
private fun getStateStr(): String {
- return "\navalanche state:" +
+ return "\nAvalancheController:" +
"\n\tshowing: [${getKey(headsUpEntryShowing)}]" +
"\n\tprevious: [$previousHunKey]" +
"\n\tnext list: $nextListStr" +
"\n\tnext map: $nextMapStr" +
- "\n\tdropped: $dropSetStr"
+ "\n\tdropped: $dropSetStr" +
+ "\nBHUM.mHeadsUpEntryMap: " +
+ baseEntryMapStr()
}
private val dropSetStr: String
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
index f37393a..30524a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
@@ -116,6 +116,7 @@
mAccessibilityMgr = accessibilityManagerWrapper;
mUiEventLogger = uiEventLogger;
mAvalancheController = avalancheController;
+ mAvalancheController.setBaseEntryMapStr(this::getEntryMapStr);
Resources resources = context.getResources();
mMinimumDisplayTime = NotificationThrottleHun.isEnabled()
? 500 : resources.getInteger(R.integer.heads_up_notification_minimum_time);
@@ -589,6 +590,18 @@
dumpInternal(pw, args);
}
+ private String getEntryMapStr() {
+ if (mHeadsUpEntryMap.isEmpty()) {
+ return "EMPTY";
+ }
+ StringBuilder entryMapStr = new StringBuilder();
+ for (HeadsUpEntry entry: mHeadsUpEntryMap.values()) {
+ entryMapStr.append("\n\t").append(
+ entry.mEntry == null ? "null" : entry.mEntry.getKey());
+ }
+ return entryMapStr.toString();
+ }
+
protected void dumpInternal(@NonNull PrintWriter pw, @NonNull String[] args) {
pw.print(" mTouchAcceptanceDelay="); pw.println(mTouchAcceptanceDelay);
pw.print(" mSnoozeLengthMs="); pw.println(mSnoozeLengthMs);
@@ -992,7 +1005,6 @@
* Clear any pending removal runnables.
*/
public void cancelAutoRemovalCallbacks(@Nullable String reason) {
- mLogger.logAutoRemoveCancelRequest(this.mEntry, reason);
Runnable runnable = () -> {
final boolean removed = cancelAutoRemovalCallbackInternal();
@@ -1001,6 +1013,7 @@
}
};
if (mEntry != null && isHeadsUpEntry(mEntry.getKey())) {
+ mLogger.logAutoRemoveCancelRequest(this.mEntry, reason);
mAvalancheController.update(this, runnable, reason + " cancelAutoRemovalCallbacks");
} else {
// Just removed
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
index 600270c..41112cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
@@ -52,7 +52,7 @@
caller: String,
isEnabled: Boolean,
notifEntryKey: String,
- outcome: String
+ stateAfter: String
) {
buffer.log(
TAG,
@@ -60,7 +60,7 @@
{
str1 = caller
str2 = notifEntryKey
- str3 = outcome
+ str3 = stateAfter
bool1 = isEnabled
},
{ "$str1\n\t=> AC[isEnabled:$bool1] update: $str2\n\t=> $str3" }
@@ -71,7 +71,7 @@
caller: String,
isEnabled: Boolean,
notifEntryKey: String,
- outcome: String
+ stateAfter: String
) {
buffer.log(
TAG,
@@ -79,7 +79,7 @@
{
str1 = caller
str2 = notifEntryKey
- str3 = outcome
+ str3 = stateAfter
bool1 = isEnabled
},
{ "$str1\n\t=> AC[isEnabled:$bool1] delete: $str2\n\t=> $str3" }
@@ -136,7 +136,7 @@
str1 = entry.logKey
str2 = reason ?: "unknown"
},
- { "request: cancel auto remove of $str1 reason: $str2" }
+ { "$str2 => request: cancelAutoRemovalCallbacks: $str1" }
)
}
@@ -148,7 +148,7 @@
str1 = entry.logKey
str2 = reason ?: "unknown"
},
- { "cancel auto remove of $str1 reason: $str2" }
+ { "$str2 => cancel auto remove: $str1" }
)
}
@@ -161,7 +161,7 @@
str2 = reason
bool1 = isWaiting
},
- { "request: $str2 => remove entry $str1 isWaiting: $isWaiting" }
+ { "request: $str2 => removeEntry: $str1 isWaiting: $isWaiting" }
)
}
@@ -174,7 +174,7 @@
str2 = reason
bool1 = isWaiting
},
- { "$str2 => remove entry $str1 isWaiting: $isWaiting" }
+ { "$str2 => removeEntry: $str1 isWaiting: $isWaiting" }
)
}
@@ -216,12 +216,12 @@
str1 = logKey(key)
str2 = reason
},
- { "remove notification $str1 when headsUpEntry is null, reason: $str2" }
+ { "remove notif $str1 when headsUpEntry is null, reason: $str2" }
)
}
fun logNotificationActuallyRemoved(entry: NotificationEntry) {
- buffer.log(TAG, INFO, { str1 = entry.logKey }, { "notification removed $str1 " })
+ buffer.log(TAG, INFO, { str1 = entry.logKey }, { "removed: $str1 " })
}
fun logUpdateNotificationRequest(key: String, alert: Boolean, hasEntry: Boolean) {
@@ -233,7 +233,7 @@
bool1 = alert
bool2 = hasEntry
},
- { "request: update notification $str1 alert: $bool1 hasEntry: $bool2" }
+ { "request: update notif $str1 alert: $bool1 hasEntry: $bool2" }
)
}
@@ -246,7 +246,7 @@
bool1 = alert
bool2 = hasEntry
},
- { "update notification $str1 alert: $bool1 hasEntry: $bool2" }
+ { "update notif $str1 alert: $bool1 hasEntry: $bool2" }
)
}
@@ -281,7 +281,7 @@
bool1 = isPinned
str2 = reason
},
- { "$str2 => set entry pinned $str1 pinned: $bool1" }
+ { "$str2 => setEntryPinned[$bool1]: $str1" }
)
}
@@ -290,7 +290,7 @@
TAG,
INFO,
{ bool1 = hasPinnedNotification },
- { "has pinned notification changed to $bool1" }
+ { "hasPinnedNotification[$bool1]" }
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt
new file mode 100644
index 0000000..421e5c4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.window
+
+import android.view.View
+import android.view.ViewGroup
+import com.android.systemui.animation.ActivityTransitionAnimator
+import com.android.systemui.fragments.FragmentHostManager
+import java.util.Optional
+
+/** Encapsulates all logic for the status bar window state management. */
+interface StatusBarWindowController {
+ val statusBarHeight: Int
+
+ /** Rereads the status bar height and reapplies the current state if the height is different. */
+ fun refreshStatusBarHeight()
+
+ /** Adds the status bar view to the window manager. */
+ fun attach()
+
+ /** Adds the given view to the status bar window view. */
+ fun addViewToWindow(view: View, layoutParams: ViewGroup.LayoutParams)
+
+ /** Returns the status bar window's background view. */
+ val backgroundView: View
+
+ /** Returns a fragment host manager for the status bar window view. */
+ val fragmentHostManager: FragmentHostManager
+
+ /**
+ * Provides an updated animation controller if we're animating a view in the status bar.
+ *
+ * This is needed because we have to make sure that the status bar window matches the full
+ * screen during the animation and that we are expanding the view below the other status bar
+ * text.
+ *
+ * @param rootView the root view of the animation
+ * @param animationController the default animation controller to use
+ * @return If the animation is on a view in the status bar, returns an Optional containing an
+ * updated animation controller that handles status-bar-related animation details. Returns an
+ * empty optional if the animation is *not* on a view in the status bar.
+ */
+ fun wrapAnimationControllerIfInStatusBar(
+ rootView: View,
+ animationController: ActivityTransitionAnimator.Controller,
+ ): Optional<ActivityTransitionAnimator.Controller>
+
+ /** Set force status bar visible. */
+ fun setForceStatusBarVisible(forceStatusBarVisible: Boolean)
+
+ /**
+ * Sets whether an ongoing process requires the status bar to be forced visible.
+ *
+ * This method is separate from {@link this#setForceStatusBarVisible} because the ongoing
+ * process **takes priority**. For example, if {@link this#setForceStatusBarVisible} is set to
+ * false but this method is set to true, then the status bar **will** be visible.
+ *
+ * TODO(b/195839150): We should likely merge this method and {@link
+ * this#setForceStatusBarVisible} together and use some sort of ranking system instead.
+ */
+ fun setOngoingProcessRequiresStatusBarVisible(visible: Boolean)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
similarity index 81%
rename from packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
index c30a6b7d..1ee7cf3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
@@ -28,7 +28,6 @@
import static com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN;
import android.content.Context;
-import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
@@ -46,28 +45,30 @@
import android.view.WindowInsets;
import android.view.WindowManager;
+import androidx.annotation.NonNull;
+
import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.animation.ActivityTransitionAnimator;
import com.android.systemui.animation.DelegateTransitionAnimatorController;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
+import com.android.systemui.statusbar.window.StatusBarWindowModule.InternalWindowViewInflater;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.unfold.util.JankMonitorTransitionProgressListener;
-import java.util.Optional;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
-import javax.inject.Inject;
+import java.util.Optional;
/**
* Encapsulates all logic for the status bar window state management.
*/
-@SysUISingleton
-public class StatusBarWindowController {
+public class StatusBarWindowControllerImpl implements StatusBarWindowController {
private static final String TAG = "StatusBarWindowController";
private static final boolean DEBUG = false;
@@ -88,21 +89,20 @@
private final WindowManager.LayoutParams mLpChanged;
private final Binder mInsetsSourceOwner = new Binder();
- @Inject
- public StatusBarWindowController(
- Context context,
- @StatusBarWindowModule.InternalWindowView StatusBarWindowView statusBarWindowView,
- ViewCaptureAwareWindowManager viewCaptureAwareWindowManager,
+ @AssistedInject
+ public StatusBarWindowControllerImpl(
+ @Assisted Context context,
+ @InternalWindowViewInflater StatusBarWindowViewInflater statusBarWindowViewInflater,
+ @Assisted ViewCaptureAwareWindowManager viewCaptureAwareWindowManager,
IWindowManager iWindowManager,
StatusBarContentInsetsProvider contentInsetsProvider,
FragmentService fragmentService,
- @Main Resources resources,
Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider) {
mContext = context;
mWindowManager = viewCaptureAwareWindowManager;
mIWindowManager = iWindowManager;
mContentInsetsProvider = contentInsetsProvider;
- mStatusBarWindowView = statusBarWindowView;
+ mStatusBarWindowView = statusBarWindowViewInflater.inflate(context);
mFragmentService = fragmentService;
mLaunchAnimationContainer = mStatusBarWindowView.findViewById(
R.id.status_bar_launch_animation_container);
@@ -117,14 +117,12 @@
/* attachedViewProvider=*/ () -> mStatusBarWindowView)));
}
+ @Override
public int getStatusBarHeight() {
return mBarHeight;
}
- /**
- * Rereads the status bar height and reapplys the current state if the height
- * is different.
- */
+ @Override
public void refreshStatusBarHeight() {
Trace.beginSection("StatusBarWindowController#refreshStatusBarHeight");
try {
@@ -141,9 +139,7 @@
}
}
- /**
- * Adds the status bar view to the window manager.
- */
+ @Override
public void attach() {
// Now that the status bar window encompasses the sliding panel and its
// translucent backdrop, the entire thing is made TRANSLUCENT and is
@@ -161,54 +157,47 @@
apply(mCurrentState);
}
- /** Adds the given view to the status bar window view. */
- public void addViewToWindow(View view, ViewGroup.LayoutParams layoutParams) {
+ @Override
+ public void addViewToWindow(@NonNull View view, @NonNull ViewGroup.LayoutParams layoutParams) {
mStatusBarWindowView.addView(view, layoutParams);
}
- /** Returns the status bar window's background view. */
+ @NonNull
+ @Override
public View getBackgroundView() {
return mStatusBarWindowView.findViewById(R.id.status_bar_container);
}
- /** Returns a fragment host manager for the status bar window view. */
+ @NonNull
+ @Override
public FragmentHostManager getFragmentHostManager() {
return mFragmentService.getFragmentHostManager(mStatusBarWindowView);
}
- /**
- * Provides an updated animation controller if we're animating a view in the status bar.
- *
- * This is needed because we have to make sure that the status bar window matches the full
- * screen during the animation and that we are expanding the view below the other status bar
- * text.
- *
- * @param rootView the root view of the animation
- * @param animationController the default animation controller to use
- * @return If the animation is on a view in the status bar, returns an Optional containing an
- * updated animation controller that handles status-bar-related animation details. Returns an
- * empty optional if the animation is *not* on a view in the status bar.
- */
+ @NonNull
+ @Override
public Optional<ActivityTransitionAnimator.Controller> wrapAnimationControllerIfInStatusBar(
- View rootView, ActivityTransitionAnimator.Controller animationController) {
+ @NonNull View rootView,
+ @NonNull ActivityTransitionAnimator.Controller animationController) {
if (rootView != mStatusBarWindowView) {
return Optional.empty();
}
animationController.setTransitionContainer(mLaunchAnimationContainer);
- return Optional.of(new DelegateTransitionAnimatorController(animationController) {
- @Override
- public void onTransitionAnimationStart(boolean isExpandingFullyAbove) {
- getDelegate().onTransitionAnimationStart(isExpandingFullyAbove);
- setLaunchAnimationRunning(true);
- }
+ return Optional.of(
+ new DelegateTransitionAnimatorController(animationController) {
+ @Override
+ public void onTransitionAnimationStart(boolean isExpandingFullyAbove) {
+ getDelegate().onTransitionAnimationStart(isExpandingFullyAbove);
+ setLaunchAnimationRunning(true);
+ }
- @Override
- public void onTransitionAnimationEnd(boolean isExpandingFullyAbove) {
- getDelegate().onTransitionAnimationEnd(isExpandingFullyAbove);
- setLaunchAnimationRunning(false);
- }
- });
+ @Override
+ public void onTransitionAnimationEnd(boolean isExpandingFullyAbove) {
+ getDelegate().onTransitionAnimationEnd(isExpandingFullyAbove);
+ setLaunchAnimationRunning(false);
+ }
+ });
}
private WindowManager.LayoutParams getBarLayoutParams(int rotation) {
@@ -275,22 +264,13 @@
}
}
- /** Set force status bar visible. */
+ @Override
public void setForceStatusBarVisible(boolean forceStatusBarVisible) {
mCurrentState.mForceStatusBarVisible = forceStatusBarVisible;
apply(mCurrentState);
}
- /**
- * Sets whether an ongoing process requires the status bar to be forced visible.
- *
- * This method is separate from {@link this#setForceStatusBarVisible} because the ongoing
- * process **takes priority**. For example, if {@link this#setForceStatusBarVisible} is set to
- * false but this method is set to true, then the status bar **will** be visible.
- *
- * TODO(b/195839150): We should likely merge this method and
- * {@link this#setForceStatusBarVisible} together and use some sort of ranking system instead.
- */
+ @Override
public void setOngoingProcessRequiresStatusBarVisible(boolean visible) {
mCurrentState.mOngoingProcessRequiresStatusBarVisible = visible;
apply(mCurrentState);
@@ -372,4 +352,13 @@
mLpChanged.forciblyShownTypes &= ~WindowInsets.Type.statusBars();
}
}
+
+ @AssistedFactory
+ public interface Factory {
+ /** Creates a new instance. */
+ StatusBarWindowControllerImpl create(
+ Context context,
+ ViewCaptureAwareWindowManager viewCaptureAwareWindowManager);
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt
index 1c7debc..ebfbac7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt
@@ -1,47 +1,36 @@
package com.android.systemui.statusbar.window
-import android.view.LayoutInflater
-import com.android.systemui.res.R
import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
import dagger.Module
-import dagger.Provides
import javax.inject.Qualifier
/** Module providing dependencies related to the status bar window. */
@Module
abstract class StatusBarWindowModule {
- /**
- * Provides a [StatusBarWindowView].
- *
- * Only [StatusBarWindowController] should inject the view.
- */
- @Module
- companion object {
- @JvmStatic
- @Provides
- @SysUISingleton
- @InternalWindowView
- fun providesStatusBarWindowView(layoutInflater: LayoutInflater): StatusBarWindowView {
- return layoutInflater.inflate(
- R.layout.super_status_bar,
- /* root= */null
- ) as StatusBarWindowView?
- ?: throw IllegalStateException(
- "R.layout.super_status_bar could not be properly inflated"
- )
- }
- }
/**
- * We want [StatusBarWindowView] to be provided to [StatusBarWindowController]'s constructor via
- * dagger so that we can provide a fake window view when testing the controller. However, we wan
- * want *only* the controller to be able to inject the window view.
+ * Binds a [StatusBarWindowViewInflater].
*
- * This protected qualifier annotation achieves this. [StatusBarWindowView] can only be injected
- * if it's annotated with [InternalWindowView], and only classes inside this [statusbar.window]
- * package can access the annotation.
+ * Only [StatusBarWindowControllerImpl] should inject it.
+ */
+ @Binds
+ @SysUISingleton
+ @InternalWindowViewInflater
+ abstract fun providesStatusBarWindowViewInflater(
+ inflaterImpl: StatusBarWindowViewInflaterImpl
+ ): StatusBarWindowViewInflater
+
+ /**
+ * We want [StatusBarWindowViewInflater] to be provided to [StatusBarWindowControllerImpl]'s
+ * constructor via dagger so that we can provide a fake window view when testing the controller.
+ * However, we wan want *only* the controller to be able to inject the window view.
+ *
+ * This protected qualifier annotation achieves this. [StatusBarWindowViewInflater] can only be
+ * injected if it's annotated with [InternalWindowViewInflater], and only classes inside this
+ * [statusbar.window] package can access the annotation.
*/
@Retention(AnnotationRetention.BINARY)
@Qualifier
- protected annotation class InternalWindowView
+ protected annotation class InternalWindowViewInflater
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt
index 8f424b2..fa9c6b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt
@@ -17,9 +17,9 @@
package com.android.systemui.statusbar.window
import android.app.StatusBarManager
-import android.app.StatusBarManager.WindowVisibleState
import android.app.StatusBarManager.WINDOW_STATE_SHOWING
import android.app.StatusBarManager.WINDOW_STATUS_BAR
+import android.app.StatusBarManager.WindowVisibleState
import android.app.StatusBarManager.windowStateToString
import android.util.Log
import com.android.systemui.dagger.SysUISingleton
@@ -31,23 +31,27 @@
/**
* A centralized class maintaining the state of the status bar window.
*
+ * @deprecated use
+ * [com.android.systemui.statusbar.window.data.repository.StatusBarWindowStateRepository] instead.
+ *
* Classes that want to get updates about the status bar window state should subscribe to this class
* via [addListener] and should NOT add their own callback on [CommandQueue].
*/
@SysUISingleton
-class StatusBarWindowStateController @Inject constructor(
- @DisplayId private val thisDisplayId: Int,
- commandQueue: CommandQueue
-) {
- private val commandQueueCallback = object : CommandQueue.Callbacks {
- override fun setWindowState(
- displayId: Int,
- @StatusBarManager.WindowType window: Int,
- @WindowVisibleState state: Int
- ) {
- [email protected](displayId, window, state)
+@Deprecated("Use StatusBarWindowRepository instead")
+class StatusBarWindowStateController
+@Inject
+constructor(@DisplayId private val thisDisplayId: Int, commandQueue: CommandQueue) {
+ private val commandQueueCallback =
+ object : CommandQueue.Callbacks {
+ override fun setWindowState(
+ displayId: Int,
+ @StatusBarManager.WindowType window: Int,
+ @WindowVisibleState state: Int,
+ ) {
+ [email protected](displayId, window, state)
+ }
}
- }
private val listeners: MutableSet<StatusBarWindowStateListener> = HashSet()
@WindowVisibleState private var windowState: Int = WINDOW_STATE_SHOWING
@@ -71,7 +75,7 @@
private fun setWindowState(
displayId: Int,
@StatusBarManager.WindowType window: Int,
- @WindowVisibleState state: Int
+ @WindowVisibleState state: Int,
) {
if (displayId != thisDisplayId) {
return
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowViewInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowViewInflater.kt
new file mode 100644
index 0000000..f030a4a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowViewInflater.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.window
+
+import android.content.Context
+import android.view.LayoutInflater
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+/**
+ * Inflates a [StatusBarWindowView]. Exists so that it can be injected into
+ * [StatusBarWindowControllerImpl] and be swapped for a fake implementation in tests.
+ */
+interface StatusBarWindowViewInflater {
+ fun inflate(context: Context): StatusBarWindowView
+}
+
+class StatusBarWindowViewInflaterImpl @Inject constructor() : StatusBarWindowViewInflater {
+
+ override fun inflate(context: Context): StatusBarWindowView {
+ val layoutInflater = LayoutInflater.from(context)
+ return layoutInflater.inflate(R.layout.super_status_bar, /* root= */ null)
+ as StatusBarWindowView?
+ ?: throw IllegalStateException(
+ "R.layout.super_status_bar could not be properly inflated"
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepository.kt
new file mode 100644
index 0000000..678576d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepository.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.window.data.repository
+
+import android.app.StatusBarManager
+import android.app.StatusBarManager.WINDOW_STATE_HIDDEN
+import android.app.StatusBarManager.WINDOW_STATE_HIDING
+import android.app.StatusBarManager.WINDOW_STATE_SHOWING
+import android.app.StatusBarManager.WINDOW_STATUS_BAR
+import android.app.StatusBarManager.WindowVisibleState
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.DisplayId
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.window.data.model.StatusBarWindowState
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * A centralized class maintaining the state of the status bar window.
+ *
+ * Classes that want to get updates about the status bar window state should subscribe to
+ * [windowState] and should NOT add their own callback on [CommandQueue].
+ */
+@SysUISingleton
+class StatusBarWindowStateRepository
+@Inject
+constructor(
+ private val commandQueue: CommandQueue,
+ @DisplayId private val thisDisplayId: Int,
+ @Application private val scope: CoroutineScope,
+) {
+ val windowState: StateFlow<StatusBarWindowState> =
+ conflatedCallbackFlow {
+ val callback =
+ object : CommandQueue.Callbacks {
+ override fun setWindowState(
+ displayId: Int,
+ @StatusBarManager.WindowType window: Int,
+ @WindowVisibleState state: Int,
+ ) {
+ // TODO(b/364360986): Log the window state changes.
+ if (displayId != thisDisplayId) {
+ return
+ }
+ if (window != WINDOW_STATUS_BAR) {
+ return
+ }
+ trySend(state.toWindowState())
+ }
+ }
+ commandQueue.addCallback(callback)
+ awaitClose { commandQueue.removeCallback(callback) }
+ }
+ // Use Eagerly because we always need to know about the status bar window state
+ .stateIn(scope, SharingStarted.Eagerly, StatusBarWindowState.Hidden)
+
+ @WindowVisibleState
+ private fun Int.toWindowState(): StatusBarWindowState {
+ return when (this) {
+ WINDOW_STATE_SHOWING -> StatusBarWindowState.Showing
+ WINDOW_STATE_HIDING -> StatusBarWindowState.Hiding
+ WINDOW_STATE_HIDDEN -> StatusBarWindowState.Hidden
+ else -> StatusBarWindowState.Hidden
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/Warmable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/shared/model/StatusBarWindowState.kt
similarity index 70%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/Warmable.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/window/shared/model/StatusBarWindowState.kt
index 0df9bfa..a99046e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/Warmable.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/shared/model/StatusBarWindowState.kt
@@ -13,11 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.wm.shell.windowdecor.viewhost
+
+package com.android.systemui.statusbar.window.data.model
/**
- * An interface for an object that can be warmed up before it's needed.
+ * Represents the state of the status bar *window* as a whole (as opposed to individual views within
+ * the status bar).
*/
-interface Warmable {
- fun warmUp()
+enum class StatusBarWindowState {
+ Showing,
+ Hiding,
+ Hidden,
}
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
index bbfa32b..32a4f12 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
@@ -117,7 +117,14 @@
int displayId) {
Runnable showToastRunnable = () -> {
UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
- Context context = mContext.createContextAsUser(userHandle, 0);
+ Context context;
+ try {
+ context = mContext.createContextAsUser(userHandle, 0);
+ } catch (IllegalStateException e) {
+ // b/366533044 : Own package not found for systemui
+ Log.e(TAG, "Cannot create toast because cannot create context", e);
+ return;
+ }
DisplayManager mDisplayManager = mContext.getSystemService(DisplayManager.class);
Display display = mDisplayManager.getDisplay(displayId);
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt
index 8ecf250..2af84c7 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt
@@ -37,7 +37,7 @@
@Application
fun applicationScope(
@Main dispatcherContext: CoroutineContext,
- ): CoroutineScope = CoroutineScope(dispatcherContext)
+ ): CoroutineScope = CoroutineScope(dispatcherContext + createCoroutineTracingContext("ApplicationScope"))
@Provides
@Singleton
@@ -51,15 +51,7 @@
@Provides
@Singleton
@Main
- fun mainCoroutineContext(@Tracing tracingCoroutineContext: CoroutineContext): CoroutineContext {
- return Dispatchers.Main.immediate + tracingCoroutineContext
- }
-
- @OptIn(ExperimentalCoroutinesApi::class)
- @Provides
- @Tracing
- @Singleton
- fun tracingCoroutineContext(): CoroutineContext {
- return createCoroutineTracingContext()
+ fun mainCoroutineContext(): CoroutineContext {
+ return Dispatchers.Main.immediate
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
index a03221e..3c06828 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
@@ -91,10 +91,9 @@
@Background
@SysUISingleton
fun bgCoroutineContext(
- @Tracing tracingCoroutineContext: CoroutineContext,
@Background bgCoroutineDispatcher: CoroutineDispatcher,
): CoroutineContext {
- return bgCoroutineDispatcher + tracingCoroutineContext
+ return bgCoroutineDispatcher
}
/** Coroutine dispatcher for background operations on for UI. */
@@ -112,9 +111,8 @@
@UiBackground
@SysUISingleton
fun uiBgCoroutineContext(
- @Tracing tracingCoroutineContext: CoroutineContext,
@UiBackground uiBgCoroutineDispatcher: CoroutineDispatcher,
): CoroutineContext {
- return uiBgCoroutineDispatcher + tracingCoroutineContext
+ return uiBgCoroutineDispatcher
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
index 82f41a7..4d9aaa6 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.util.settings
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
import android.annotation.UserIdInt
import android.content.ContentResolver
import android.database.ContentObserver
@@ -93,7 +94,7 @@
*/
@AnyThread
fun registerContentObserverAsync(name: String, settingsObserver: ContentObserver) =
- CoroutineScope(backgroundDispatcher).launch {
+ CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-A")).launch {
registerContentObserverSync(getUriFor(name), settingsObserver)
}
@@ -110,7 +111,7 @@
settingsObserver: ContentObserver,
@WorkerThread registered: Runnable
) =
- CoroutineScope(backgroundDispatcher).launch {
+ CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-B")).launch {
registerContentObserverSync(getUriFor(name), settingsObserver)
registered.run()
}
@@ -143,7 +144,7 @@
*/
@AnyThread
fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) =
- CoroutineScope(backgroundDispatcher).launch {
+ CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-C")).launch {
registerContentObserverSync(uri, settingsObserver)
}
@@ -160,7 +161,7 @@
settingsObserver: ContentObserver,
@WorkerThread registered: Runnable
) =
- CoroutineScope(backgroundDispatcher).launch {
+ CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-D")).launch {
registerContentObserverSync(uri, settingsObserver)
registered.run()
}
@@ -205,7 +206,7 @@
notifyForDescendants: Boolean,
settingsObserver: ContentObserver
) =
- CoroutineScope(backgroundDispatcher).launch {
+ CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-E")).launch {
registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
}
@@ -223,7 +224,7 @@
settingsObserver: ContentObserver,
@WorkerThread registered: Runnable
) =
- CoroutineScope(backgroundDispatcher).launch {
+ CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-F")).launch {
registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
registered.run()
}
@@ -274,7 +275,7 @@
notifyForDescendants: Boolean,
settingsObserver: ContentObserver
) =
- CoroutineScope(backgroundDispatcher).launch {
+ CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-G")).launch {
registerContentObserverSync(uri, notifyForDescendants, settingsObserver)
}
@@ -292,7 +293,7 @@
settingsObserver: ContentObserver,
@WorkerThread registered: Runnable
) =
- CoroutineScope(backgroundDispatcher).launch {
+ CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-H")).launch {
registerContentObserverSync(uri, notifyForDescendants, settingsObserver)
registered.run()
}
@@ -329,7 +330,7 @@
*/
@AnyThread
fun unregisterContentObserverAsync(settingsObserver: ContentObserver) =
- CoroutineScope(backgroundDispatcher).launch { unregisterContentObserver(settingsObserver) }
+ CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-I")).launch { unregisterContentObserver(settingsObserver) }
/**
* Look up a name in the database.
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
index 8e3b813..c820c07 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.util.settings
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
import android.annotation.UserIdInt
import android.annotation.WorkerThread
import android.content.ContentResolver
@@ -78,7 +79,7 @@
}
override fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) =
- CoroutineScope(backgroundDispatcher).launch {
+ CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-A")).launch {
registerContentObserverForUserSync(uri, settingsObserver, userId)
}
@@ -112,7 +113,7 @@
notifyForDescendants: Boolean,
settingsObserver: ContentObserver
) =
- CoroutineScope(backgroundDispatcher).launch {
+ CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-B")).launch {
registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId)
}
@@ -157,7 +158,7 @@
settingsObserver: ContentObserver,
userHandle: Int
) =
- CoroutineScope(backgroundDispatcher).launch {
+ CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-C")).launch {
registerContentObserverForUserSync(getUriFor(name), settingsObserver, userHandle)
}
@@ -198,7 +199,7 @@
settingsObserver: ContentObserver,
userHandle: Int
) =
- CoroutineScope(backgroundDispatcher).launch {
+ CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-D")).launch {
registerContentObserverForUserSync(uri, settingsObserver, userHandle)
}
@@ -215,7 +216,7 @@
userHandle: Int,
@WorkerThread registered: Runnable
) =
- CoroutineScope(backgroundDispatcher).launch {
+ CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-E")).launch {
registerContentObserverForUserSync(uri, settingsObserver, userHandle)
registered.run()
}
@@ -274,7 +275,7 @@
settingsObserver: ContentObserver,
userHandle: Int
) {
- CoroutineScope(backgroundDispatcher).launch {
+ CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-F")).launch {
registerContentObserverForUserSync(
getUriFor(name),
notifyForDescendants,
@@ -338,7 +339,7 @@
settingsObserver: ContentObserver,
userHandle: Int
) =
- CoroutineScope(backgroundDispatcher).launch {
+ CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-G")).launch {
registerContentObserverForUserSync(
uri,
notifyForDescendants,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 7385b82..e764015 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -22,6 +22,7 @@
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
+import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE;
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
@@ -449,7 +450,8 @@
@Override
public void onEntryRemoved(NotificationEntry entry,
@NotifCollection.CancellationReason int reason) {
- if (reason == REASON_APP_CANCEL || reason == REASON_APP_CANCEL_ALL) {
+ if (reason == REASON_APP_CANCEL || reason == REASON_APP_CANCEL_ALL
+ || reason == REASON_PACKAGE_BANNED) {
BubblesManager.this.onEntryRemoved(entry);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
index 103449b..ee8ce17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
@@ -26,6 +26,7 @@
import static org.mockito.Mockito.verify;
import android.app.UiModeManager;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
import android.platform.test.annotations.EnableFlags;
@@ -78,6 +79,12 @@
mNightMode = mUiModeManager.getNightMode();
mUiModeManager.setNightMode(MODE_NIGHT_YES);
+ // Programmatically update the resource's configuration to night mode to reduce flakiness
+ Configuration nightConfig = new Configuration(mContext.getResources().getConfiguration());
+ nightConfig.uiMode = Configuration.UI_MODE_NIGHT_YES;
+ mContext.getResources().updateConfiguration(nightConfig,
+ mContext.getResources().getDisplayMetrics(), null);
+
mSpyContext = spy(mContext);
doNothing().when(mSpyContext).startActivity(any());
@@ -101,6 +108,8 @@
@Test
public void insetsOnDarkTheme_menuOnLeft_matchInsets() {
+ // In dark theme, the inset is not 0 to avoid weird spacing issue between the menu and
+ // the edge of the screen.
mMenuView.onConfigurationChanged(/* newConfig= */ null);
final InstantInsetLayerDrawable insetLayerDrawable =
(InstantInsetLayerDrawable) mMenuView.getBackground();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index bbff539..6dc4b10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -18,10 +18,6 @@
import android.graphics.Point
import android.hardware.biometrics.BiometricSourceType
-import android.hardware.biometrics.ComponentInfoInternal
-import android.hardware.biometrics.SensorLocationInternal
-import android.hardware.biometrics.SensorProperties
-import android.hardware.fingerprint.FingerprintSensorProperties
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.testing.TestableLooper.RunWithLooper
import android.util.DisplayMetrics
@@ -47,7 +43,6 @@
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.leak.RotationUtils
import com.android.systemui.util.mockito.any
-import javax.inject.Provider
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.After
import org.junit.Assert.assertFalse
@@ -67,6 +62,8 @@
import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
+import javax.inject.Provider
+
@ExperimentalCoroutinesApi
@SmallTest
@@ -82,28 +79,35 @@
@Mock private lateinit var authController: AuthController
@Mock private lateinit var authRippleInteractor: AuthRippleInteractor
@Mock private lateinit var keyguardStateController: KeyguardStateController
- @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
- @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
- @Mock private lateinit var biometricUnlockController: BiometricUnlockController
- @Mock private lateinit var udfpsControllerProvider: Provider<UdfpsController>
- @Mock private lateinit var udfpsController: UdfpsController
- @Mock private lateinit var statusBarStateController: StatusBarStateController
- @Mock private lateinit var lightRevealScrim: LightRevealScrim
- @Mock private lateinit var fpSensorProp: FingerprintSensorPropertiesInternal
+ @Mock
+ private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
+ @Mock
+ private lateinit var notificationShadeWindowController: NotificationShadeWindowController
+ @Mock
+ private lateinit var biometricUnlockController: BiometricUnlockController
+ @Mock
+ private lateinit var udfpsControllerProvider: Provider<UdfpsController>
+ @Mock
+ private lateinit var udfpsController: UdfpsController
+ @Mock
+ private lateinit var statusBarStateController: StatusBarStateController
+ @Mock
+ private lateinit var lightRevealScrim: LightRevealScrim
+ @Mock
+ private lateinit var fpSensorProp: FingerprintSensorPropertiesInternal
private val facePropertyRepository = FakeFacePropertyRepository()
private val displayMetrics = DisplayMetrics()
@Captor
private lateinit var biometricUnlockListener:
- ArgumentCaptor<BiometricUnlockController.BiometricUnlockEventsListener>
+ ArgumentCaptor<BiometricUnlockController.BiometricUnlockEventsListener>
@Before
fun setUp() {
mSetFlagsRule.disableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
MockitoAnnotations.initMocks(this)
- staticMockSession =
- mockitoSession()
+ staticMockSession = mockitoSession()
.mockStatic(RotationUtils::class.java)
.strictness(Strictness.LENIENT)
.startMocking()
@@ -112,26 +116,25 @@
`when`(authController.udfpsProps).thenReturn(listOf(fpSensorProp))
`when`(udfpsControllerProvider.get()).thenReturn(udfpsController)
- controller =
- AuthRippleController(
- context,
- authController,
- configurationController,
- keyguardUpdateMonitor,
- keyguardStateController,
- wakefulnessLifecycle,
- commandRegistry,
- notificationShadeWindowController,
- udfpsControllerProvider,
- statusBarStateController,
- displayMetrics,
- KeyguardLogger(logcatLogBuffer(AuthRippleController.TAG)),
- biometricUnlockController,
- lightRevealScrim,
- authRippleInteractor,
- facePropertyRepository,
- rippleView,
- )
+ controller = AuthRippleController(
+ context,
+ authController,
+ configurationController,
+ keyguardUpdateMonitor,
+ keyguardStateController,
+ wakefulnessLifecycle,
+ commandRegistry,
+ notificationShadeWindowController,
+ udfpsControllerProvider,
+ statusBarStateController,
+ displayMetrics,
+ KeyguardLogger(logcatLogBuffer(AuthRippleController.TAG)),
+ biometricUnlockController,
+ lightRevealScrim,
+ authRippleInteractor,
+ facePropertyRepository,
+ rippleView,
+ )
controller.init()
}
@@ -147,18 +150,13 @@
`when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
controller.onViewAttached()
`when`(keyguardStateController.isShowing).thenReturn(true)
- `when`(
- keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
- eq(BiometricSourceType.FINGERPRINT)
- )
- )
- .thenReturn(true)
+ `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+ eq(BiometricSourceType.FINGERPRINT))).thenReturn(true)
// WHEN fingerprint authenticated
verify(biometricUnlockController).addListener(biometricUnlockListener.capture())
- biometricUnlockListener.value.onBiometricUnlockedWithKeyguardDismissal(
- BiometricSourceType.FINGERPRINT
- )
+ biometricUnlockListener.value
+ .onBiometricUnlockedWithKeyguardDismissal(BiometricSourceType.FINGERPRINT)
// THEN update sensor location and show ripple
verify(rippleView).setFingerprintSensorLocation(fpsLocation, 0f)
@@ -171,12 +169,8 @@
val fpsLocation = Point(5, 5)
`when`(authController.udfpsLocation).thenReturn(fpsLocation)
controller.onViewAttached()
- `when`(
- keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
- eq(BiometricSourceType.FINGERPRINT)
- )
- )
- .thenReturn(true)
+ `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+ eq(BiometricSourceType.FINGERPRINT))).thenReturn(true)
// WHEN keyguard is NOT showing & fingerprint authenticated
`when`(keyguardStateController.isShowing).thenReturn(false)
@@ -185,8 +179,7 @@
captor.value.onBiometricAuthenticated(
0 /* userId */,
BiometricSourceType.FINGERPRINT /* type */,
- false /* isStrongBiometric */
- )
+ false /* isStrongBiometric */)
// THEN no ripple
verify(rippleView, never()).startUnlockedRipple(any())
@@ -201,19 +194,14 @@
`when`(keyguardStateController.isShowing).thenReturn(true)
// WHEN unlocking with fingerprint is NOT allowed & fingerprint authenticated
- `when`(
- keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
- eq(BiometricSourceType.FINGERPRINT)
- )
- )
- .thenReturn(false)
+ `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+ eq(BiometricSourceType.FINGERPRINT))).thenReturn(false)
val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
verify(keyguardUpdateMonitor).registerCallback(captor.capture())
captor.value.onBiometricAuthenticated(
0 /* userId */,
BiometricSourceType.FINGERPRINT /* type */,
- false /* isStrongBiometric */
- )
+ false /* isStrongBiometric */)
// THEN no ripple
verify(rippleView, never()).startUnlockedRipple(any())
@@ -230,8 +218,7 @@
captor.value.onBiometricAuthenticated(
0 /* userId */,
BiometricSourceType.FACE /* type */,
- false /* isStrongBiometric */
- )
+ false /* isStrongBiometric */)
verify(rippleView, never()).startUnlockedRipple(any())
}
@@ -246,17 +233,18 @@
captor.value.onBiometricAuthenticated(
0 /* userId */,
BiometricSourceType.FINGERPRINT /* type */,
- false /* isStrongBiometric */
- )
+ false /* isStrongBiometric */)
verify(rippleView, never()).startUnlockedRipple(any())
}
@Test
fun registersAndDeregisters() {
controller.onViewAttached()
- val captor = ArgumentCaptor.forClass(KeyguardStateController.Callback::class.java)
+ val captor = ArgumentCaptor
+ .forClass(KeyguardStateController.Callback::class.java)
verify(keyguardStateController).addCallback(captor.capture())
- val captor2 = ArgumentCaptor.forClass(WakefulnessLifecycle.Observer::class.java)
+ val captor2 = ArgumentCaptor
+ .forClass(WakefulnessLifecycle.Observer::class.java)
verify(wakefulnessLifecycle).addObserver(captor2.capture())
controller.onViewDetached()
verify(keyguardStateController).removeCallback(any())
@@ -271,25 +259,17 @@
`when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
controller.onViewAttached()
`when`(keyguardStateController.isShowing).thenReturn(true)
- `when`(
- keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
- BiometricSourceType.FINGERPRINT
- )
- )
- .thenReturn(true)
+ `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+ BiometricSourceType.FINGERPRINT)).thenReturn(true)
`when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
controller.showUnlockRipple(BiometricSourceType.FINGERPRINT)
- assertTrue(
- "reveal didn't start on keyguardFadingAway",
- controller.startLightRevealScrimOnKeyguardFadingAway
- )
+ assertTrue("reveal didn't start on keyguardFadingAway",
+ controller.startLightRevealScrimOnKeyguardFadingAway)
`when`(keyguardStateController.isKeyguardFadingAway).thenReturn(true)
controller.onKeyguardFadingAwayChanged()
- assertFalse(
- "reveal triggers multiple times",
- controller.startLightRevealScrimOnKeyguardFadingAway
- )
+ assertFalse("reveal triggers multiple times",
+ controller.startLightRevealScrimOnKeyguardFadingAway)
}
@Test
@@ -302,27 +282,23 @@
`when`(keyguardStateController.isShowing).thenReturn(true)
`when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
`when`(authController.isUdfpsFingerDown).thenReturn(true)
- `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(eq(BiometricSourceType.FACE)))
- .thenReturn(true)
+ `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+ eq(BiometricSourceType.FACE))).thenReturn(true)
controller.showUnlockRipple(BiometricSourceType.FACE)
- assertTrue(
- "reveal didn't start on keyguardFadingAway",
- controller.startLightRevealScrimOnKeyguardFadingAway
- )
+ assertTrue("reveal didn't start on keyguardFadingAway",
+ controller.startLightRevealScrimOnKeyguardFadingAway)
`when`(keyguardStateController.isKeyguardFadingAway).thenReturn(true)
controller.onKeyguardFadingAwayChanged()
- assertFalse(
- "reveal triggers multiple times",
- controller.startLightRevealScrimOnKeyguardFadingAway
- )
+ assertFalse("reveal triggers multiple times",
+ controller.startLightRevealScrimOnKeyguardFadingAway)
}
@Test
fun testUpdateRippleColor() {
controller.onViewAttached()
- val captor =
- ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java)
+ val captor = ArgumentCaptor
+ .forClass(ConfigurationController.ConfigurationListener::class.java)
verify(configurationController).addCallback(captor.capture())
reset(rippleView)
@@ -357,40 +333,6 @@
}
@Test
- fun testUltrasonicUdfps_onFingerDown_runningForDeviceEntry_doNotShowDwellRipple() {
- // GIVEN UDFPS is ultrasonic
- `when`(authController.udfpsProps)
- .thenReturn(
- listOf(
- FingerprintSensorPropertiesInternal(
- 0 /* sensorId */,
- SensorProperties.STRENGTH_STRONG,
- 5 /* maxEnrollmentsPerUser */,
- listOf<ComponentInfoInternal>(),
- FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC,
- false /* halControlsIllumination */,
- true /* resetLockoutRequiresHardwareAuthToken */,
- listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT),
- )
- )
- )
-
- // GIVEN fingerprint detection is running on keyguard
- `when`(keyguardUpdateMonitor.isFingerprintDetectionRunning).thenReturn(true)
-
- // GIVEN view is already attached
- controller.onViewAttached()
- val captor = ArgumentCaptor.forClass(UdfpsController.Callback::class.java)
- verify(udfpsController).addCallback(captor.capture())
-
- // WHEN finger is down
- captor.value.onFingerDown()
-
- // THEN never show dwell ripple
- verify(rippleView, never()).startDwellRipple(false)
- }
-
- @Test
fun testUdfps_onFingerDown_notDeviceEntry_doesNotShowDwellRipple() {
// GIVEN fingerprint detection is NOT running on keyguard
`when`(keyguardUpdateMonitor.isFingerprintDetectionRunning).thenReturn(false)
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 d3e20c6..53f0800 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
@@ -73,6 +73,7 @@
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.media.InputMediaDevice;
+import com.android.settingslib.media.InputRouteManager;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.SysuiTestCase;
@@ -100,6 +101,7 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
@SmallTest
@@ -115,6 +117,10 @@
private static final String TEST_SONG = "test_song";
private static final String TEST_SESSION_ID = "test_session_id";
private static final String TEST_SESSION_NAME = "test_session_name";
+ private static final int MAX_VOLUME = 1;
+ private static final int CURRENT_VOLUME = 0;
+ private static final boolean VOLUME_FIXED_TRUE = true;
+
@Mock
private DialogTransitionAnimator mDialogTransitionAnimator;
@Mock
@@ -181,6 +187,7 @@
private String mPackageName = null;
private MediaSwitchingController mMediaSwitchingController;
private LocalMediaManager mLocalMediaManager;
+ private InputRouteManager mInputRouteManager;
private List<MediaController> mMediaControllers = new ArrayList<>();
private List<MediaDevice> mMediaDevices = new ArrayList<>();
private List<NearbyDevice> mNearbyDevices = new ArrayList<>();
@@ -228,6 +235,10 @@
mLocalMediaManager = spy(mMediaSwitchingController.mLocalMediaManager);
when(mLocalMediaManager.isPreferenceRouteListingExist()).thenReturn(false);
mMediaSwitchingController.mLocalMediaManager = mLocalMediaManager;
+ mMediaSwitchingController.mInputRouteManager =
+ new InputRouteManager(mContext, mAudioManager);
+ mInputRouteManager = spy(mMediaSwitchingController.mInputRouteManager);
+ mMediaSwitchingController.mInputRouteManager = mInputRouteManager;
MediaDescription.Builder builder = new MediaDescription.Builder();
builder.setTitle(TEST_SONG);
builder.setSubtitle(TEST_ARTIST);
@@ -545,9 +556,6 @@
// Output devices have changed.
mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
- final int MAX_VOLUME = 1;
- final int CURRENT_VOLUME = 0;
- final boolean IS_VOLUME_FIXED = true;
final MediaDevice mediaDevice3 =
InputMediaDevice.create(
mContext,
@@ -555,7 +563,7 @@
AudioDeviceInfo.TYPE_BUILTIN_MIC,
MAX_VOLUME,
CURRENT_VOLUME,
- IS_VOLUME_FIXED);
+ VOLUME_FIXED_TRUE);
final MediaDevice mediaDevice4 =
InputMediaDevice.create(
mContext,
@@ -563,7 +571,7 @@
AudioDeviceInfo.TYPE_WIRED_HEADSET,
MAX_VOLUME,
CURRENT_VOLUME,
- IS_VOLUME_FIXED);
+ VOLUME_FIXED_TRUE);
final List<MediaDevice> inputDevices = new ArrayList<>();
inputDevices.add(mediaDevice3);
inputDevices.add(mediaDevice4);
@@ -1312,4 +1320,23 @@
verify(mCallback).dismissDialog();
}
+
+ @EnableFlags(Flags.FLAG_ENABLE_AUDIO_INPUT_DEVICE_ROUTING_AND_VOLUME_CONTROL)
+ @Test
+ public void getSelectedMediaDevice() {
+ // Mock MediaDevice since none of the output media device constructor is publicly available
+ // outside of SettingsLib package.
+ final MediaDevice selectedOutputMediaDevice = mock(MediaDevice.class);
+ doReturn(Collections.singletonList(selectedOutputMediaDevice))
+ .when(mLocalMediaManager)
+ .getSelectedMediaDevice();
+
+ // Mock selected input media device.
+ final MediaDevice selectedInputMediaDevice = mock(MediaDevice.class);
+ doReturn(selectedInputMediaDevice).when(mInputRouteManager).getSelectedInputDevice();
+
+ List<MediaDevice> selectedMediaDevices = mMediaSwitchingController.getSelectedMediaDevice();
+ assertThat(selectedMediaDevices)
+ .containsExactly(selectedOutputMediaDevice, selectedInputMediaDevice);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
index b86d571..ab846f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
@@ -21,6 +21,7 @@
import android.hardware.input.KeyGestureEvent
import android.os.UserHandle
import android.os.UserManager
+import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
import android.view.KeyEvent
@@ -32,6 +33,8 @@
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.SysuiTestCase
+import com.android.systemui.notetask.NoteTaskEntryPoint.KEYBOARD_SHORTCUT
+import com.android.systemui.notetask.NoteTaskEntryPoint.TAIL_BUTTON
import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.util.concurrency.FakeExecutor
@@ -62,8 +65,7 @@
@RunWith(AndroidJUnit4::class)
internal class NoteTaskInitializerTest : SysuiTestCase() {
- @get:Rule
- val setFlagsRule = SetFlagsRule()
+ @get:Rule val setFlagsRule = SetFlagsRule()
@Mock lateinit var commandQueue: CommandQueue
@Mock lateinit var inputManager: InputManager
@@ -83,10 +85,7 @@
whenever(keyguardMonitor.isUserUnlocked(userTracker.userId)).thenReturn(true)
}
- private fun createUnderTest(
- isEnabled: Boolean,
- bubbles: Bubbles?,
- ): NoteTaskInitializer =
+ private fun createUnderTest(isEnabled: Boolean, bubbles: Bubbles?): NoteTaskInitializer =
NoteTaskInitializer(
controller = controller,
commandQueue = commandQueue,
@@ -104,7 +103,7 @@
code: Int,
downTime: Long = 0L,
eventTime: Long = 0L,
- metaState: Int = 0
+ metaState: Int = 0,
): KeyEvent = KeyEvent(downTime, eventTime, action, code, 0 /*repeat*/, metaState)
@Test
@@ -113,7 +112,6 @@
createUnderTest(isEnabled = true, bubbles = bubbles).initialize()
- verify(commandQueue).addCallback(any())
verify(roleManager).addOnRoleHoldersChangedListenerAsUser(any(), any(), any())
verify(controller).updateNoteTaskForCurrentUserAndManagedProfiles()
verify(keyguardMonitor).registerCallback(any())
@@ -125,7 +123,6 @@
createUnderTest(isEnabled = true, bubbles = bubbles).initialize()
- verify(commandQueue).addCallback(any())
verify(roleManager).addOnRoleHoldersChangedListenerAsUser(any(), any(), any())
verify(controller, never()).setNoteTaskShortcutEnabled(any(), any())
verify(keyguardMonitor).registerCallback(any())
@@ -165,12 +162,13 @@
}
@Test
+ @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
fun initialize_handleSystemKey() {
val expectedKeyEvent =
createKeyEvent(
ACTION_DOWN,
KEYCODE_N,
- metaState = KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON
+ metaState = KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON,
)
val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
underTest.initialize()
@@ -183,22 +181,66 @@
@Test
@EnableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
- fun initialize_handleKeyGestureEvent() {
- val gestureEvent = KeyGestureEvent.Builder()
- .setKeycodes(intArrayOf(KeyEvent.KEYCODE_N))
- .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON)
- .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES)
- .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- .build()
+ fun handlesShortcut_metaCtrlN() {
+ val gestureEvent =
+ KeyGestureEvent.Builder()
+ .setKeycodes(intArrayOf(KeyEvent.KEYCODE_N))
+ .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON)
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES)
+ .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ .build()
val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
underTest.initialize()
- val callback =
- withArgCaptor { verify(inputManager).registerKeyGestureEventHandler(capture()) }
+ val callback = withArgCaptor {
+ verify(inputManager).registerKeyGestureEventHandler(capture())
+ }
assertThat(callback.handleKeyGestureEvent(gestureEvent, null)).isTrue()
executor.runAllReady()
- verify(controller).showNoteTask(any())
+ verify(controller).showNoteTask(eq(KEYBOARD_SHORTCUT))
+ }
+
+ @Test
+ @EnableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
+ fun handlesShortcut_stylusTailButton() {
+ val gestureEvent =
+ KeyGestureEvent.Builder()
+ .setKeycodes(intArrayOf(KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL))
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES)
+ .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ .build()
+ val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
+ underTest.initialize()
+ val callback = withArgCaptor {
+ verify(inputManager).registerKeyGestureEventHandler(capture())
+ }
+
+ assertThat(callback.handleKeyGestureEvent(gestureEvent, null)).isTrue()
+
+ executor.runAllReady()
+ verify(controller).showNoteTask(eq(TAIL_BUTTON))
+ }
+
+ @Test
+ @EnableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
+ fun ignoresUnrelatedShortcuts() {
+ val gestureEvent =
+ KeyGestureEvent.Builder()
+ .setKeycodes(intArrayOf(KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL))
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+ .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ .build()
+ val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
+ underTest.initialize()
+ val callback = withArgCaptor {
+ verify(inputManager).registerKeyGestureEventHandler(capture())
+ }
+
+ assertThat(callback.handleKeyGestureEvent(gestureEvent, null)).isFalse()
+
+ executor.runAllReady()
+ verify(controller, never()).showNoteTask(any())
}
@Test
@@ -249,6 +291,7 @@
}
@Test
+ @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
fun tailButtonGestureDetection_singlePress_shouldShowNoteTaskOnUp() {
val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
underTest.initialize()
@@ -267,6 +310,7 @@
}
@Test
+ @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
fun tailButtonGestureDetection_doublePress_shouldNotShowNoteTaskTwice() {
val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
underTest.initialize()
@@ -289,6 +333,7 @@
}
@Test
+ @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
fun tailButtonGestureDetection_longPress_shouldNotShowNoteTask() {
val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
underTest.initialize()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt
index 755adc6..6423d25 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt
@@ -64,7 +64,6 @@
otherTiles = listOf(),
columns = 4,
modifier = Modifier.fillMaxSize(),
- onAddTile = { _, _ -> },
onRemoveTile = {},
onSetTiles = onSetTiles,
onResize = {},
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt
new file mode 100644
index 0000000..682ed92
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.ui.compose
+
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithContentDescription
+import androidx.compose.ui.test.performCustomAccessibilityActionWithLabel
+import androidx.compose.ui.text.AnnotatedString
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.qs.panels.shared.model.SizedTile
+import com.android.systemui.qs.panels.shared.model.SizedTileImpl
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.DefaultEditTileGrid
+import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.shared.model.TileCategory
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ResizingTest : SysuiTestCase() {
+ @get:Rule val composeRule = createComposeRule()
+
+ @Composable
+ private fun EditTileGridUnderTest(listState: EditTileListState, onResize: (TileSpec) -> Unit) {
+ DefaultEditTileGrid(
+ currentListState = listState,
+ otherTiles = listOf(),
+ columns = 4,
+ modifier = Modifier.fillMaxSize(),
+ onRemoveTile = {},
+ onSetTiles = {},
+ onResize = onResize,
+ )
+ }
+
+ @OptIn(ExperimentalTestApi::class)
+ @Test
+ fun resizedIcon_shouldBeLarge() {
+ var tiles by mutableStateOf(TestEditTiles)
+ val listState = EditTileListState(tiles, 4)
+ composeRule.setContent {
+ EditTileGridUnderTest(listState) { spec ->
+ tiles =
+ tiles.map {
+ if (it.tile.tileSpec == spec) {
+ toggleWidth(it)
+ } else {
+ it
+ }
+ }
+ }
+ }
+ composeRule.waitForIdle()
+
+ composeRule
+ .onNodeWithContentDescription("tileA")
+ .performCustomAccessibilityActionWithLabel("Toggle size")
+
+ assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(2)
+ }
+
+ @OptIn(ExperimentalTestApi::class)
+ @Test
+ fun resizedLarge_shouldBeIcon() {
+ var tiles by mutableStateOf(TestEditTiles)
+ val listState = EditTileListState(tiles, 4)
+ composeRule.setContent {
+ EditTileGridUnderTest(listState) { spec ->
+ tiles =
+ tiles.map {
+ if (it.tile.tileSpec == spec) {
+ toggleWidth(it)
+ } else {
+ it
+ }
+ }
+ }
+ }
+ composeRule.waitForIdle()
+
+ composeRule
+ .onNodeWithContentDescription("tileD_large")
+ .performCustomAccessibilityActionWithLabel("Toggle size")
+
+ assertThat(tiles.find { it.tile.tileSpec.spec == "tileD_large" }?.width).isEqualTo(1)
+ }
+
+ companion object {
+ private fun toggleWidth(tile: SizedTile<EditTileViewModel>): SizedTile<EditTileViewModel> {
+ return SizedTileImpl(tile.tile, width = if (tile.isIcon) 2 else 1)
+ }
+
+ private fun createEditTile(tileSpec: String): SizedTile<EditTileViewModel> {
+ return SizedTileImpl(
+ EditTileViewModel(
+ tileSpec = TileSpec.create(tileSpec),
+ icon =
+ Icon.Resource(
+ android.R.drawable.star_on,
+ ContentDescription.Loaded(tileSpec),
+ ),
+ label = AnnotatedString(tileSpec),
+ appName = null,
+ isCurrent = true,
+ availableEditActions = emptySet(),
+ category = TileCategory.UNKNOWN,
+ ),
+ getWidth(tileSpec),
+ )
+ }
+
+ private fun getWidth(tileSpec: String): Int {
+ return if (tileSpec.endsWith("large")) {
+ 2
+ } else {
+ 1
+ }
+ }
+
+ private val TestEditTiles =
+ listOf(
+ createEditTile("tileA"),
+ createEditTile("tileB"),
+ createEditTile("tileC"),
+ createEditTile("tileD_large"),
+ createEditTile("tileE"),
+ )
+ }
+}
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 c0444fe..b4a0f23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -118,7 +118,7 @@
override fun create(
lifecycleOwner: LifecycleOwner,
touchHandlers: Set<TouchHandler>,
- loggingName: String
+ loggingName: String,
): AmbientTouchComponent =
object : AmbientTouchComponent {
override fun getTouchMonitor(): TouchMonitor = touchMonitor
@@ -141,7 +141,7 @@
kosmos.notificationStackScrollLayoutController,
kosmos.keyguardMediaController,
kosmos.lockscreenSmartspaceController,
- logcatLogBuffer("GlanceableHubContainerControllerTest")
+ logcatLogBuffer("GlanceableHubContainerControllerTest"),
)
}
testableLooper = TestableLooper.get(this)
@@ -150,7 +150,7 @@
overrideResource(R.dimen.communal_top_edge_swipe_region_height, TOP_SWIPE_REGION_WIDTH)
overrideResource(
R.dimen.communal_bottom_edge_swipe_region_height,
- BOTTOM_SWIPE_REGION_WIDTH
+ BOTTOM_SWIPE_REGION_WIDTH,
)
// Make communal available so that communalInteractor.desiredScene accurately reflects
@@ -188,7 +188,7 @@
kosmos.notificationStackScrollLayoutController,
kosmos.keyguardMediaController,
kosmos.lockscreenSmartspaceController,
- logcatLogBuffer("GlanceableHubContainerControllerTest")
+ logcatLogBuffer("GlanceableHubContainerControllerTest"),
)
// First call succeeds.
@@ -217,7 +217,7 @@
kosmos.notificationStackScrollLayoutController,
kosmos.keyguardMediaController,
kosmos.lockscreenSmartspaceController,
- logcatLogBuffer("GlanceableHubContainerControllerTest")
+ logcatLogBuffer("GlanceableHubContainerControllerTest"),
)
assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.INITIALIZED)
@@ -241,7 +241,7 @@
kosmos.notificationStackScrollLayoutController,
kosmos.keyguardMediaController,
kosmos.lockscreenSmartspaceController,
- logcatLogBuffer("GlanceableHubContainerControllerTest")
+ logcatLogBuffer("GlanceableHubContainerControllerTest"),
)
// Only initView without attaching a view as we don't want the flows to start collecting
@@ -342,7 +342,7 @@
from = KeyguardState.GONE,
to = KeyguardState.GLANCEABLE_HUB,
value = 1.0f,
- transitionState = TransitionState.RUNNING
+ transitionState = TransitionState.RUNNING,
)
)
testableLooper.processAllMessages()
@@ -449,7 +449,6 @@
fun gestureExclusionZone_setAfterInit() =
with(kosmos) {
testScope.runTest {
- whenever(containerView.layoutDirection).thenReturn(View.LAYOUT_DIRECTION_LTR)
goToScene(CommunalScenes.Communal)
assertThat(containerView.systemGestureExclusionRects)
@@ -458,13 +457,7 @@
/* left= */ 0,
/* top= */ TOP_SWIPE_REGION_WIDTH,
/* right= */ CONTAINER_WIDTH,
- /* bottom= */ CONTAINER_HEIGHT - BOTTOM_SWIPE_REGION_WIDTH
- ),
- Rect(
- /* left= */ 0,
- /* top= */ 0,
- /* right= */ 0,
- /* bottom= */ CONTAINER_HEIGHT
+ /* bottom= */ CONTAINER_HEIGHT - BOTTOM_SWIPE_REGION_WIDTH,
)
)
}
@@ -475,67 +468,14 @@
fun gestureExclusionZone_setAfterInit_fullSwipe() =
with(kosmos) {
testScope.runTest {
- whenever(containerView.layoutDirection).thenReturn(View.LAYOUT_DIRECTION_LTR)
goToScene(CommunalScenes.Communal)
- assertThat(containerView.systemGestureExclusionRects)
- .containsExactly(
- Rect(
- /* left= */ 0,
- /* top= */ 0,
- /* right= */ 0,
- /* bottom= */ CONTAINER_HEIGHT
- )
- )
+ assertThat(containerView.systemGestureExclusionRects).isEmpty()
}
}
@Test
@DisableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX)
- fun gestureExclusionZone_setAfterInit_rtl() =
- with(kosmos) {
- testScope.runTest {
- whenever(containerView.layoutDirection).thenReturn(View.LAYOUT_DIRECTION_RTL)
- goToScene(CommunalScenes.Communal)
-
- assertThat(containerView.systemGestureExclusionRects)
- .containsExactly(
- Rect(
- /* left= */ 0,
- /* top= */ TOP_SWIPE_REGION_WIDTH,
- /* right= */ CONTAINER_WIDTH,
- /* bottom= */ CONTAINER_HEIGHT - BOTTOM_SWIPE_REGION_WIDTH
- ),
- Rect(
- /* left= */ 0,
- /* top= */ 0,
- /* right= */ CONTAINER_WIDTH,
- /* bottom= */ CONTAINER_HEIGHT
- )
- )
- }
- }
-
- @EnableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX)
- fun gestureExclusionZone_setAfterInit_rtl_fullSwipe() =
- with(kosmos) {
- testScope.runTest {
- whenever(containerView.layoutDirection).thenReturn(View.LAYOUT_DIRECTION_RTL)
- goToScene(CommunalScenes.Communal)
-
- assertThat(containerView.systemGestureExclusionRects)
- .containsExactly(
- Rect(
- /* left= */ 0,
- /* top= */ 0,
- /* right= */ CONTAINER_WIDTH,
- /* bottom= */ CONTAINER_HEIGHT
- )
- )
- }
- }
-
- @Test
fun gestureExclusionZone_unsetWhenShadeOpen() =
with(kosmos) {
testScope.runTest {
@@ -554,6 +494,7 @@
}
@Test
+ @DisableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX)
fun gestureExclusionZone_unsetWhenBouncerOpen() =
with(kosmos) {
testScope.runTest {
@@ -572,6 +513,7 @@
}
@Test
+ @DisableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX)
fun gestureExclusionZone_unsetWhenHubClosed() =
with(kosmos) {
testScope.runTest {
@@ -597,7 +539,7 @@
whenever(
notificationStackScrollLayoutController.isBelowLastNotification(
any(),
- any()
+ any(),
)
)
.thenReturn(false)
@@ -675,7 +617,7 @@
from = KeyguardState.GONE,
to = KeyguardState.GLANCEABLE_HUB,
value = 1.0f,
- transitionState = TransitionState.RUNNING
+ transitionState = TransitionState.RUNNING,
)
)
testableLooper.processAllMessages()
@@ -696,7 +638,7 @@
whenever(
notificationStackScrollLayoutController.isBelowLastNotification(
any(),
- any()
+ any(),
)
)
.thenReturn(true)
@@ -728,7 +670,7 @@
whenever(
notificationStackScrollLayoutController.isBelowLastNotification(
any(),
- any()
+ any(),
)
)
.thenReturn(true)
@@ -752,7 +694,7 @@
whenever(
notificationStackScrollLayoutController.isBelowLastNotification(
any(),
- any()
+ any(),
)
)
.thenReturn(true)
@@ -805,13 +747,13 @@
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.GLANCEABLE_HUB,
- kosmos.testScope
+ kosmos.testScope,
)
} else {
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.LOCKSCREEN,
- kosmos.testScope
+ kosmos.testScope,
)
}
testableLooper.processAllMessages()
@@ -836,7 +778,7 @@
MotionEvent.ACTION_DOWN,
CONTAINER_WIDTH.toFloat() / 2,
CONTAINER_HEIGHT.toFloat() / 2,
- 0
+ 0,
)
private val CANCEL_EVENT =
@@ -846,7 +788,7 @@
MotionEvent.ACTION_CANCEL,
CONTAINER_WIDTH.toFloat() / 2,
CONTAINER_HEIGHT.toFloat() / 2,
- 0
+ 0,
)
private val MOVE_EVENT =
@@ -856,7 +798,7 @@
MotionEvent.ACTION_MOVE,
CONTAINER_WIDTH.toFloat() / 2,
CONTAINER_HEIGHT.toFloat() / 2,
- 0
+ 0,
)
private val UP_EVENT =
@@ -866,7 +808,7 @@
MotionEvent.ACTION_UP,
CONTAINER_WIDTH.toFloat() / 2,
CONTAINER_HEIGHT.toFloat() / 2,
- 0
+ 0,
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/system/QuickStepContractTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/system/QuickStepContractTest.kt
new file mode 100644
index 0000000..6254fb1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/system/QuickStepContractTest.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.shared.system
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_COMMUNAL_HUB_SHOWING
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class QuickStepContractTest : SysuiTestCase() {
+ @Test
+ fun isBackGestureDisabled_hubShowing() {
+ val sysuiStateFlags = SYSUI_STATE_COMMUNAL_HUB_SHOWING
+
+ // Gestures are disabled while on the hub.
+ assertThat(
+ QuickStepContract.isBackGestureDisabled(sysuiStateFlags, /* forTrackpad= */ false)
+ )
+ .isTrue()
+ }
+
+ @Test
+ fun isBackGestureDisabled_hubAndShadeShowing() {
+ val sysuiStateFlags =
+ SYSUI_STATE_COMMUNAL_HUB_SHOWING and SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE
+
+ // Gestures are enabled because the shade shows over the hub.
+ assertThat(
+ QuickStepContract.isBackGestureDisabled(sysuiStateFlags, /* forTrackpad= */ false)
+ )
+ .isFalse()
+ }
+
+ @Test
+ fun isBackGestureDisabled_hubAndBouncerShowing() {
+ val sysuiStateFlags = SYSUI_STATE_COMMUNAL_HUB_SHOWING and SYSUI_STATE_BOUNCER_SHOWING
+
+ // Gestures are enabled because the bouncer shows over the hub.
+ assertThat(
+ QuickStepContract.isBackGestureDisabled(sysuiStateFlags, /* forTrackpad= */ false)
+ )
+ .isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
index d2dfc92..907c684 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
@@ -17,16 +17,19 @@
import android.app.StatusBarManager.DISABLE2_NONE
import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
+import android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS
import android.app.StatusBarManager.DISABLE_CLOCK
import android.app.StatusBarManager.DISABLE_NONE
import android.app.StatusBarManager.DISABLE_NOTIFICATION_ALERTS
+import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
+import android.app.StatusBarManager.DISABLE_SYSTEM_INFO
import android.content.res.Configuration
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.res.R
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
@@ -82,7 +85,7 @@
@Test
fun disableFlags_initialValue_none() {
assertThat(underTest.disableFlags.value)
- .isEqualTo(DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE))
+ .isEqualTo(DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE, animate = false))
}
@Test
@@ -182,12 +185,7 @@
fun disableFlags_quickSettingsDisabled_quickSettingsEnabledFalse() =
testScope.runTest {
getCommandQueueCallback()
- .disable(
- DISPLAY_ID,
- DISABLE_NONE,
- DISABLE2_QUICK_SETTINGS,
- /* animate= */ false,
- )
+ .disable(DISPLAY_ID, DISABLE_NONE, DISABLE2_QUICK_SETTINGS, /* animate= */ false)
assertThat(underTest.disableFlags.value.isQuickSettingsEnabled()).isFalse()
}
@@ -217,21 +215,84 @@
configuration.orientation = Configuration.ORIENTATION_LANDSCAPE
mContext.orCreateTestableResources.addOverride(
R.bool.config_use_split_notification_shade,
- /* value= */ false
+ /* value= */ false,
)
remoteInputQuickSettingsDisabler.setRemoteInputActive(true)
remoteInputQuickSettingsDisabler.onConfigChanged(configuration)
getCommandQueueCallback()
+ .disable(DISPLAY_ID, DISABLE_NONE, DISABLE2_NONE, /* animate= */ false)
+
+ // THEN quick settings is disabled (even if the disable flags don't say so)
+ assertThat(underTest.disableFlags.value.isQuickSettingsEnabled()).isFalse()
+ }
+
+ @Test
+ fun disableFlags_clockDisabled() =
+ testScope.runTest {
+ getCommandQueueCallback()
+ .disable(DISPLAY_ID, DISABLE_CLOCK, DISABLE2_NONE, /* animate= */ false)
+
+ assertThat(underTest.disableFlags.value.isClockEnabled).isFalse()
+ }
+
+ @Test
+ fun disableFlags_clockEnabled() =
+ testScope.runTest {
+ getCommandQueueCallback()
+ .disable(DISPLAY_ID, DISABLE_NONE, DISABLE2_NONE, /* animate= */ false)
+
+ assertThat(underTest.disableFlags.value.isClockEnabled).isTrue()
+ }
+
+ @Test
+ fun disableFlags_notificationIconsDisabled() =
+ testScope.runTest {
+ getCommandQueueCallback()
.disable(
DISPLAY_ID,
- DISABLE_NONE,
+ DISABLE_NOTIFICATION_ICONS,
DISABLE2_NONE,
/* animate= */ false,
)
- // THEN quick settings is disabled (even if the disable flags don't say so)
- assertThat(underTest.disableFlags.value.isQuickSettingsEnabled()).isFalse()
+ assertThat(underTest.disableFlags.value.areNotificationIconsEnabled).isFalse()
+ }
+
+ @Test
+ fun disableFlags_notificationIconsEnabled() =
+ testScope.runTest {
+ getCommandQueueCallback()
+ .disable(DISPLAY_ID, DISABLE_NONE, DISABLE2_NONE, /* animate= */ false)
+
+ assertThat(underTest.disableFlags.value.areNotificationIconsEnabled).isTrue()
+ }
+
+ @Test
+ fun disableFlags_systemInfoDisabled_viaDisable1() =
+ testScope.runTest {
+ getCommandQueueCallback()
+ .disable(DISPLAY_ID, DISABLE_SYSTEM_INFO, DISABLE2_NONE, /* animate= */ false)
+
+ assertThat(underTest.disableFlags.value.isSystemInfoEnabled).isFalse()
+ }
+
+ @Test
+ fun disableFlags_systemInfoDisabled_viaDisable2() =
+ testScope.runTest {
+ getCommandQueueCallback()
+ .disable(DISPLAY_ID, DISABLE_NONE, DISABLE2_SYSTEM_ICONS, /* animate= */ false)
+
+ assertThat(underTest.disableFlags.value.isSystemInfoEnabled).isFalse()
+ }
+
+ @Test
+ fun disableFlags_systemInfoEnabled() =
+ testScope.runTest {
+ getCommandQueueCallback()
+ .disable(DISPLAY_ID, DISABLE_NONE, DISABLE2_NONE, /* animate= */ false)
+
+ assertThat(underTest.disableFlags.value.isSystemInfoEnabled).isTrue()
}
@Test
@@ -267,6 +328,34 @@
assertThat(underTest.disableFlags.value.isQuickSettingsEnabled()).isFalse()
}
+ @Test
+ fun disableFlags_animateFalse() =
+ testScope.runTest {
+ getCommandQueueCallback()
+ .disable(
+ DISPLAY_ID,
+ DISABLE_NOTIFICATION_ALERTS,
+ DISABLE2_NONE,
+ /* animate= */ false,
+ )
+
+ assertThat(underTest.disableFlags.value.animate).isFalse()
+ }
+
+ @Test
+ fun disableFlags_animateTrue() =
+ testScope.runTest {
+ getCommandQueueCallback()
+ .disable(
+ DISPLAY_ID,
+ DISABLE_NOTIFICATION_ALERTS,
+ DISABLE2_NONE,
+ /* animate= */ true,
+ )
+
+ assertThat(underTest.disableFlags.value.animate).isTrue()
+ }
+
private fun getCommandQueueCallback(): CommandQueue.Callbacks {
val callbackCaptor = argumentCaptor<CommandQueue.Callbacks>()
verify(commandQueue).addCallback(callbackCaptor.capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index af04309..c710c56f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -168,7 +168,7 @@
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
-import com.android.systemui.statusbar.core.StatusBarInitializer;
+import com.android.systemui.statusbar.core.StatusBarInitializerImpl;
import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -504,7 +504,7 @@
mock(FragmentService.class),
mLightBarController,
mAutoHideController,
- new StatusBarInitializer(
+ new StatusBarInitializerImpl(
mStatusBarWindowController,
mCollapsedStatusBarFragmentProvider,
emptySet()),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 135fab8..63a560f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -18,6 +18,7 @@
import static com.android.systemui.Flags.FLAG_STATUS_BAR_RON_CHIPS;
import static com.android.systemui.Flags.FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS;
+import static com.android.systemui.Flags.FLAG_STATUS_BAR_SIMPLE_FRAGMENT;
import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_CLOSED;
import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_OPEN;
@@ -157,6 +158,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void testDisableNone() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -167,6 +169,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void testDisableSystemInfo_systemAnimationIdle_doesHide() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -184,6 +187,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void testSystemStatusAnimation_startedDisabled_finishedWithAnimator_showsSystemInfo() {
// GIVEN the status bar hides the system info via disable flags, while there is no event
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -213,6 +217,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void testSystemStatusAnimation_systemInfoDisabled_staysInvisible() {
// GIVEN the status bar hides the system info via disable flags, while there is no event
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -228,8 +233,8 @@
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
}
-
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void testSystemStatusAnimation_notDisabled_animatesAlphaZero() {
// GIVEN the status bar is not disabled
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -245,6 +250,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void testSystemStatusAnimation_notDisabled_animatesBackToAlphaOne() {
// GIVEN the status bar is not disabled
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -268,6 +274,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void testDisableNotifications() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -285,6 +292,25 @@
}
@Test
+ @EnableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
+ public void testDisableNotifications_doesNothingWhenFlagEnabled() {
+ CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+ fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
+
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
+
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
+
+ fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
+
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
+ }
+
+ @Test
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void testDisableClock() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -302,7 +328,26 @@
}
@Test
+ @EnableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
+ public void testDisableClock_doesNothingWhenFlagEnabled() {
+ CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+ fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_CLOCK, 0, false);
+
+ assertEquals(View.VISIBLE, getClockView().getVisibility());
+
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ assertEquals(View.VISIBLE, getClockView().getVisibility());
+
+ fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_CLOCK, 0, false);
+
+ assertEquals(View.VISIBLE, getClockView().getVisibility());
+ }
+
+ @Test
@DisableSceneContainer
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void disable_shadeOpenAndShouldHide_everythingHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -320,6 +365,7 @@
@Test
@DisableSceneContainer
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void disable_shadeOpenButNotShouldHide_everythingShown() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -338,6 +384,7 @@
/** Regression test for b/279790651. */
@Test
@DisableSceneContainer
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void disable_shadeOpenAndShouldHide_thenShadeNotOpenAndDozingUpdate_everythingShown() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -365,6 +412,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void disable_notTransitioningToOccluded_everythingShown() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -380,6 +428,7 @@
@Test
@DisableSceneContainer
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void disable_isTransitioningToOccluded_everythingHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -395,6 +444,7 @@
@Test
@DisableSceneContainer
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void disable_wasTransitioningToOccluded_transitionFinished_everythingShown() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -425,7 +475,7 @@
}
@Test
- @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
public void disable_noOngoingCall_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -437,7 +487,7 @@
}
@Test
- @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
public void disable_hasOngoingCall_chipDisplayedAndNotificationIconsHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -450,7 +500,7 @@
}
@Test
- @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
public void disable_hasOngoingCallButNotificationIconsDisabled_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -463,7 +513,7 @@
}
@Test
- @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
public void disable_hasOngoingCallButAlsoHun_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -476,7 +526,7 @@
}
@Test
- @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
public void disable_ongoingCallEnded_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -500,7 +550,7 @@
}
@Test
- @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
public void disable_hasOngoingCall_hidesNotifsWithoutAnimation() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// Enable animations for testing so that we can verify we still aren't animating
@@ -517,7 +567,7 @@
}
@Test
- @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
public void screenSharingChipsDisabled_ignoresNewCallback() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -551,6 +601,7 @@
@Test
@EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void noOngoingActivity_chipHidden() {
resumeAndGetFragment();
@@ -568,6 +619,7 @@
@Test
@EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void hasPrimaryOngoingActivity_primaryChipDisplayedAndNotificationIconsHidden() {
resumeAndGetFragment();
@@ -581,8 +633,36 @@
}
@Test
+ @EnableFlags({
+ FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+ FLAG_STATUS_BAR_RON_CHIPS,
+ FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
+ public void hasPrimaryOngoingActivity_viewsUnchangedWhenSimpleFragmentFlagOn() {
+ resumeAndGetFragment();
+
+ assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
+
+ mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
+ /* hasPrimaryOngoingActivity= */ true,
+ /* hasSecondaryOngoingActivity= */ false,
+ /* shouldAnimate= */ false);
+
+ assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
+
+ mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
+ /* hasPrimaryOngoingActivity= */ false,
+ /* hasSecondaryOngoingActivity= */ false,
+ /* shouldAnimate= */ false);
+
+ assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
+ }
+
+ @Test
@EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
- @DisableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+ @DisableFlags({FLAG_STATUS_BAR_RON_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
public void hasSecondaryOngoingActivity_butRonsFlagOff_secondaryChipHidden() {
resumeAndGetFragment();
@@ -596,6 +676,7 @@
@Test
@EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_RON_CHIPS})
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void hasSecondaryOngoingActivity_flagOn_secondaryChipShownAndNotificationIconsHidden() {
resumeAndGetFragment();
@@ -610,7 +691,7 @@
@Test
@EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
- @DisableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+ @DisableFlags({FLAG_STATUS_BAR_RON_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
public void hasOngoingActivityButNotificationIconsDisabled_chipHidden_ronsFlagOff() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -627,6 +708,7 @@
@Test
@EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_RON_CHIPS})
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void hasOngoingActivitiesButNotificationIconsDisabled_chipsHidden_ronsFlagOn() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -644,7 +726,7 @@
@Test
@EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
- @DisableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+ @DisableFlags({FLAG_STATUS_BAR_RON_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
public void hasOngoingActivityButAlsoHun_chipHidden_ronsFlagOff() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -661,6 +743,7 @@
@Test
@EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_RON_CHIPS})
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void hasOngoingActivitiesButAlsoHun_chipsHidden_ronsFlagOn() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -678,7 +761,7 @@
@Test
@EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
- @DisableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+ @DisableFlags({FLAG_STATUS_BAR_RON_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
public void primaryOngoingActivityEnded_chipHidden_ronsFlagOff() {
resumeAndGetFragment();
@@ -701,6 +784,7 @@
@Test
@EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_RON_CHIPS})
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void primaryOngoingActivityEnded_chipHidden_ronsFlagOn() {
resumeAndGetFragment();
@@ -723,6 +807,7 @@
@Test
@EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_RON_CHIPS})
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void secondaryOngoingActivityEnded_chipHidden() {
resumeAndGetFragment();
@@ -745,7 +830,7 @@
@Test
@EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
- @DisableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+ @DisableFlags({FLAG_STATUS_BAR_RON_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
public void hasOngoingActivity_hidesNotifsWithoutAnimation_ronsFlagOff() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// Enable animations for testing so that we can verify we still aren't animating
@@ -764,6 +849,7 @@
@Test
@EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_RON_CHIPS})
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void hasOngoingActivity_hidesNotifsWithoutAnimation_ronsFlagOn() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// Enable animations for testing so that we can verify we still aren't animating
@@ -782,7 +868,7 @@
@Test
@EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
- @DisableFlags(FLAG_STATUS_BAR_RON_CHIPS)
+ @DisableFlags({FLAG_STATUS_BAR_RON_CHIPS, FLAG_STATUS_BAR_SIMPLE_FRAGMENT})
public void screenSharingChipsEnabled_ignoresOngoingCallController_ronsFlagOff() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -815,6 +901,7 @@
@Test
@EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, FLAG_STATUS_BAR_RON_CHIPS})
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void screenSharingChipsEnabled_ignoresOngoingCallController_ronsFlagOn() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -848,6 +935,7 @@
@Test
@EnableSceneContainer
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void isHomeStatusBarAllowedByScene_false_everythingHidden() {
resumeAndGetFragment();
@@ -861,6 +949,7 @@
@Test
@EnableSceneContainer
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void isHomeStatusBarAllowedByScene_true_everythingShown() {
resumeAndGetFragment();
@@ -874,6 +963,7 @@
@Test
@EnableSceneContainer
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void disable_isHomeStatusBarAllowedBySceneFalse_disableValuesIgnored() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -891,6 +981,7 @@
@Test
@EnableSceneContainer
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void disable_isHomeStatusBarAllowedBySceneTrue_disableValuesUsed() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -908,6 +999,7 @@
@Test
@DisableSceneContainer
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void isHomeStatusBarAllowedByScene_sceneContainerDisabled_valueNotUsed() {
resumeAndGetFragment();
@@ -921,6 +1013,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void disable_isDozing_clockAndSystemInfoVisible() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mStatusBarStateController.isDozing()).thenReturn(true);
@@ -932,6 +1025,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void disable_NotDozing_clockAndSystemInfoVisible() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mStatusBarStateController.isDozing()).thenReturn(false);
@@ -943,6 +1037,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void disable_headsUpShouldBeVisibleTrue_clockDisabled() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(true);
@@ -953,6 +1048,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void disable_headsUpShouldBeVisibleFalse_clockNotDisabled() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(false);
@@ -1006,6 +1102,7 @@
@Test
@DisableSceneContainer
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void testStatusBarIcons_hiddenThroughoutCameraLaunch() {
final CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -1028,6 +1125,7 @@
@Test
@DisableSceneContainer
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void testStatusBarIcons_hiddenThroughoutLockscreenToDreamTransition() {
final CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -1063,6 +1161,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
public void testStatusBarIcons_lockscreenToDreamTransitionButNotDreaming_iconsVisible() {
final CollapsedStatusBarFragment fragment = resumeAndGetFragment();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaControllerTest.kt
index 997c00c..c435d3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaControllerTest.kt
@@ -16,10 +16,12 @@
package com.android.systemui.statusbar.phone.fragment
+import android.platform.test.annotations.DisableFlags
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_STATUS_BAR_SIMPLE_FRAGMENT
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.AnimatorTestRule
import junit.framework.Assert.assertEquals
@@ -36,6 +38,7 @@
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
+@DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT)
class MultiSourceMinAlphaControllerTest : SysuiTestCase() {
private val view = View(context)
@@ -60,7 +63,7 @@
multiSourceMinAlphaController.animateToAlpha(
alpha = 0.5f,
sourceId = TEST_SOURCE_1,
- duration = TEST_ANIMATION_DURATION
+ duration = TEST_ANIMATION_DURATION,
)
animatorTestRule.advanceTimeBy(TEST_ANIMATION_DURATION)
assertEquals(0.5f, view.alpha)
@@ -71,7 +74,7 @@
multiSourceMinAlphaController.animateToAlpha(
alpha = 0.5f,
sourceId = TEST_SOURCE_1,
- duration = TEST_ANIMATION_DURATION
+ duration = TEST_ANIMATION_DURATION,
)
multiSourceMinAlphaController.setAlpha(alpha = 0.7f, sourceId = TEST_SOURCE_2)
multiSourceMinAlphaController.reset()
@@ -94,7 +97,7 @@
multiSourceMinAlphaController.animateToAlpha(
alpha = 0f,
sourceId = TEST_SOURCE_1,
- duration = TEST_ANIMATION_DURATION
+ duration = TEST_ANIMATION_DURATION,
)
animatorTestRule.advanceTimeBy(TEST_ANIMATION_DURATION / 2)
multiSourceMinAlphaController.setAlpha(alpha = 1f, sourceId = TEST_SOURCE_1)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
new file mode 100644
index 0000000..5036e77
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared.domain.interactor
+
+import android.app.StatusBarManager.DISABLE2_NONE
+import android.app.StatusBarManager.DISABLE_CLOCK
+import android.app.StatusBarManager.DISABLE_NONE
+import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
+import android.app.StatusBarManager.DISABLE_SYSTEM_INFO
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.test.runTest
+
+@SmallTest
+class CollapsedStatusBarInteractorTest : SysuiTestCase() {
+ val kosmos = testKosmos()
+ val testScope = kosmos.testScope
+ val disableFlagsRepo = kosmos.fakeDisableFlagsRepository
+
+ val underTest = kosmos.collapsedStatusBarInteractor
+
+ @Test
+ fun visibilityViaDisableFlags_allDisabled() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.visibilityViaDisableFlags)
+
+ disableFlagsRepo.disableFlags.value =
+ DisableFlagsModel(
+ DISABLE_CLOCK or DISABLE_NOTIFICATION_ICONS or DISABLE_SYSTEM_INFO,
+ DISABLE2_NONE,
+ animate = false,
+ )
+
+ assertThat(latest!!.isClockAllowed).isFalse()
+ assertThat(latest!!.areNotificationIconsAllowed).isFalse()
+ assertThat(latest!!.isSystemInfoAllowed).isFalse()
+ }
+
+ @Test
+ fun visibilityViaDisableFlags_allEnabled() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.visibilityViaDisableFlags)
+
+ disableFlagsRepo.disableFlags.value =
+ DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE, animate = false)
+
+ assertThat(latest!!.isClockAllowed).isTrue()
+ assertThat(latest!!.areNotificationIconsAllowed).isTrue()
+ assertThat(latest!!.isSystemInfoAllowed).isTrue()
+ }
+
+ @Test
+ fun visibilityViaDisableFlags_animateFalse() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.visibilityViaDisableFlags)
+
+ disableFlagsRepo.disableFlags.value =
+ DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE, animate = false)
+
+ assertThat(latest!!.animate).isFalse()
+ }
+
+ @Test
+ fun visibilityViaDisableFlags_animateTrue() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.visibilityViaDisableFlags)
+
+ disableFlagsRepo.disableFlags.value =
+ DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE, animate = true)
+
+ assertThat(latest!!.animate).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
index 7ae6ea5..bd85780 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
@@ -16,21 +16,27 @@
package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
+import android.app.StatusBarManager.DISABLE2_NONE
+import android.app.StatusBarManager.DISABLE_CLOCK
+import android.app.StatusBarManager.DISABLE_NONE
+import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
+import android.app.StatusBarManager.DISABLE_SYSTEM_INFO
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
+import android.view.View
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.coroutines.collectValues
+import com.android.systemui.flags.DisableSceneContainer
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository
-import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
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.kosmos.Kosmos
-import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testCase
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
@@ -38,27 +44,25 @@
import com.android.systemui.mediaprojection.data.model.MediaProjectionState
import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
import com.android.systemui.scene.data.repository.sceneContainerRepository
-import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor
-import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
+import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.NORMAL_PACKAGE
import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.setUpPackageManagerForMediaProjection
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsScreenRecordChip
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsShareToAppChip
-import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
import com.android.systemui.statusbar.data.model.StatusBarMode
import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository.Companion.DISPLAY_ID
import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository
+import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
-import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
-import com.android.systemui.statusbar.phone.domain.interactor.lightsOutInteractor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.emptyFlow
@@ -83,21 +87,15 @@
private val statusBarModeRepository = kosmos.fakeStatusBarModeRepository
private val activeNotificationListRepository = kosmos.activeNotificationListRepository
private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+ private val disableFlagsRepository = kosmos.fakeDisableFlagsRepository
- private val underTest =
- CollapsedStatusBarViewModelImpl(
- kosmos.lightsOutInteractor,
- kosmos.activeNotificationsInteractor,
- kosmos.keyguardTransitionInteractor,
- kosmos.sceneInteractor,
- kosmos.sceneContainerOcclusionInteractor,
- kosmos.ongoingActivityChipsViewModel,
- kosmos.applicationCoroutineScope,
- )
+ private lateinit var underTest: CollapsedStatusBarViewModel
@Before
fun setUp() {
setUpPackageManagerForMediaProjection(kosmos)
+ // Initialize here because some flags are checked when this class is constructed
+ underTest = kosmos.collapsedStatusBarViewModel
}
@Test
@@ -495,14 +493,272 @@
assertThat(latest).isTrue()
}
+ @Test
+ fun isClockVisible_allowedByDisableFlags_visible() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isClockVisible)
+ transitionKeyguardToGone()
+
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
+
+ assertThat(latest!!.visibility).isEqualTo(View.VISIBLE)
+ }
+
+ @Test
+ fun isClockVisible_notAllowedByDisableFlags_gone() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isClockVisible)
+ transitionKeyguardToGone()
+
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(DISABLE_CLOCK, DISABLE2_NONE)
+
+ assertThat(latest!!.visibility).isEqualTo(View.GONE)
+ }
+
+ @Test
+ fun isNotificationIconContainerVisible_allowedByDisableFlags_visible() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isNotificationIconContainerVisible)
+ transitionKeyguardToGone()
+
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
+
+ assertThat(latest!!.visibility).isEqualTo(View.VISIBLE)
+ }
+
+ @Test
+ fun isNotificationIconContainerVisible_notAllowedByDisableFlags_gone() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isNotificationIconContainerVisible)
+ transitionKeyguardToGone()
+
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(DISABLE_NOTIFICATION_ICONS, DISABLE2_NONE)
+
+ assertThat(latest!!.visibility).isEqualTo(View.GONE)
+ }
+
+ @Test
+ fun isSystemInfoVisible_allowedByDisableFlags_visible() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isSystemInfoVisible)
+ transitionKeyguardToGone()
+
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
+
+ assertThat(latest!!.visibility).isEqualTo(View.VISIBLE)
+ }
+
+ @Test
+ fun isSystemInfoVisible_notAllowedByDisableFlags_gone() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isSystemInfoVisible)
+ transitionKeyguardToGone()
+
+ disableFlagsRepository.disableFlags.value =
+ DisableFlagsModel(DISABLE_SYSTEM_INFO, DISABLE2_NONE)
+
+ assertThat(latest!!.visibility).isEqualTo(View.GONE)
+ }
+
+ @Test
+ @DisableSceneContainer
+ fun lockscreenVisible_sceneFlagOff_noStatusBarViewsShown() =
+ testScope.runTest {
+ val clockVisible by collectLastValue(underTest.isClockVisible)
+ val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
+ val systemInfoVisible by collectLastValue(underTest.isSystemInfoVisible)
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.GONE,
+ to = KeyguardState.LOCKSCREEN,
+ testScope = this,
+ )
+
+ assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+ assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
+ assertThat(systemInfoVisible!!.visibility).isEqualTo(View.GONE)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun lockscreenVisible_sceneFlagOn_noStatusBarViewsShown() =
+ testScope.runTest {
+ val clockVisible by collectLastValue(underTest.isClockVisible)
+ val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
+ val systemInfoVisible by collectLastValue(underTest.isSystemInfoVisible)
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
+
+ assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+ assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
+ assertThat(systemInfoVisible!!.visibility).isEqualTo(View.GONE)
+ }
+
+ @Test
+ @DisableSceneContainer
+ fun bouncerVisible_sceneFlagOff_noStatusBarViewsShown() =
+ testScope.runTest {
+ val clockVisible by collectLastValue(underTest.isClockVisible)
+ val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
+ val systemInfoVisible by collectLastValue(underTest.isSystemInfoVisible)
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ testScope = this,
+ )
+
+ assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+ assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
+ assertThat(systemInfoVisible!!.visibility).isEqualTo(View.GONE)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun bouncerVisible_sceneFlagOn_noStatusBarViewsShown() =
+ testScope.runTest {
+ val clockVisible by collectLastValue(underTest.isClockVisible)
+ val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
+ val systemInfoVisible by collectLastValue(underTest.isSystemInfoVisible)
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Bouncer)
+
+ assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+ assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
+ assertThat(systemInfoVisible!!.visibility).isEqualTo(View.GONE)
+ }
+
+ @Test
+ @DisableSceneContainer
+ fun keyguardIsOccluded_sceneFlagOff_statusBarViewsShown() =
+ testScope.runTest {
+ val clockVisible by collectLastValue(underTest.isClockVisible)
+ val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
+ val systemInfoVisible by collectLastValue(underTest.isSystemInfoVisible)
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.OCCLUDED,
+ testScope = this,
+ )
+
+ assertThat(clockVisible!!.visibility).isEqualTo(View.VISIBLE)
+ assertThat(notifIconsVisible!!.visibility).isEqualTo(View.VISIBLE)
+ assertThat(systemInfoVisible!!.visibility).isEqualTo(View.VISIBLE)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun keyguardIsOccluded_sceneFlagOn_statusBarViewsShown() =
+ testScope.runTest {
+ val clockVisible by collectLastValue(underTest.isClockVisible)
+ val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
+ val systemInfoVisible by collectLastValue(underTest.isSystemInfoVisible)
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
+ kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(true, taskInfo = null)
+
+ assertThat(clockVisible!!.visibility).isEqualTo(View.VISIBLE)
+ assertThat(notifIconsVisible!!.visibility).isEqualTo(View.VISIBLE)
+ assertThat(systemInfoVisible!!.visibility).isEqualTo(View.VISIBLE)
+ }
+
+ @Test
+ @DisableSceneContainer
+ fun keyguardNotShown_sceneFlagOff_statusBarViewsShown() =
+ testScope.runTest {
+ val clockVisible by collectLastValue(underTest.isClockVisible)
+ val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
+ val systemInfoVisible by collectLastValue(underTest.isSystemInfoVisible)
+
+ transitionKeyguardToGone()
+
+ assertThat(clockVisible!!.visibility).isEqualTo(View.VISIBLE)
+ assertThat(notifIconsVisible!!.visibility).isEqualTo(View.VISIBLE)
+ assertThat(systemInfoVisible!!.visibility).isEqualTo(View.VISIBLE)
+ }
+
+ @Test
+ @DisableSceneContainer
+ fun shadeNotShown_sceneFlagOff_statusBarViewsShown() =
+ testScope.runTest {
+ val clockVisible by collectLastValue(underTest.isClockVisible)
+ val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
+ val systemInfoVisible by collectLastValue(underTest.isSystemInfoVisible)
+ transitionKeyguardToGone()
+
+ kosmos.shadeTestUtil.setShadeExpansion(0f)
+
+ assertThat(clockVisible!!.visibility).isEqualTo(View.VISIBLE)
+ assertThat(notifIconsVisible!!.visibility).isEqualTo(View.VISIBLE)
+ assertThat(systemInfoVisible!!.visibility).isEqualTo(View.VISIBLE)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun keyguardNotShownAndShadeNotShown_sceneFlagOn_statusBarViewsShown() =
+ testScope.runTest {
+ val clockVisible by collectLastValue(underTest.isClockVisible)
+ val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
+ val systemInfoVisible by collectLastValue(underTest.isSystemInfoVisible)
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Gone)
+
+ assertThat(clockVisible!!.visibility).isEqualTo(View.VISIBLE)
+ assertThat(notifIconsVisible!!.visibility).isEqualTo(View.VISIBLE)
+ assertThat(systemInfoVisible!!.visibility).isEqualTo(View.VISIBLE)
+ }
+
+ @Test
+ @DisableSceneContainer
+ fun shadeShown_sceneFlagOff_noStatusBarViewsShown() =
+ testScope.runTest {
+ val clockVisible by collectLastValue(underTest.isClockVisible)
+ val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
+ val systemInfoVisible by collectLastValue(underTest.isSystemInfoVisible)
+ transitionKeyguardToGone()
+
+ kosmos.shadeTestUtil.setShadeExpansion(1f)
+
+ assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+ assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
+ assertThat(systemInfoVisible!!.visibility).isEqualTo(View.GONE)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun shadeShown_sceneFlagOn_noStatusBarViewsShown() =
+ testScope.runTest {
+ val clockVisible by collectLastValue(underTest.isClockVisible)
+ val notifIconsVisible by collectLastValue(underTest.isNotificationIconContainerVisible)
+ val systemInfoVisible by collectLastValue(underTest.isSystemInfoVisible)
+ transitionKeyguardToGone()
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Shade)
+
+ assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+ assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
+ assertThat(systemInfoVisible!!.visibility).isEqualTo(View.GONE)
+ }
+
private fun activeNotificationsStore(notifications: List<ActiveNotificationModel>) =
ActiveNotificationsStore.Builder()
.apply { notifications.forEach(::addIndividualNotif) }
.build()
private val testNotifications =
- listOf(
- activeNotificationModel(key = "notif1"),
- activeNotificationModel(key = "notif2"),
+ listOf(activeNotificationModel(key = "notif1"), activeNotificationModel(key = "notif2"))
+
+ private suspend fun transitionKeyguardToGone() {
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ testScope = testScope,
)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
index 4834d36..cc90c11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
+import android.view.View
import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import kotlinx.coroutines.flow.Flow
@@ -36,9 +37,29 @@
override val isHomeStatusBarAllowedByScene = MutableStateFlow(false)
- override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> = areNotificationLightsOut
+ override val isClockVisible =
+ MutableStateFlow(
+ CollapsedStatusBarViewModel.VisibilityModel(
+ visibility = View.GONE,
+ shouldAnimateChange = false,
+ )
+ )
- fun setNotificationLightsOut(lightsOut: Boolean) {
- areNotificationLightsOut.value = lightsOut
- }
+ override val isNotificationIconContainerVisible =
+ MutableStateFlow(
+ CollapsedStatusBarViewModel.VisibilityModel(
+ visibility = View.GONE,
+ shouldAnimateChange = false,
+ )
+ )
+
+ override val isSystemInfoVisible =
+ MutableStateFlow(
+ CollapsedStatusBarViewModel.VisibilityModel(
+ visibility = View.GONE,
+ shouldAnimateChange = false,
+ )
+ )
+
+ override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> = areNotificationLightsOut
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryTest.kt
new file mode 100644
index 0000000..38e04bb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryTest.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.window.data.repository
+
+import android.app.StatusBarManager.WINDOW_NAVIGATION_BAR
+import android.app.StatusBarManager.WINDOW_STATE_HIDDEN
+import android.app.StatusBarManager.WINDOW_STATE_HIDING
+import android.app.StatusBarManager.WINDOW_STATE_SHOWING
+import android.app.StatusBarManager.WINDOW_STATUS_BAR
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.commandQueue
+import com.android.systemui.statusbar.window.data.model.StatusBarWindowState
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.argumentCaptor
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class StatusBarWindowStateRepositoryTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val commandQueue = kosmos.commandQueue
+ private val underTest =
+ StatusBarWindowStateRepository(commandQueue, DISPLAY_ID, testScope.backgroundScope)
+
+ private val callback: CommandQueue.Callbacks
+ get() {
+ testScope.runCurrent()
+ val callbackCaptor = argumentCaptor<CommandQueue.Callbacks>()
+ verify(commandQueue).addCallback(callbackCaptor.capture())
+ return callbackCaptor.firstValue
+ }
+
+ @Test
+ fun windowState_notSameDisplayId_notUpdated() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.windowState)
+ assertThat(latest).isEqualTo(StatusBarWindowState.Hidden)
+
+ callback.setWindowState(DISPLAY_ID + 1, WINDOW_STATUS_BAR, WINDOW_STATE_SHOWING)
+
+ assertThat(latest).isEqualTo(StatusBarWindowState.Hidden)
+ }
+
+ @Test
+ fun windowState_notStatusBarWindow_notUpdated() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.windowState)
+ assertThat(latest).isEqualTo(StatusBarWindowState.Hidden)
+
+ callback.setWindowState(DISPLAY_ID, WINDOW_NAVIGATION_BAR, WINDOW_STATE_SHOWING)
+
+ assertThat(latest).isEqualTo(StatusBarWindowState.Hidden)
+ }
+
+ @Test
+ fun windowState_showing_updated() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.windowState)
+
+ callback.setWindowState(DISPLAY_ID, WINDOW_STATUS_BAR, WINDOW_STATE_SHOWING)
+
+ assertThat(latest).isEqualTo(StatusBarWindowState.Showing)
+ }
+
+ @Test
+ fun windowState_hiding_updated() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.windowState)
+
+ callback.setWindowState(DISPLAY_ID, WINDOW_STATUS_BAR, WINDOW_STATE_HIDING)
+
+ assertThat(latest).isEqualTo(StatusBarWindowState.Hiding)
+ }
+
+ @Test
+ fun windowState_hidden_updated() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.windowState)
+ callback.setWindowState(DISPLAY_ID, WINDOW_STATUS_BAR, WINDOW_STATE_SHOWING)
+ assertThat(latest).isEqualTo(StatusBarWindowState.Showing)
+
+ callback.setWindowState(DISPLAY_ID, WINDOW_STATUS_BAR, WINDOW_STATE_HIDDEN)
+
+ assertThat(latest).isEqualTo(StatusBarWindowState.Hidden)
+ }
+}
+
+private const val DISPLAY_ID = 10
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 3e7980d..0d39834 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -24,6 +24,7 @@
import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
+import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
import static androidx.test.ext.truth.content.IntentSubject.assertThat;
@@ -1100,6 +1101,18 @@
}
@Test
+ public void testNotifsBanned_entryListenerRemove() {
+ mEntryListener.onEntryAdded(mRow);
+ mBubbleController.updateBubble(mBubbleEntry);
+
+ assertTrue(mBubbleController.hasBubbles());
+
+ // Removes the notification
+ mEntryListener.onEntryRemoved(mRow, REASON_PACKAGE_BANNED);
+ assertFalse(mBubbleController.hasBubbles());
+ }
+
+ @Test
public void removeBubble_intercepted() {
mEntryListener.onEntryAdded(mRow);
mBubbleController.updateBubble(mBubbleEntry);
diff --git a/packages/SystemUI/tests/utils/src/android/hardware/input/FakeInputManager.kt b/packages/SystemUI/tests/utils/src/android/hardware/input/FakeInputManager.kt
index ee36cad..de4bbec 100644
--- a/packages/SystemUI/tests/utils/src/android/hardware/input/FakeInputManager.kt
+++ b/packages/SystemUI/tests/utils/src/android/hardware/input/FakeInputManager.kt
@@ -84,7 +84,7 @@
if (devices.containsKey(deviceId)) {
return
}
- addPhysicalKeyboard(deviceId, enabled)
+ addPhysicalKeyboard(deviceId, enabled = enabled)
}
fun registerInputDeviceListener(listener: InputDeviceListener) {
@@ -92,9 +92,15 @@
inputDeviceListener = listener
}
- fun addPhysicalKeyboard(id: Int, enabled: Boolean = true) {
+ fun addPhysicalKeyboard(
+ id: Int,
+ vendorId: Int = 0,
+ productId: Int = 0,
+ isFullKeyboard: Boolean = true,
+ enabled: Boolean = true
+ ) {
check(id > 0) { "Physical keyboard ids have to be > 0" }
- addKeyboard(id, enabled)
+ addKeyboard(id, vendorId, productId, isFullKeyboard, enabled)
}
fun removeKeysFromKeyboard(deviceId: Int, vararg keyCodes: Int) {
@@ -102,20 +108,38 @@
supportedKeyCodesByDeviceId[deviceId]!!.removeAll(keyCodes.asList())
}
- private fun addKeyboard(id: Int, enabled: Boolean = true) {
- devices[id] =
+ private fun addKeyboard(
+ id: Int,
+ vendorId: Int = 0,
+ productId: Int = 0,
+ isFullKeyboard: Boolean = true,
+ enabled: Boolean = true
+ ) {
+ val keyboardType =
+ if (isFullKeyboard) InputDevice.KEYBOARD_TYPE_ALPHABETIC
+ else InputDevice.KEYBOARD_TYPE_NON_ALPHABETIC
+ // VendorId and productId are set to 0 if not specified, which is the same as the default
+ // values used in InputDevice.Builder
+ val builder =
InputDevice.Builder()
.setId(id)
- .setKeyboardType(InputDevice.KEYBOARD_TYPE_ALPHABETIC)
+ .setVendorId(vendorId)
+ .setProductId(productId)
+ .setKeyboardType(keyboardType)
.setSources(InputDevice.SOURCE_KEYBOARD)
.setEnabled(enabled)
.setKeyCharacterMap(keyCharacterMap)
- .build()
+ devices[id] = builder.build()
+ inputDeviceListener?.onInputDeviceAdded(id)
supportedKeyCodesByDeviceId[id] = allKeyCodes.toMutableSet()
}
- fun addDevice(id: Int, sources: Int) {
- devices[id] = InputDevice.Builder().setId(id).setSources(sources).build()
+ fun addDevice(id: Int, sources: Int, isNotFound: Boolean = false) {
+ // there's not way of differentiate device connection vs registry in current implementation.
+ // If the device isNotFound, it means that we connect an unregistered device.
+ if (!isNotFound) {
+ devices[id] = InputDevice.Builder().setId(id).setSources(sources).build()
+ }
inputDeviceListener?.onInputDeviceAdded(id)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractorKosmos.kt
index 8124224..3d41362 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractorKosmos.kt
@@ -16,9 +16,11 @@
package com.android.systemui.communal.domain.interactor
+import android.service.dream.dreamManager
import com.android.systemui.common.usagestats.domain.interactor.usageStatsInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.plugins.activityStarter
import com.android.systemui.shared.system.taskStackChangeListeners
@@ -32,6 +34,8 @@
keyguardTransitionInteractor = keyguardTransitionInteractor,
taskStackChangeListeners = taskStackChangeListeners,
usageStatsInteractor = usageStatsInteractor,
+ dreamManager = dreamManager,
+ bgScope = applicationCoroutineScope,
logBuffer = logcatLogBuffer("WidgetTrampolineInteractor"),
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
index 574bbcd..e2b283b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
@@ -39,5 +39,6 @@
powerInteractor = powerInteractor,
alternateBouncerInteractor = alternateBouncerInteractor,
shadeInteractor = { shadeInteractor },
+ keyguardInteractor = { keyguardInteractor },
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractorKosmos.kt
index 6e650a3..77afa79 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractorKosmos.kt
@@ -21,6 +21,7 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.media.controls.data.repository.mediaFilterRepository
import com.android.systemui.media.controls.domain.pipeline.mediaDataProcessor
+import com.android.systemui.media.controls.shared.mediaLogger
import com.android.systemui.media.controls.util.mediaInstanceId
import com.android.systemui.media.mediaOutputDialogManager
import com.android.systemui.plugins.activityStarter
@@ -39,5 +40,6 @@
lockscreenUserManager = notificationLockscreenUserManager,
mediaOutputDialogManager = mediaOutputDialogManager,
broadcastDialogController = mockBroadcastDialogController,
+ mediaLogger = mediaLogger,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/factory/MediaControlInteractorFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/factory/MediaControlInteractorFactoryKosmos.kt
index e490b75..9ea660f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/factory/MediaControlInteractorFactoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/factory/MediaControlInteractorFactoryKosmos.kt
@@ -23,6 +23,7 @@
import com.android.systemui.media.controls.data.repository.mediaFilterRepository
import com.android.systemui.media.controls.domain.pipeline.interactor.MediaControlInteractor
import com.android.systemui.media.controls.domain.pipeline.mediaDataProcessor
+import com.android.systemui.media.controls.shared.mediaLogger
import com.android.systemui.media.mediaOutputDialogManager
import com.android.systemui.plugins.activityStarter
import com.android.systemui.statusbar.notificationLockscreenUserManager
@@ -42,6 +43,7 @@
lockscreenUserManager = notificationLockscreenUserManager,
mediaOutputDialogManager = mediaOutputDialogManager,
broadcastDialogController = mockBroadcastDialogController,
+ mediaLogger = mediaLogger,
)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/Warmable.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt
similarity index 62%
copy from libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/Warmable.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt
index 0df9bfa..385a813 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/Warmable.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.wm.shell.windowdecor.viewhost
-/**
- * An interface for an object that can be warmed up before it's needed.
- */
-interface Warmable {
- fun warmUp()
-}
+package com.android.systemui.statusbar.pipeline.shared.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+
+val Kosmos.collapsedStatusBarInteractor: CollapsedStatusBarInteractor by
+ Kosmos.Fixture { CollapsedStatusBarInteractor(fakeDisableFlagsRepository) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelKosmos.kt
new file mode 100644
index 0000000..1c7fd48
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelKosmos.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
+
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
+import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+import com.android.systemui.statusbar.phone.domain.interactor.lightsOutInteractor
+import com.android.systemui.statusbar.pipeline.shared.domain.interactor.collapsedStatusBarInteractor
+
+val Kosmos.collapsedStatusBarViewModel: CollapsedStatusBarViewModel by
+ Kosmos.Fixture {
+ CollapsedStatusBarViewModelImpl(
+ collapsedStatusBarInteractor,
+ lightsOutInteractor,
+ activeNotificationsInteractor,
+ keyguardTransitionInteractor,
+ sceneInteractor,
+ sceneContainerOcclusionInteractor,
+ shadeInteractor,
+ ongoingActivityChipsViewModel,
+ applicationCoroutineScope,
+ )
+ }
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index a100974..57b58d8 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -128,7 +128,11 @@
val currentDirection =
if (angle < lastHingeAngle) FOLD_UPDATE_START_CLOSING else FOLD_UPDATE_START_OPENING
- if (isTransitionInProgress && currentDirection != lastFoldUpdate) {
+ val changedDirectionWhileInTransition =
+ isTransitionInProgress && currentDirection != lastFoldUpdate
+ val unfoldedPastThresholdSinceLastTransition =
+ angle - lastHingeAngleBeforeTransition > HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES
+ if (changedDirectionWhileInTransition || unfoldedPastThresholdSinceLastTransition) {
lastHingeAngleBeforeTransition = lastHingeAngle
}
@@ -153,7 +157,7 @@
isOnLargeScreen // Avoids sending closing event when on small screen.
// Start event is sent regardless due to hall sensor.
) {
- notifyFoldUpdate(transitionUpdate, lastHingeAngle)
+ notifyFoldUpdate(transitionUpdate, angle)
}
if (isTransitionInProgress) {
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index 93cdde0..75d07bb 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -1037,14 +1037,12 @@
@Override
public void onCaptureFailed(int captureSequenceId, int reason) {
- if (Flags.concertMode()) {
- if (mCaptureCallback != null) {
- try {
- mCaptureCallback.onCaptureProcessFailed(captureSequenceId, reason);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to notify capture failure due to remote " +
- "exception!");
- }
+ if (mCaptureCallback != null) {
+ try {
+ mCaptureCallback.onCaptureProcessFailed(captureSequenceId, reason);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to notify capture failure due to remote " +
+ "exception!");
}
}
}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
index 2417262..90bb93d 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
@@ -16,12 +16,11 @@
package android.platform.test.ravenwood;
+import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_INST_RESOURCE_APK;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_RESOURCE_APK;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERSION_JAVA_SYSPROP;
-import static org.junit.Assert.fail;
-
import android.app.ActivityManager;
import android.app.Instrumentation;
import android.app.ResourcesManager;
@@ -211,23 +210,21 @@
var file = new File(RAVENWOOD_RESOURCE_APK);
return config.mState.loadResources(file.exists() ? file : null);
};
- // Set up test context's resources.
+
+ // Set up test context's (== instrumentation context's) resources.
// If the target package name == test package name, then we use the main resources.
- // Otherwise, we don't simulate loading resources from the test APK yet.
- // (we need to add `test_resource_apk` to `android_ravenwood_test`)
- final Supplier<Resources> testResourcesLoader;
+ final Supplier<Resources> instResourcesLoader;
if (isSelfInstrumenting) {
- testResourcesLoader = targetResourcesLoader;
+ instResourcesLoader = targetResourcesLoader;
} else {
- testResourcesLoader = () -> {
- fail("Cannot load resources from the test context (yet)."
- + " Use target context's resources instead.");
- return null; // unreachable.
+ instResourcesLoader = () -> {
+ var file = new File(RAVENWOOD_INST_RESOURCE_APK);
+ return config.mState.loadResources(file.exists() ? file : null);
};
}
- var testContext = new RavenwoodContext(
- config.mTestPackageName, main, testResourcesLoader);
+ var instContext = new RavenwoodContext(
+ config.mTestPackageName, main, instResourcesLoader);
var targetContext = new RavenwoodContext(
config.mTargetPackageName, main, targetResourcesLoader);
@@ -236,18 +233,18 @@
config.mTargetPackageName, main, targetResourcesLoader);
appContext.setApplicationContext(appContext);
if (isSelfInstrumenting) {
- testContext.setApplicationContext(appContext);
+ instContext.setApplicationContext(appContext);
targetContext.setApplicationContext(appContext);
} else {
// When instrumenting into another APK, the test context doesn't have an app context.
targetContext.setApplicationContext(appContext);
}
- config.mTestContext = testContext;
+ config.mInstContext = instContext;
config.mTargetContext = targetContext;
// Prepare other fields.
config.mInstrumentation = new Instrumentation();
- config.mInstrumentation.basicInit(config.mTestContext, config.mTargetContext);
+ config.mInstrumentation.basicInit(config.mInstContext, config.mTargetContext);
InstrumentationRegistry.registerInstance(config.mInstrumentation, Bundle.EMPTY);
RavenwoodSystemServer.init(config);
@@ -284,13 +281,13 @@
InstrumentationRegistry.registerInstance(null, Bundle.EMPTY);
config.mInstrumentation = null;
- if (config.mTestContext != null) {
- ((RavenwoodContext) config.mTestContext).cleanUp();
+ if (config.mInstContext != null) {
+ ((RavenwoodContext) config.mInstContext).cleanUp();
}
if (config.mTargetContext != null) {
((RavenwoodContext) config.mTargetContext).cleanUp();
}
- config.mTestContext = null;
+ config.mInstContext = null;
config.mTargetContext = null;
if (config.mProvideMainThread) {
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
index d4090e2..3946dd84 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
@@ -67,7 +67,7 @@
sStartedServices = new ArraySet<>();
sTimings = new TimingsTraceAndSlog();
- sServiceManager = new SystemServiceManager(config.mTestContext);
+ sServiceManager = new SystemServiceManager(config.mInstContext);
sServiceManager.setStartInfo(false,
SystemClock.elapsedRealtime(),
SystemClock.uptimeMillis());
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
index 4cb2ce1..5ba972d 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
@@ -167,6 +167,7 @@
return runner;
}
+ private final Class<?> mTestJavaClass;
private TestClass mTestClass = null;
private Runner mRealRunner = null;
private Description mDescription = null;
@@ -192,26 +193,29 @@
* Constructor.
*/
public RavenwoodAwareTestRunner(Class<?> testClass) {
+ mTestJavaClass = testClass;
try {
performGlobalInitialization();
+ /*
+ * If the class has @DisabledOnRavenwood, then we'll delegate to
+ * ClassSkippingTestRunner, which simply skips it.
+ *
+ * We need to do it before instantiating TestClass for b/367694651.
+ */
+ if (isOnRavenwood() && !RavenwoodAwareTestRunnerHook.shouldRunClassOnRavenwood(
+ testClass)) {
+ mRealRunner = new ClassSkippingTestRunner(testClass);
+ mDescription = mRealRunner.getDescription();
+ return;
+ }
+
mTestClass = new TestClass(testClass);
Log.v(TAG, "RavenwoodAwareTestRunner starting for " + testClass.getCanonicalName());
onRunnerInitializing();
- /*
- * If the class has @DisabledOnRavenwood, then we'll delegate to
- * ClassSkippingTestRunner, which simply skips it.
- */
- if (isOnRavenwood() && !RavenwoodAwareTestRunnerHook.shouldRunClassOnRavenwood(
- mTestClass.getJavaClass())) {
- mRealRunner = new ClassSkippingTestRunner(mTestClass);
- mDescription = mRealRunner.getDescription();
- return;
- }
-
// Find the real runner.
final Class<? extends Runner> realRunnerClass;
final InnerRunner innerRunnerAnnotation = mTestClass.getAnnotation(InnerRunner.class);
@@ -318,7 +322,7 @@
return;
}
- Log.v(TAG, "Starting " + mTestClass.getJavaClass().getCanonicalName());
+ Log.v(TAG, "Starting " + mTestJavaClass.getCanonicalName());
if (RAVENWOOD_VERBOSE_LOGGING) {
dumpDescription(getDescription());
}
@@ -444,14 +448,11 @@
* filter.
*/
private static class ClassSkippingTestRunner extends Runner implements Filterable {
- private final TestClass mTestClass;
private final Description mDescription;
private boolean mFilteredOut;
- ClassSkippingTestRunner(TestClass testClass) {
- mTestClass = testClass;
- mDescription = Description.createTestDescription(
- testClass.getJavaClass(), testClass.getJavaClass().getSimpleName());
+ ClassSkippingTestRunner(Class<?> testClass) {
+ mDescription = Description.createTestDescription(testClass, testClass.getSimpleName());
mFilteredOut = false;
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
index ea33aa6..446f819 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
@@ -74,7 +74,7 @@
final List<Class<?>> mServicesRequired = new ArrayList<>();
- volatile Context mTestContext;
+ volatile Context mInstContext;
volatile Context mTargetContext;
volatile Instrumentation mInstrumentation;
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index 984106b..4196d8e 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -216,7 +216,7 @@
*/
@Deprecated
public Context getContext() {
- return Objects.requireNonNull(mConfiguration.mTestContext,
+ return Objects.requireNonNull(mConfiguration.mInstContext,
"Context is only available during @Test execution");
}
diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java
index 96746c6..989bb6b 100644
--- a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java
+++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java
@@ -63,6 +63,8 @@
public static final String RAVENWOOD_SYSPROP = "ro.is_on_ravenwood";
public static final String RAVENWOOD_RESOURCE_APK = "ravenwood-res-apks/ravenwood-res.apk";
+ public static final String RAVENWOOD_INST_RESOURCE_APK =
+ "ravenwood-res-apks/ravenwood-inst-res.apk";
public static final String RAVENWOOD_EMPTY_RESOURCES_APK =
RAVENWOOD_RUNTIME_PATH + "ravenwood-data/ravenwood-empty-res.apk";
diff --git a/ravenwood/tests/bivalentinst/Android.bp b/ravenwood/tests/bivalentinst/Android.bp
index 38d1b299..41e45e5 100644
--- a/ravenwood/tests/bivalentinst/Android.bp
+++ b/ravenwood/tests/bivalentinst/Android.bp
@@ -27,8 +27,7 @@
"junit",
"truth",
],
- // TODO(b/366246777) uncomment it and the test.
- // resource_apk: "RavenwoodBivalentInstTest_self_inst_device",
+ resource_apk: "RavenwoodBivalentInstTest_self_inst_device",
auto_gen_config: true,
}
@@ -53,8 +52,8 @@
"junit",
"truth",
],
- // TODO(b/366246777) uncomment it and the test.
- // resource_apk: "RavenwoodBivalentInstTestTarget",
+ resource_apk: "RavenwoodBivalentInstTestTarget",
+ inst_resource_apk: "RavenwoodBivalentInstTest_nonself_inst_device",
auto_gen_config: true,
}
diff --git a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java
index 9f3ca6f..92d43d7 100644
--- a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java
+++ b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java
@@ -19,7 +19,6 @@
import android.app.Instrumentation;
import android.content.Context;
-import android.platform.test.annotations.DisabledOnRavenwood;
import android.platform.test.ravenwood.RavenwoodConfig;
import android.platform.test.ravenwood.RavenwoodConfig.Config;
@@ -97,7 +96,6 @@
}
@Test
- @DisabledOnRavenwood(reason = "b/366246777")
public void testTargetAppResource() {
assertThat(sTargetContext.getString(
com.android.ravenwood.bivalentinst_target_app.R.string.test_string_in_target))
@@ -105,8 +103,6 @@
}
@Test
- @DisabledOnRavenwood(
- reason = "Loading resources from non-self-instrumenting test APK isn't supported yet")
public void testTestAppResource() {
assertThat(sTestContext.getString(
com.android.ravenwood.bivalentinsttest_nonself_inst.R.string.test_string_in_test))
diff --git a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java
index fdff222..2f35923 100644
--- a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java
+++ b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java
@@ -19,7 +19,6 @@
import android.app.Instrumentation;
import android.content.Context;
-import android.platform.test.annotations.DisabledOnRavenwood;
import android.platform.test.ravenwood.RavenwoodConfig;
import android.platform.test.ravenwood.RavenwoodConfig.Config;
@@ -109,7 +108,6 @@
}
@Test
- @DisabledOnRavenwood(reason = "b/366246777")
public void testTargetAppResource() {
assertThat(sTargetContext.getString(
com.android.ravenwood.bivalentinsttest_self_inst.R.string.test_string_in_test))
@@ -117,7 +115,6 @@
}
@Test
- @DisabledOnRavenwood(reason = "b/366246777")
public void testTestAppResource() {
assertThat(sTestContext.getString(
com.android.ravenwood.bivalentinsttest_self_inst.R.string.test_string_in_test))
diff --git a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerCallbackTest.java b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerCallbackTest.java
index 6d8fb98..bd01313 100644
--- a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerCallbackTest.java
+++ b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerCallbackTest.java
@@ -17,12 +17,14 @@
import static org.junit.Assume.assumeTrue;
+import android.platform.test.annotations.DisabledOnRavenwood;
import android.platform.test.annotations.NoRavenizer;
import android.platform.test.ravenwood.RavenwoodAwareTestRunner;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.AfterClass;
+import org.junit.Assert;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.ClassRule;
@@ -31,6 +33,7 @@
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import java.util.ArrayList;
@@ -353,4 +356,103 @@
public void test2() {
}
}
+
+ /**
+ * The test class is unloadable, but has a @DisabledOnRavenwood.
+ */
+ @RunWith(AndroidJUnit4.class)
+ @DisabledOnRavenwood
+ // CHECKSTYLE:OFF
+ @Expected("""
+ testRunStarted: classes
+ testSuiteStarted: classes
+ testSuiteStarted: ClassUnloadbleAndDisabledTest(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$ClassUnloadbleAndDisabledTest)
+ testIgnored: ClassUnloadbleAndDisabledTest(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$ClassUnloadbleAndDisabledTest)
+ testSuiteFinished: ClassUnloadbleAndDisabledTest(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$ClassUnloadbleAndDisabledTest)
+ testSuiteFinished: classes
+ testRunFinished: 0,0,0,1
+ """)
+ // CHECKSTYLE:ON
+ public static class ClassUnloadbleAndDisabledTest {
+ static {
+ Assert.fail("Class unloadable!");
+ }
+
+ @Test
+ public void test1() {
+ }
+
+ @Test
+ public void test2() {
+ }
+ }
+
+ /**
+ * The test class is unloadable, but has a @DisabledOnRavenwood.
+ */
+ @RunWith(AndroidJUnit4.class)
+ // CHECKSTYLE:OFF
+ @Expected("""
+ testRunStarted: classes
+ testSuiteStarted: classes
+ testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$ClassUnloadbleAndEnabledTest
+ testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$ClassUnloadbleAndEnabledTest
+ testStarted: test1(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$ClassUnloadbleAndEnabledTest)
+ testFailure: Class unloadable!
+ testFinished: test1(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$ClassUnloadbleAndEnabledTest)
+ testStarted: test2(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$ClassUnloadbleAndEnabledTest)
+ testFailure: Class unloadable!
+ testFinished: test2(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$ClassUnloadbleAndEnabledTest)
+ testSuiteFinished: classes
+ testRunFinished: 2,2,0,0
+ """)
+ // CHECKSTYLE:ON
+ public static class ClassUnloadbleAndEnabledTest {
+ static {
+ Assert.fail("Class unloadable!");
+ }
+
+ @Test
+ public void test1() {
+ }
+
+ @Test
+ public void test2() {
+ }
+ }
+
+ public static class BrokenTestRunner extends BlockJUnit4ClassRunner {
+ public BrokenTestRunner(Class<?> testClass) throws InitializationError {
+ super(testClass);
+
+ if (true) {
+ throw new RuntimeException("This is a broken test runner!");
+ }
+ }
+ }
+
+ /**
+ * The test runner throws an exception from the ctor.
+ */
+ @RunWith(BrokenTestRunner.class)
+ // CHECKSTYLE:OFF
+ @Expected("""
+ testRunStarted: classes
+ testSuiteStarted: classes
+ testStarted: Constructor(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$BrokenRunnerTest)
+ testFailure: Exception detected in constructor
+ testFinished: Constructor(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$BrokenRunnerTest)
+ testSuiteFinished: classes
+ testRunFinished: 1,1,0,0
+ """)
+ // CHECKSTYLE:ON
+ public static class BrokenRunnerTest {
+ @Test
+ public void test1() {
+ }
+
+ @Test
+ public void test2() {
+ }
+ }
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
index cf039df..b4713d9 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.WorkerThread;
import android.app.appfunctions.AppFunctionStaticMetadataHelper;
import android.app.appfunctions.ExecuteAppFunctionAidlRequest;
import android.app.appfunctions.ExecuteAppFunctionResponse;
@@ -45,7 +46,6 @@
import com.android.server.appfunctions.RemoteServiceCaller.RunServiceCallCallback;
import com.android.server.appfunctions.RemoteServiceCaller.ServiceUsageCompleteListener;
-import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.CompletionException;
@@ -83,23 +83,6 @@
mServiceConfig = serviceConfig;
}
- @Override
- public void executeAppFunction(
- @NonNull ExecuteAppFunctionAidlRequest requestInternal,
- @NonNull IExecuteAppFunctionCallback executeAppFunctionCallback) {
- Objects.requireNonNull(requestInternal);
- Objects.requireNonNull(executeAppFunctionCallback);
-
- final SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback =
- new SafeOneTimeExecuteAppFunctionCallback(executeAppFunctionCallback);
-
- try {
- executeAppFunctionInternal(requestInternal, safeExecuteAppFunctionCallback);
- } catch (Exception e) {
- safeExecuteAppFunctionCallback.onResult(mapExceptionToExecuteAppFunctionResponse(e));
- }
- }
-
/** Called when the user is unlocked. */
public void onUserUnlocked(TargetUser user) {
Objects.requireNonNull(user);
@@ -120,18 +103,22 @@
}
}
- private void executeAppFunctionInternal(
- ExecuteAppFunctionAidlRequest requestInternal,
- SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback) {
+ @Override
+ public void executeAppFunction(
+ @NonNull ExecuteAppFunctionAidlRequest requestInternal,
+ @NonNull IExecuteAppFunctionCallback executeAppFunctionCallback) {
+ Objects.requireNonNull(requestInternal);
+ Objects.requireNonNull(executeAppFunctionCallback);
+
+ final SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback =
+ new SafeOneTimeExecuteAppFunctionCallback(executeAppFunctionCallback);
String validatedCallingPackage;
- UserHandle targetUser;
try {
validatedCallingPackage =
mCallerValidator.validateCallingPackage(requestInternal.getCallingPackage());
- targetUser =
- mCallerValidator.verifyTargetUserHandle(
- requestInternal.getUserHandle(), validatedCallingPackage);
+ mCallerValidator.verifyTargetUserHandle(
+ requestInternal.getUserHandle(), validatedCallingPackage);
} catch (SecurityException exception) {
safeExecuteAppFunctionCallback.onResult(
ExecuteAppFunctionResponse.newFailure(
@@ -141,6 +128,30 @@
return;
}
+ int callingUid = Binder.getCallingUid();
+ int callingPid = Binder.getCallingUid();
+ THREAD_POOL_EXECUTOR.execute(
+ () -> {
+ try {
+ executeAppFunctionInternal(
+ requestInternal,
+ callingUid,
+ callingPid,
+ safeExecuteAppFunctionCallback);
+ } catch (Exception e) {
+ safeExecuteAppFunctionCallback.onResult(
+ mapExceptionToExecuteAppFunctionResponse(e));
+ }
+ });
+ }
+
+ @WorkerThread
+ private void executeAppFunctionInternal(
+ ExecuteAppFunctionAidlRequest requestInternal,
+ int callingUid,
+ int callingPid,
+ SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback) {
+ UserHandle targetUser = requestInternal.getUserHandle();
// TODO(b/354956319): Add and honor the new enterprise policies.
if (mCallerValidator.isUserOrganizationManaged(targetUser)) {
safeExecuteAppFunctionCallback.onResult(
@@ -165,7 +176,9 @@
var unused =
mCallerValidator
.verifyCallerCanExecuteAppFunction(
- validatedCallingPackage,
+ callingUid,
+ callingPid,
+ requestInternal.getCallingPackage(),
targetPackageName,
requestInternal.getClientRequest().getFunctionIdentifier())
.thenAccept(
@@ -191,19 +204,12 @@
/* extras= */ null));
return;
}
- final long token = Binder.clearCallingIdentity();
- try {
- bindAppFunctionServiceUnchecked(
- requestInternal,
- serviceIntent,
- targetUser,
- safeExecuteAppFunctionCallback,
- /* bindFlags= */ Context.BIND_AUTO_CREATE,
- /* timeoutInMillis= */ mServiceConfig
- .getExecuteAppFunctionTimeoutMillis());
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ bindAppFunctionServiceUnchecked(
+ requestInternal,
+ serviceIntent,
+ targetUser,
+ safeExecuteAppFunctionCallback,
+ /* bindFlags= */ Context.BIND_AUTO_CREATE);
})
.exceptionally(
ex -> {
@@ -218,13 +224,11 @@
@NonNull Intent serviceIntent,
@NonNull UserHandle targetUser,
@NonNull SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback,
- int bindFlags,
- long timeoutInMillis) {
+ int bindFlags) {
boolean bindServiceResult =
mRemoteServiceCaller.runServiceCall(
serviceIntent,
bindFlags,
- timeoutInMillis,
targetUser,
new RunServiceCallCallback<IAppFunctionService>() {
@Override
@@ -265,16 +269,6 @@
"Failed to connect to AppFunctionService",
/* extras= */ null));
}
-
- @Override
- public void onTimedOut() {
- Slog.e(TAG, "Timed out");
- safeExecuteAppFunctionCallback.onResult(
- ExecuteAppFunctionResponse.newFailure(
- ExecuteAppFunctionResponse.RESULT_TIMED_OUT,
- "Binding to AppFunctionService timed out.",
- /* extras= */ null));
- }
});
if (!bindServiceResult) {
@@ -332,30 +326,27 @@
Slog.d(TAG, "AppSearch Manager not found for user: " + user.getUserIdentifier());
return;
}
- try (FutureGlobalSearchSession futureGlobalSearchSession =
+ FutureGlobalSearchSession futureGlobalSearchSession =
new FutureGlobalSearchSession(
- perUserAppSearchManager, AppFunctionExecutors.THREAD_POOL_EXECUTOR)) {
- AppFunctionMetadataObserver appFunctionMetadataObserver =
- new AppFunctionMetadataObserver(
- user.getUserHandle(),
- mContext.createContextAsUser(user.getUserHandle(), /* flags= */ 0));
- var unused =
- futureGlobalSearchSession
- .registerObserverCallbackAsync(
- "android",
- new ObserverSpec.Builder().build(),
- THREAD_POOL_EXECUTOR,
- appFunctionMetadataObserver)
- .whenComplete(
- (voidResult, ex) -> {
- if (ex != null) {
- Slog.e(TAG, "Failed to register observer: ", ex);
- }
- });
-
- } catch (IOException ex) {
- Slog.e(TAG, "Failed to close observer session: ", ex);
- }
+ perUserAppSearchManager, AppFunctionExecutors.THREAD_POOL_EXECUTOR);
+ AppFunctionMetadataObserver appFunctionMetadataObserver =
+ new AppFunctionMetadataObserver(
+ user.getUserHandle(),
+ mContext.createContextAsUser(user.getUserHandle(), /* flags= */ 0));
+ var unused =
+ futureGlobalSearchSession
+ .registerObserverCallbackAsync(
+ "android",
+ new ObserverSpec.Builder().build(),
+ THREAD_POOL_EXECUTOR,
+ appFunctionMetadataObserver)
+ .whenComplete(
+ (voidResult, ex) -> {
+ if (ex != null) {
+ Slog.e(TAG, "Failed to register observer: ", ex);
+ }
+ futureGlobalSearchSession.close();
+ });
}
private void trySyncRuntimeMetadata(@NonNull TargetUser user) {
diff --git a/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java b/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java
index e7a861e..3592ed5 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java
@@ -60,9 +60,9 @@
* Validates that the caller can execute the specified app function.
*
* <p>The caller can execute if the app function's package name is the same as the caller's
- * package or the caller has either {@link Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or
- * {@link Manifest.permission.EXECUTE_APP_FUNCTIONS} granted. In some cases, app functions can
- * still opt-out of caller having {@link Manifest.permission.EXECUTE_APP_FUNCTIONS}.
+ * package or the caller has either {@link Manifest.permission#EXECUTE_APP_FUNCTIONS_TRUSTED} or
+ * {@link Manifest.permission#EXECUTE_APP_FUNCTIONS} granted. In some cases, app functions can
+ * still opt-out of caller having {@link Manifest.permission#EXECUTE_APP_FUNCTIONS}.
*
* @param callerPackageName The calling package (as previously validated).
* @param targetPackageName The package that owns the app function to execute.
@@ -70,6 +70,8 @@
* @return Whether the caller can execute the specified app function.
*/
AndroidFuture<Boolean> verifyCallerCanExecuteAppFunction(
+ int callingUid,
+ int callingPid,
@NonNull String callerPackageName,
@NonNull String targetPackageName,
@NonNull String functionId);
diff --git a/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java b/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java
index 94a63b4..8b6251a 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java
@@ -20,6 +20,7 @@
import static android.app.appfunctions.AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_NAMESPACE;
import static android.app.appfunctions.AppFunctionStaticMetadataHelper.STATIC_PROPERTY_RESTRICT_CALLERS_WITH_EXECUTE_APP_FUNCTIONS;
import static android.app.appfunctions.AppFunctionStaticMetadataHelper.getDocumentIdForAppFunction;
+
import static com.android.server.appfunctions.AppFunctionExecutors.THREAD_POOL_EXECUTOR;
import android.Manifest;
@@ -41,6 +42,7 @@
import android.os.UserManager;
import com.android.internal.infra.AndroidFuture;
+
import java.util.Objects;
/* Validates that caller has the correct privilege to call an AppFunctionManager Api. */
@@ -82,7 +84,6 @@
}
@Override
- @BinderThread
@RequiresPermission(
anyOf = {
Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED,
@@ -90,6 +91,8 @@
},
conditional = true)
public AndroidFuture<Boolean> verifyCallerCanExecuteAppFunction(
+ int callingUid,
+ int callingPid,
@NonNull String callerPackageName,
@NonNull String targetPackageName,
@NonNull String functionId) {
@@ -97,11 +100,11 @@
return AndroidFuture.completedFuture(true);
}
- int pid = Binder.getCallingPid();
- int uid = Binder.getCallingUid();
boolean hasTrustedExecutionPermission =
mContext.checkPermission(
- Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED, pid, uid)
+ Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED,
+ callingPid,
+ callingUid)
== PackageManager.PERMISSION_GRANTED;
if (hasTrustedExecutionPermission) {
@@ -109,40 +112,34 @@
}
boolean hasExecutionPermission =
- mContext.checkPermission(Manifest.permission.EXECUTE_APP_FUNCTIONS, pid, uid)
+ mContext.checkPermission(
+ Manifest.permission.EXECUTE_APP_FUNCTIONS, callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED;
if (!hasExecutionPermission) {
return AndroidFuture.completedFuture(false);
}
- final long token = Binder.clearCallingIdentity();
- try {
- FutureAppSearchSession futureAppSearchSession =
- new FutureAppSearchSessionImpl(
- mContext.getSystemService(AppSearchManager.class),
- THREAD_POOL_EXECUTOR,
- new SearchContext.Builder(APP_FUNCTION_STATIC_METADATA_DB).build());
+ FutureAppSearchSession futureAppSearchSession =
+ new FutureAppSearchSessionImpl(
+ mContext.getSystemService(AppSearchManager.class),
+ THREAD_POOL_EXECUTOR,
+ new SearchContext.Builder(APP_FUNCTION_STATIC_METADATA_DB).build());
- String documentId = getDocumentIdForAppFunction(targetPackageName, functionId);
+ String documentId = getDocumentIdForAppFunction(targetPackageName, functionId);
- return futureAppSearchSession
- .getByDocumentId(
- new GetByDocumentIdRequest.Builder(APP_FUNCTION_STATIC_NAMESPACE)
- .addIds(documentId)
- .build())
- .thenApply(
- batchResult ->
- getGenericDocumentFromBatchResult(batchResult, documentId))
- .thenApply(
- CallerValidatorImpl::getRestrictCallersWithExecuteAppFunctionsProperty)
- .thenApply(
- restrictCallersWithExecuteAppFunctions ->
- !restrictCallersWithExecuteAppFunctions
- && hasExecutionPermission);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ return futureAppSearchSession
+ .getByDocumentId(
+ new GetByDocumentIdRequest.Builder(APP_FUNCTION_STATIC_NAMESPACE)
+ .addIds(documentId)
+ .build())
+ .thenApply(
+ batchResult -> getGenericDocumentFromBatchResult(batchResult, documentId))
+ .thenApply(document -> !getRestrictCallersWithExecuteAppFunctionsProperty(document))
+ .whenComplete(
+ (result, throwable) -> {
+ futureAppSearchSession.close();
+ });
}
private static GenericDocument getGenericDocumentFromBatchResult(
@@ -167,19 +164,13 @@
}
@Override
- @BinderThread
public boolean isUserOrganizationManaged(@NonNull UserHandle targetUser) {
- final long callingIdentityToken = Binder.clearCallingIdentity();
- try {
- if (Objects.requireNonNull(mContext.getSystemService(DevicePolicyManager.class))
- .isDeviceManaged()) {
- return true;
- }
- return Objects.requireNonNull(mContext.getSystemService(UserManager.class))
- .isManagedProfile(targetUser.getIdentifier());
- } finally {
- Binder.restoreCallingIdentity(callingIdentityToken);
+ if (Objects.requireNonNull(mContext.getSystemService(DevicePolicyManager.class))
+ .isDeviceManaged()) {
+ return true;
}
+ return Objects.requireNonNull(mContext.getSystemService(UserManager.class))
+ .isManagedProfile(targetUser.getIdentifier());
}
/**
diff --git a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
index 0044b4b..de2034b 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
@@ -84,6 +84,9 @@
AndroidFuture<FutureSearchResults> search(
@NonNull String queryExpression, @NonNull SearchSpec searchSpec);
+ @Override
+ void close();
+
/** A future API wrapper of {@link android.app.appsearch.SearchResults}. */
interface FutureSearchResults {
diff --git a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSessionImpl.java b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSessionImpl.java
index 3079d9f..d24bb87 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSessionImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSessionImpl.java
@@ -38,7 +38,6 @@
import com.android.internal.infra.AndroidFuture;
-import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -183,7 +182,15 @@
}
@Override
- public void close() throws IOException {}
+ public void close() {
+ getSessionAsync()
+ .whenComplete(
+ (appSearchSession, throwable) -> {
+ if (appSearchSession != null) {
+ appSearchSession.close();
+ }
+ });
+ }
private static final class FutureSearchResultsImpl implements FutureSearchResults {
private final SearchResults mSearchResults;
diff --git a/services/appfunctions/java/com/android/server/appfunctions/FutureGlobalSearchSession.java b/services/appfunctions/java/com/android/server/appfunctions/FutureGlobalSearchSession.java
index 0c22624..874c5da 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/FutureGlobalSearchSession.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/FutureGlobalSearchSession.java
@@ -23,12 +23,10 @@
import android.app.appsearch.exceptions.AppSearchException;
import android.app.appsearch.observer.ObserverCallback;
import android.app.appsearch.observer.ObserverSpec;
-import android.util.Slog;
import com.android.internal.infra.AndroidFuture;
import java.io.Closeable;
-import java.io.IOException;
import java.util.concurrent.Executor;
/** A wrapper around {@link GlobalSearchSession} that provides a future-based API. */
@@ -84,11 +82,13 @@
}
@Override
- public void close() throws IOException {
- try {
- getSessionAsync().get().close();
- } catch (Exception ex) {
- Slog.e(TAG, "Failed to close global search session", ex);
- }
+ public void close() {
+ getSessionAsync()
+ .whenComplete(
+ (appSearchSession, throwable) -> {
+ if (appSearchSession != null) {
+ appSearchSession.close();
+ }
+ });
}
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java b/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
index 8c6f50e..e29b6e4 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
@@ -145,13 +145,25 @@
ArrayMap<String, ArraySet<String>> removedFunctionsDiffMap =
getRemovedFunctionsDiffMap(staticPackageToFunctionMap, runtimePackageToFunctionMap);
- Set<AppSearchSchema> appRuntimeMetadataSchemas =
- getAllRuntimeMetadataSchemas(staticPackageToFunctionMap.keySet());
- appRuntimeMetadataSchemas.add(
- AppFunctionRuntimeMetadata.createParentAppFunctionRuntimeSchema());
+ if (!staticPackageToFunctionMap.keySet().equals(runtimePackageToFunctionMap.keySet())) {
+ // Drop removed packages from removedFunctionsDiffMap, as setSchema() deletes them
+ ArraySet<String> removedPackages =
+ getRemovedPackages(
+ staticPackageToFunctionMap.keySet(), removedFunctionsDiffMap.keySet());
+ for (String packageName : removedPackages) {
+ removedFunctionsDiffMap.remove(packageName);
+ }
+ Set<AppSearchSchema> appRuntimeMetadataSchemas =
+ getAllRuntimeMetadataSchemas(staticPackageToFunctionMap.keySet());
+ appRuntimeMetadataSchemas.add(
+ AppFunctionRuntimeMetadata.createParentAppFunctionRuntimeSchema());
+ SetSchemaRequest addSetSchemaRequest =
+ buildSetSchemaRequestForRuntimeMetadataSchemas(
+ mPackageManager, appRuntimeMetadataSchemas);
+ Objects.requireNonNull(
+ runtimeMetadataSearchSession.setSchema(addSetSchemaRequest).get());
+ }
- // Operation order matters here. i.e. remove -> setSchema -> add. Otherwise we would
- // encounter an error trying to delete a document with no existing schema.
if (!removedFunctionsDiffMap.isEmpty()) {
RemoveByDocumentIdRequest removeByDocumentIdRequest =
buildRemoveRuntimeMetadataRequest(removedFunctionsDiffMap);
@@ -164,12 +176,6 @@
}
if (!addedFunctionsDiffMap.isEmpty()) {
- // TODO(b/357551503): only set schema on package diff
- SetSchemaRequest addSetSchemaRequest =
- buildSetSchemaRequestForRuntimeMetadataSchemas(
- mPackageManager, appRuntimeMetadataSchemas);
- Objects.requireNonNull(
- runtimeMetadataSearchSession.setSchema(addSetSchemaRequest).get());
PutDocumentsRequest putDocumentsRequest =
buildPutRuntimeMetadataRequest(addedFunctionsDiffMap);
AppSearchBatchResult<String, Void> putDocumentBatchResult =
@@ -276,6 +282,30 @@
}
/**
+ * This method returns a set of packages that are in the removed function packages but not in
+ * the all existing static packages.
+ *
+ * @param allExistingStaticPackages A set of all existing static metadata packages.
+ * @param removedFunctionPackages A set of all removed function packages.
+ * @return A set of packages that are in the removed function packages but not in the all
+ * existing static packages.
+ */
+ @NonNull
+ private static ArraySet<String> getRemovedPackages(
+ @NonNull Set<String> allExistingStaticPackages,
+ @NonNull Set<String> removedFunctionPackages) {
+ ArraySet<String> removedPackages = new ArraySet<>();
+
+ for (String packageName : removedFunctionPackages) {
+ if (!allExistingStaticPackages.contains(packageName)) {
+ removedPackages.add(packageName);
+ }
+ }
+
+ return removedPackages;
+ }
+
+ /**
* This method returns a map of package names to a set of function ids that are in the static
* metadata but not in the runtime metadata.
*
diff --git a/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCaller.java b/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCaller.java
index 58597c3..cd5c383 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCaller.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCaller.java
@@ -43,7 +43,6 @@
* @param intent An Intent object that describes the service that should be bound.
* @param bindFlags Flags used to control the binding process See {@link
* android.content.Context#bindService}.
- * @param timeoutInMillis The maximum time in milliseconds to wait for the service connection.
* @param userHandle The UserHandle of the user for which the service should be bound.
* @param callback A callback to be invoked for various events. See {@link
* RunServiceCallCallback}.
@@ -51,7 +50,6 @@
boolean runServiceCall(
@NonNull Intent intent,
int bindFlags,
- long timeoutInMillis,
@NonNull UserHandle userHandle,
@NonNull RunServiceCallCallback<T> callback);
@@ -75,11 +73,5 @@
/** Called when the service connection was failed to establish. */
void onFailedToConnect();
-
- /**
- * Called when the whole operation(i.e. binding and the service call) takes longer than
- * allowed.
- */
- void onTimedOut();
}
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCallerImpl.java b/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCallerImpl.java
index eea17ee..070a99d 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCallerImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCallerImpl.java
@@ -62,12 +62,11 @@
public boolean runServiceCall(
@NonNull Intent intent,
int bindFlags,
- long timeoutInMillis,
@NonNull UserHandle userHandle,
@NonNull RunServiceCallCallback<T> callback) {
OneOffServiceConnection serviceConnection =
new OneOffServiceConnection(
- intent, bindFlags, timeoutInMillis, userHandle, callback);
+ intent, bindFlags, userHandle, callback);
return serviceConnection.bindAndRun();
}
@@ -76,28 +75,17 @@
implements ServiceConnection, ServiceUsageCompleteListener {
private final Intent mIntent;
private final int mFlags;
- private final long mTimeoutMillis;
private final UserHandle mUserHandle;
private final RunServiceCallCallback<T> mCallback;
- private final Runnable mTimeoutCallback;
OneOffServiceConnection(
@NonNull Intent intent,
int flags,
- long timeoutMillis,
@NonNull UserHandle userHandle,
@NonNull RunServiceCallCallback<T> callback) {
mIntent = intent;
mFlags = flags;
- mTimeoutMillis = timeoutMillis;
mCallback = callback;
- mTimeoutCallback =
- () ->
- mExecutor.execute(
- () -> {
- safeUnbind();
- mCallback.onTimedOut();
- });
mUserHandle = userHandle;
}
@@ -105,9 +93,7 @@
boolean bindServiceResult =
mContext.bindServiceAsUser(mIntent, this, mFlags, mUserHandle);
- if (bindServiceResult) {
- mHandler.postDelayed(mTimeoutCallback, mTimeoutMillis);
- } else {
+ if(!bindServiceResult) {
safeUnbind();
}
@@ -141,7 +127,6 @@
private void safeUnbind() {
try {
- mHandler.removeCallbacks(mTimeoutCallback);
mContext.unbindService(this);
} catch (Exception ex) {
Log.w(TAG, "Failed to unbind", ex);
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index b109472..2fa0e0d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -720,6 +720,9 @@
void handleInlineSuggestionRequest(InlineSuggestionsRequest inlineSuggestionsRequest,
ViewState viewState) {
+ if (sVerbose) {
+ Slog.v(TAG, "handleInlineSuggestionRequest(): inline suggestion request received");
+ }
synchronized (mLock) {
if (!mWaitForInlineRequest || mPendingInlineSuggestionsRequest != null) {
return;
@@ -734,15 +737,27 @@
@GuardedBy("mLock")
void maybeRequestFillLocked() {
if (mPendingFillRequest == null) {
+ if (sVerbose) {
+ Slog.v(TAG, "maybeRequestFillLocked(): cancelling calling fill request "
+ + "due to empty pending fill request");
+ }
return;
}
mFieldClassificationIdSnapshot = sIdCounterForPcc.get();
if (mWaitForInlineRequest) {
if (mPendingInlineSuggestionsRequest == null) {
+ if (sVerbose) {
+ Slog.v(TAG, "maybeRequestFillLocked(): cancelling calling fill request "
+ + "due to waiting for inline request and pending inline request is "
+ + "currently empty");
+ }
return;
}
-
+ if (sVerbose) {
+ Slog.v(TAG, "maybeRequestFillLocked(): adding inline request to pending "
+ + "fill request");
+ }
mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
mPendingFillRequest.getFillContexts(),
mPendingFillRequest.getHints(),
@@ -750,8 +765,17 @@
mPendingFillRequest.getFlags(),
mPendingInlineSuggestionsRequest,
mPendingFillRequest.getDelayedFillIntentSender());
+ } else {
+ if (sVerbose) {
+ Slog.v(TAG, "maybeRequestFillLocked(): not adding inline request to pending "
+ + "fill request");
+ }
}
+
mLastFillRequest = mPendingFillRequest;
+ if (sVerbose) {
+ Slog.v(TAG, "maybeRequestFillLocked(): sending fill request");
+ }
if (shouldRequestSecondaryProvider(mPendingFillRequest.getFlags())
&& mSecondaryProviderHandler != null) {
Slog.v(TAG, "Requesting fill response to secondary provider.");
diff --git a/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java b/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java
index 46d60f9..0c54720 100644
--- a/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java
+++ b/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java
@@ -454,10 +454,10 @@
@NonNull Associations associations)
throws IOException {
final XmlSerializer serializer = parent.startTag(null, XML_TAG_ASSOCIATIONS);
+ writeIntAttribute(serializer, XML_ATTR_MAX_ID, associations.getMaxId());
for (AssociationInfo association : associations.getAssociations()) {
writeAssociation(serializer, association);
}
- writeIntAttribute(serializer, XML_ATTR_MAX_ID, associations.getMaxId());
serializer.endTag(null, XML_TAG_ASSOCIATIONS);
}
diff --git a/services/companion/java/com/android/server/companion/virtual/OWNERS b/services/companion/java/com/android/server/companion/virtual/OWNERS
index 4fe0592..4b732ac 100644
--- a/services/companion/java/com/android/server/companion/virtual/OWNERS
+++ b/services/companion/java/com/android/server/companion/virtual/OWNERS
@@ -2,7 +2,9 @@
set noparent
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
\ No newline at end of file
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 6657c1c..59dea09 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -160,6 +160,7 @@
private int mLastChargeCounter;
private int mLastBatteryCycleCount;
private int mLastChargingState;
+ private int mLastBatteryCapacityLevel;
/**
* The last seen charging policy. This requires the
* {@link android.Manifest.permission#BATTERY_STATS} permission and should therefore not be
@@ -609,7 +610,8 @@
|| mHealthInfo.batteryChargeCounterUah != mLastChargeCounter
|| mInvalidCharger != mLastInvalidCharger
|| mHealthInfo.batteryCycleCount != mLastBatteryCycleCount
- || mHealthInfo.chargingState != mLastChargingState)) {
+ || mHealthInfo.chargingState != mLastChargingState
+ || mHealthInfo.batteryCapacityLevel != mLastBatteryCapacityLevel)) {
if (mPlugType != mLastPlugType) {
if (mLastPlugType == BATTERY_PLUGGED_NONE) {
@@ -829,6 +831,7 @@
mLastInvalidCharger = mInvalidCharger;
mLastBatteryCycleCount = mHealthInfo.batteryCycleCount;
mLastChargingState = mHealthInfo.chargingState;
+ mLastBatteryCapacityLevel = mHealthInfo.batteryCapacityLevel;
}
}
@@ -862,6 +865,7 @@
intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah);
intent.putExtra(BatteryManager.EXTRA_CYCLE_COUNT, mHealthInfo.batteryCycleCount);
intent.putExtra(BatteryManager.EXTRA_CHARGING_STATUS, mHealthInfo.chargingState);
+ intent.putExtra(BatteryManager.EXTRA_CAPACITY_LEVEL, mHealthInfo.batteryCapacityLevel);
if (DEBUG) {
Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. scale:" + BATTERY_SCALE
+ ", info:" + mHealthInfo.toString());
@@ -964,6 +968,7 @@
event.putLong(BatteryManager.EXTRA_EVENT_TIMESTAMP, now);
event.putInt(BatteryManager.EXTRA_CYCLE_COUNT, mHealthInfo.batteryCycleCount);
event.putInt(BatteryManager.EXTRA_CHARGING_STATUS, mHealthInfo.chargingState);
+ event.putInt(BatteryManager.EXTRA_CAPACITY_LEVEL, mHealthInfo.batteryCapacityLevel);
boolean queueWasEmpty = mBatteryLevelsEventQueue.isEmpty();
mBatteryLevelsEventQueue.add(event);
@@ -1401,6 +1406,7 @@
pw.println(" technology: " + mHealthInfo.batteryTechnology);
pw.println(" Charging state: " + mHealthInfo.chargingState);
pw.println(" Charging policy: " + mHealthInfo.chargingPolicy);
+ pw.println(" Capacity level: " + mHealthInfo.batteryCapacityLevel);
} else {
Shell shell = new Shell();
shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null));
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 68d0ad2..a459ea9 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -173,6 +173,15 @@
"include-filter": "com.android.server.wm.BackgroundActivityStart*"
}
]
+ },
+ {
+ "name": "CtsOsTestCases",
+ "file_patterns": ["StorageManagerService\\.java"],
+ "options": [
+ {
+ "include-filter": "android.os.storage.cts.StorageStatsManagerTest"
+ }
+ ]
}
]
}
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 1c13ad5..f32031de 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -32,11 +32,11 @@
import static android.app.UiModeManager.PROJECTION_TYPE_NONE;
import static android.os.UserHandle.USER_SYSTEM;
import static android.os.UserHandle.getCallingUserId;
-import static android.os.UserManager.isVisibleBackgroundUsersEnabled;
import static android.provider.Settings.Secure.CONTRAST_LEVEL;
import static android.util.TimeUtils.isTimeBetween;
import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
+import static com.android.server.pm.UserManagerService.enforceCurrentUserIfVisibleBackgroundEnabled;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -100,7 +100,6 @@
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.DumpUtils;
-import com.android.server.pm.UserManagerService;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
@@ -850,7 +849,7 @@
}
final int user = UserHandle.getCallingUserId();
- enforceValidCallingUser(user);
+ enforceCurrentUserIfVisibleBackgroundEnabled(user);
final long ident = Binder.clearCallingIdentity();
try {
@@ -914,7 +913,7 @@
@AttentionModeThemeOverlayType int attentionModeThemeOverlayType) {
setAttentionModeThemeOverlay_enforcePermission();
- enforceValidCallingUser(UserHandle.getCallingUserId());
+ enforceCurrentUserIfVisibleBackgroundEnabled(UserHandle.getCallingUserId());
synchronized (mLock) {
if (mAttentionModeThemeOverlay != attentionModeThemeOverlayType) {
@@ -1005,7 +1004,7 @@
return false;
}
final int user = Binder.getCallingUserHandle().getIdentifier();
- enforceValidCallingUser(user);
+ enforceCurrentUserIfVisibleBackgroundEnabled(user);
if (user != mCurrentUser && getContext().checkCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS)
@@ -1064,7 +1063,7 @@
return;
}
final int user = UserHandle.getCallingUserId();
- enforceValidCallingUser(user);
+ enforceCurrentUserIfVisibleBackgroundEnabled(user);
final long ident = Binder.clearCallingIdentity();
try {
@@ -1094,7 +1093,7 @@
return;
}
final int user = UserHandle.getCallingUserId();
- enforceValidCallingUser(user);
+ enforceCurrentUserIfVisibleBackgroundEnabled(user);
final long ident = Binder.clearCallingIdentity();
try {
@@ -1116,7 +1115,7 @@
assertLegit(callingPackage);
assertSingleProjectionType(projectionType);
enforceProjectionTypePermissions(projectionType);
- enforceValidCallingUser(getCallingUserId());
+ enforceCurrentUserIfVisibleBackgroundEnabled(getCallingUserId());
synchronized (mLock) {
if (mProjectionHolders == null) {
@@ -1162,7 +1161,7 @@
assertLegit(callingPackage);
assertSingleProjectionType(projectionType);
enforceProjectionTypePermissions(projectionType);
- enforceValidCallingUser(getCallingUserId());
+ enforceCurrentUserIfVisibleBackgroundEnabled(getCallingUserId());
return releaseProjectionUnchecked(projectionType, callingPackage);
}
@@ -1204,7 +1203,7 @@
return;
}
- enforceValidCallingUser(getCallingUserId());
+ enforceCurrentUserIfVisibleBackgroundEnabled(getCallingUserId());
synchronized (mLock) {
if (mProjectionListeners == null) {
@@ -1253,32 +1252,6 @@
}
};
- // This method validates whether calling user is valid in visible background users
- // feature. Valid user is the current user or the system or in the same profile group as
- // the current user.
- private void enforceValidCallingUser(int userId) {
- if (!isVisibleBackgroundUsersEnabled()) {
- return;
- }
- if (LOG) {
- Slog.d(TAG, "enforceValidCallingUser: userId=" + userId
- + " isSystemUser=" + (userId == USER_SYSTEM) + " current user=" + mCurrentUser
- + " callingPid=" + Binder.getCallingPid()
- + " callingUid=" + mInjector.getCallingUid());
- }
- long ident = Binder.clearCallingIdentity();
- try {
- if (userId != USER_SYSTEM && userId != mCurrentUser
- && !UserManagerService.getInstance().isSameProfileGroup(userId, mCurrentUser)) {
- throw new SecurityException(
- "Calling user is not valid for level-1 compatibility in MUMD. "
- + "callingUserId=" + userId + " currentUserId=" + mCurrentUser);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
private void enforceProjectionTypePermissions(@UiModeManager.ProjectionType int p) {
if ((p & PROJECTION_TYPE_AUTOMOTIVE) != 0) {
getContext().enforceCallingPermission(
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 765afef..88edb12 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -2169,6 +2169,9 @@
Log.i(TAG, "callingUid=" + callingUid + ", userId=" + accounts.userId
+ " performing rename account");
Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
+ if (resultingAccount == null) {
+ resultingAccount = accountToRename;
+ }
Bundle result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index 34c3d7e..a73a991 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -74,6 +74,7 @@
import android.util.Xml;
import com.android.internal.R;
+import com.android.internal.annotations.Keep;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.util.FrameworkStatsLog;
@@ -214,7 +215,7 @@
class PairingThread extends Thread implements NsdManager.RegistrationListener {
private NsdManager mNsdManager;
- private String mPublicKey;
+ @Keep private String mPublicKey;
private String mPairingCode;
private String mGuid;
private String mServiceName;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 54a7410..414a4e6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -714,12 +714,14 @@
/**
* Map userId to its companion app uids.
*/
+ @GuardedBy("mCompanionAppUidsMap")
private final Map<Integer, Set<Integer>> mCompanionAppUidsMap = new ArrayMap<>();
/**
* The profile owner UIDs.
*/
- private ArraySet<Integer> mProfileOwnerUids = null;
+ @GuardedBy("mProfileOwnerUids")
+ private final ArraySet<Integer> mProfileOwnerUids = new ArraySet<>();
final UserController mUserController;
@VisibleForTesting
@@ -15302,10 +15304,8 @@
}
psr.setReportedForegroundServiceTypes(fgServiceTypes);
- ProcessChangeItem item = mProcessList.enqueueProcessChangeItemLocked(
- proc.getPid(), proc.info.uid);
- item.changes |= ProcessChangeItem.CHANGE_FOREGROUND_SERVICES;
- item.foregroundServiceTypes = fgServiceTypes;
+ mProcessList.enqueueProcessChangeItemLocked(proc.getPid(), proc.info.uid,
+ ProcessChangeItem.CHANGE_FOREGROUND_SERVICES, fgServiceTypes);
}
if (oomAdj) {
updateOomAdjLocked(proc, OOM_ADJ_REASON_UI_VISIBILITY);
@@ -17535,32 +17535,35 @@
@Override
public void setProfileOwnerUid(ArraySet<Integer> profileOwnerUids) {
- synchronized (ActivityManagerService.this) {
- mProfileOwnerUids = profileOwnerUids;
+ synchronized (mProfileOwnerUids) {
+ mProfileOwnerUids.clear();
+ mProfileOwnerUids.addAll(profileOwnerUids);
}
}
@Override
public boolean isProfileOwner(int uid) {
- synchronized (ActivityManagerService.this) {
- return mProfileOwnerUids != null && mProfileOwnerUids.indexOf(uid) >= 0;
+ synchronized (mProfileOwnerUids) {
+ return mProfileOwnerUids.indexOf(uid) >= 0;
}
}
@Override
public void setCompanionAppUids(int userId, Set<Integer> companionAppUids) {
- synchronized (ActivityManagerService.this) {
+ synchronized (mCompanionAppUidsMap) {
mCompanionAppUidsMap.put(userId, companionAppUids);
}
}
@Override
public boolean isAssociatedCompanionApp(int userId, int uid) {
- final Set<Integer> allUids = mCompanionAppUidsMap.get(userId);
- if (allUids == null) {
- return false;
+ synchronized (mCompanionAppUidsMap) {
+ final Set<Integer> allUids = mCompanionAppUidsMap.get(userId);
+ if (allUids == null) {
+ return false;
+ }
+ return allUids.contains(uid);
}
- return allUids.contains(uid);
}
@Override
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 6bb56c9..e885c14 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -79,6 +79,7 @@
sSecureSettingToTypeMap.put(Settings.Secure.MULTI_PRESS_TIMEOUT, int.class);
sSecureSettingToTypeMap.put(Settings.Secure.KEY_REPEAT_TIMEOUT_MS, int.class);
sSecureSettingToTypeMap.put(Settings.Secure.KEY_REPEAT_DELAY_MS, int.class);
+ sSecureSettingToTypeMap.put(Settings.Secure.KEY_REPEAT_ENABLED, int.class);
sSecureSettingToTypeMap.put(Settings.Secure.STYLUS_POINTER_ICON_ENABLED, int.class);
// add other secure settings here...
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index d6f04db..1bcf825 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -1,16 +1,24 @@
# Applications & Processes
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
+per-file ActivityManager* = file:/ACTIVITY_MANAGER_OWNERS
+per-file ActiveServices.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file ProcessList.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file ActivityThread.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file ProcessRecord.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file SystemServer.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file ServiceRecord.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file AppProfiler.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file ProcessStateRecord.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file ProcessServiceRecord.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file ForegroundServiceTypeLoggerModule.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file AppRestrictionController.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file ProcessErrorStateRecord.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file ProcessProfileRecord.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file ConnectionRecord.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file UidRecord.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file IntentBindRecord.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file AppFGSTracker.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file FgsTempAllowList.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file HostingRecord.java = file:/ACTIVITY_MANAGER_OWNERS
# Windows & Activities
[email protected]
@@ -20,24 +28,19 @@
per-file AccessCheckDelegateHelper.java = file:/core/java/android/permission/OWNERS
# Battery Stats
[email protected]
+per-file AppBatteryTracker.java = file:/BATTERY_STATS_OWNERS
per-file BatteryStats* = file:/BATTERY_STATS_OWNERS
per-file BatteryExternalStats* = file:/BATTERY_STATS_OWNERS
-# Londoners
[email protected]
[email protected]
-
# Voice Interaction
per-file *Assist* = file:/core/java/android/service/voice/OWNERS
per-file *Voice* = file:/core/java/android/service/voice/OWNERS
-per-file SettingsToPropertiesMapper.java = [email protected], [email protected], [email protected], [email protected], [email protected]
+# Content Provider
+per-file ContentProvider* = [email protected], [email protected]
-per-file CarUserSwitchingDialog.java = file:platform/packages/services/Car:/OWNERS
-
-per-file ContentProviderHelper.java = [email protected], [email protected], [email protected], [email protected]
-
+# Cached App Freezer
+per-file ProcessCachedOptimizerRecord.java = file:/PERFORMANCE_OWNERS
per-file CachedAppOptimizer.java = file:/PERFORMANCE_OWNERS
per-file Freezer.java = file:/PERFORMANCE_OWNERS
@@ -46,3 +49,23 @@
# Broadcasts
per-file Broadcast* = file:/BROADCASTS_OWNERS
+
+# Permissions & Packages
+per-file *Permission* = [email protected]
+per-file *Package* = [email protected]
+
+# OOM Adjuster
+per-file *Oom* = file:/OOM_ADJUSTER_OWNERS
+
+# Miscellaneous
+per-file SettingsToPropertiesMapper.java = [email protected], [email protected], [email protected], [email protected], [email protected]
+per-file CarUserSwitchingDialog.java = file:platform/packages/services/Car:/OWNERS
+
+# Londoners
[email protected] #{LAST_RESORT_SUGGESTION}
[email protected] #{LAST_RESORT_SUGGESTION}
+
+# Default
[email protected] #{LAST_RESORT_SUGGESTION}
[email protected] #{LAST_RESORT_SUGGESTION}
[email protected] #{LAST_RESORT_SUGGESTION}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 22ec790..78a0a11 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -3617,14 +3617,12 @@
if (changes != 0) {
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
"Changes in " + app + ": " + changes);
- ActivityManagerService.ProcessChangeItem item =
- mProcessList.enqueueProcessChangeItemLocked(app.getPid(), app.info.uid);
- item.changes |= changes;
- item.foregroundActivities = state.hasRepForegroundActivities();
+ mProcessList.enqueueProcessChangeItemLocked(app.getPid(), app.info.uid,
+ changes, state.hasRepForegroundActivities());
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "Item " + Integer.toHexString(System.identityHashCode(item))
- + " " + app.toShortString() + ": changes=" + item.changes
- + " foreground=" + item.foregroundActivities
+ "Enqueued process change item for "
+ + app.toShortString() + ": changes=" + changes
+ + " foreground=" + state.hasRepForegroundActivities()
+ " type=" + state.getAdjType() + " source=" + state.getAdjSource()
+ " target=" + state.getAdjTarget());
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 00250b4..a93ae72 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -4998,53 +4998,70 @@
}
@GuardedBy("mService")
- ProcessChangeItem enqueueProcessChangeItemLocked(int pid, int uid) {
+ void enqueueProcessChangeItemLocked(int pid, int uid, int changes, int foregroundServicetypes) {
synchronized (mProcessChangeLock) {
- int i = mPendingProcessChanges.size() - 1;
- ActivityManagerService.ProcessChangeItem item = null;
- while (i >= 0) {
- item = mPendingProcessChanges.get(i);
- if (item.pid == pid) {
- if (DEBUG_PROCESS_OBSERVERS) {
- Slog.i(TAG_PROCESS_OBSERVERS, "Re-using existing item: " + item);
- }
- break;
- }
- i--;
- }
-
- if (i < 0) {
- // No existing item in pending changes; need a new one.
- final int num = mAvailProcessChanges.size();
- if (num > 0) {
- item = mAvailProcessChanges.remove(num - 1);
- if (DEBUG_PROCESS_OBSERVERS) {
- Slog.i(TAG_PROCESS_OBSERVERS, "Retrieving available item: " + item);
- }
- } else {
- item = new ActivityManagerService.ProcessChangeItem();
- if (DEBUG_PROCESS_OBSERVERS) {
- Slog.i(TAG_PROCESS_OBSERVERS, "Allocating new item: " + item);
- }
- }
- item.changes = 0;
- item.pid = pid;
- item.uid = uid;
- if (mPendingProcessChanges.size() == 0) {
- if (DEBUG_PROCESS_OBSERVERS) {
- Slog.i(TAG_PROCESS_OBSERVERS, "*** Enqueueing dispatch processes changed!");
- }
- mService.mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG)
- .sendToTarget();
- }
- mPendingProcessChanges.add(item);
- }
-
- return item;
+ final ProcessChangeItem item = enqueueProcessChangeItemLocked(pid, uid);
+ item.changes |= changes;
+ item.foregroundServiceTypes = foregroundServicetypes;
}
}
@GuardedBy("mService")
+ void enqueueProcessChangeItemLocked(int pid, int uid, int changes,
+ boolean hasForegroundActivities) {
+ synchronized (mProcessChangeLock) {
+ final ProcessChangeItem item = enqueueProcessChangeItemLocked(pid, uid);
+ item.changes |= changes;
+ item.foregroundActivities = hasForegroundActivities;
+ }
+ }
+
+ @GuardedBy({"mService", "mProcessChangeLock"})
+ private ProcessChangeItem enqueueProcessChangeItemLocked(int pid, int uid) {
+ int i = mPendingProcessChanges.size() - 1;
+ ActivityManagerService.ProcessChangeItem item = null;
+ while (i >= 0) {
+ item = mPendingProcessChanges.get(i);
+ if (item.pid == pid) {
+ if (DEBUG_PROCESS_OBSERVERS) {
+ Slog.i(TAG_PROCESS_OBSERVERS, "Re-using existing item: " + item);
+ }
+ break;
+ }
+ i--;
+ }
+
+ if (i < 0) {
+ // No existing item in pending changes; need a new one.
+ final int num = mAvailProcessChanges.size();
+ if (num > 0) {
+ item = mAvailProcessChanges.remove(num - 1);
+ if (DEBUG_PROCESS_OBSERVERS) {
+ Slog.i(TAG_PROCESS_OBSERVERS, "Retrieving available item: " + item);
+ }
+ } else {
+ item = new ActivityManagerService.ProcessChangeItem();
+ if (DEBUG_PROCESS_OBSERVERS) {
+ Slog.i(TAG_PROCESS_OBSERVERS, "Allocating new item: " + item);
+ }
+ }
+ item.changes = 0;
+ item.pid = pid;
+ item.uid = uid;
+ if (mPendingProcessChanges.size() == 0) {
+ if (DEBUG_PROCESS_OBSERVERS) {
+ Slog.i(TAG_PROCESS_OBSERVERS, "*** Enqueueing dispatch processes changed!");
+ }
+ mService.mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG)
+ .sendToTarget();
+ }
+ mPendingProcessChanges.add(item);
+ }
+
+ return item;
+ }
+
+ @GuardedBy("mService")
void scheduleDispatchProcessDiedLocked(int pid, int uid) {
synchronized (mProcessChangeLock) {
for (int i = mPendingProcessChanges.size() - 1; i >= 0; i--) {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index b186eaa..262c76e 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -156,6 +156,9 @@
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@@ -223,18 +226,9 @@
private static final int USER_SWITCH_CALLBACKS_TIMEOUT_MS = 5 * 1000;
/**
- * Amount of time waited for
- * {@link ActivityTaskManagerInternal.ScreenObserver#onKeyguardStateChanged} callbacks to be
- * called after calling {@link WindowManagerService#lockDeviceNow}.
- * Otherwise, we should throw a {@link RuntimeException} and never dismiss the
- * {@link UserSwitchingDialog}.
- */
- static final int SHOW_KEYGUARD_TIMEOUT_MS = 20 * 1000;
-
- /**
* Amount of time waited for {@link WindowManagerService#dismissKeyguard} callbacks to be
* called after dismissing the keyguard.
- * Otherwise, we should move on to dismiss the dialog {@link #dismissUserSwitchDialog}}
+ * Otherwise, we should move on to dismiss the dialog {@link #dismissUserSwitchDialog()}
* and report user switch is complete {@link #REPORT_USER_SWITCH_COMPLETE_MSG}.
*/
private static final int DISMISS_KEYGUARD_TIMEOUT_MS = 2 * 1000;
@@ -1986,10 +1980,18 @@
// it should be moved outside, but for now it's not as there are many calls to
// external components here afterwards
updateProfileRelatedCaches();
+ dispatchOnBeforeUserSwitching(userId);
mInjector.getWindowManager().setCurrentUser(userId);
mInjector.reportCurWakefulnessUsageEvent();
+ // Once the internal notion of the active user has switched, we lock the device
+ // with the option to show the user switcher on the keyguard.
if (userSwitchUiEnabled) {
mInjector.getWindowManager().setSwitchingUser(true);
+ // Only lock if the user has a secure keyguard PIN/Pattern/Pwd
+ if (mInjector.getKeyguardManager().isDeviceSecure(userId)) {
+ // Make sure the device is locked before moving on with the user switch
+ mInjector.lockDeviceNowAndWaitForKeyguardShown();
+ }
}
} else {
@@ -2284,6 +2286,25 @@
mUserSwitchObservers.finishBroadcast();
}
+ private void dispatchOnBeforeUserSwitching(@UserIdInt int newUserId) {
+ final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
+ t.traceBegin("dispatchOnBeforeUserSwitching-" + newUserId);
+ final int observerCount = mUserSwitchObservers.beginBroadcast();
+ for (int i = 0; i < observerCount; i++) {
+ final String name = "#" + i + " " + mUserSwitchObservers.getBroadcastCookie(i);
+ t.traceBegin("onBeforeUserSwitching-" + name);
+ try {
+ mUserSwitchObservers.getBroadcastItem(i).onBeforeUserSwitching(newUserId);
+ } catch (RemoteException e) {
+ // Ignore
+ } finally {
+ t.traceEnd();
+ }
+ }
+ mUserSwitchObservers.finishBroadcast();
+ t.traceEnd();
+ }
+
/** Called on handler thread */
@VisibleForTesting
void dispatchUserSwitchComplete(@UserIdInt int oldUserId, @UserIdInt int newUserId) {
@@ -2499,17 +2520,6 @@
final int observerCount = mUserSwitchObservers.beginBroadcast();
if (observerCount > 0) {
- for (int i = 0; i < observerCount; i++) {
- final String name = "#" + i + " " + mUserSwitchObservers.getBroadcastCookie(i);
- t.traceBegin("onBeforeUserSwitching-" + name);
- try {
- mUserSwitchObservers.getBroadcastItem(i).onBeforeUserSwitching(newUserId);
- } catch (RemoteException e) {
- // Ignore
- } finally {
- t.traceEnd();
- }
- }
final ArraySet<String> curWaitingUserSwitchCallbacks = new ArraySet<>();
synchronized (mLock) {
uss.switching = true;
@@ -2606,56 +2616,34 @@
@VisibleForTesting
void completeUserSwitch(int oldUserId, int newUserId) {
- final Runnable sendUserSwitchCompleteMessage = () -> {
- mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
- mHandler.sendMessage(mHandler.obtainMessage(
- REPORT_USER_SWITCH_COMPLETE_MSG, oldUserId, newUserId));
- };
- if (isUserSwitchUiEnabled()) {
- if (mInjector.getKeyguardManager().isDeviceSecure(newUserId)) {
- this.showKeyguard(() -> dismissUserSwitchDialog(sendUserSwitchCompleteMessage));
- } else {
- this.dismissKeyguard(() -> dismissUserSwitchDialog(sendUserSwitchCompleteMessage));
- }
+ final boolean isUserSwitchUiEnabled = isUserSwitchUiEnabled();
+ // serialize each conditional step
+ await(
+ // STEP 1 - If there is no challenge set, dismiss the keyguard right away
+ isUserSwitchUiEnabled && !mInjector.getKeyguardManager().isDeviceSecure(newUserId),
+ mInjector::dismissKeyguard,
+ () -> await(
+ // STEP 2 - If user switch ui was enabled, dismiss user switch dialog
+ isUserSwitchUiEnabled,
+ this::dismissUserSwitchDialog,
+ () -> {
+ // STEP 3 - Send REPORT_USER_SWITCH_COMPLETE_MSG to broadcast
+ // ACTION_USER_SWITCHED & call UserSwitchObservers.onUserSwitchComplete
+ mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
+ mHandler.sendMessage(mHandler.obtainMessage(
+ REPORT_USER_SWITCH_COMPLETE_MSG, oldUserId, newUserId));
+ }
+ ));
+ }
+
+ private void await(boolean condition, Consumer<Runnable> conditionalStep, Runnable nextStep) {
+ if (condition) {
+ conditionalStep.accept(nextStep);
} else {
- sendUserSwitchCompleteMessage.run();
+ nextStep.run();
}
}
- protected void showKeyguard(Runnable runnable) {
- runWithTimeout(mInjector::showKeyguard, SHOW_KEYGUARD_TIMEOUT_MS, runnable, () -> {
- throw new RuntimeException(
- "Keyguard is not shown in " + SHOW_KEYGUARD_TIMEOUT_MS + " ms.");
- }, "showKeyguard");
- }
-
- protected void dismissKeyguard(Runnable runnable) {
- runWithTimeout(mInjector::dismissKeyguard, DISMISS_KEYGUARD_TIMEOUT_MS, runnable, runnable,
- "dismissKeyguard");
- }
-
- private void runWithTimeout(Consumer<Runnable> task, int timeoutMs, Runnable onSuccess,
- Runnable onTimeout, String traceMsg) {
- final AtomicInteger state = new AtomicInteger(0); // state = 0 (RUNNING)
-
- asyncTraceBegin(traceMsg, 0);
-
- mHandler.postDelayed(() -> {
- if (state.compareAndSet(0, 1)) { // state = 1 (TIMEOUT)
- asyncTraceEnd(traceMsg, 0);
- Slogf.w(TAG, "Timeout: %s did not finish in %d ms", traceMsg, timeoutMs);
- onTimeout.run();
- }
- }, timeoutMs);
-
- task.accept(() -> {
- if (state.compareAndSet(0, 2)) { // state = 2 (SUCCESS)
- asyncTraceEnd(traceMsg, 0);
- onSuccess.run();
- }
- });
- }
-
private void moveUserToForeground(UserState uss, int newUserId) {
boolean homeInFront = mInjector.taskSupervisorSwitchUser(newUserId, uss);
if (homeInFront) {
@@ -4100,45 +4088,29 @@
return IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
}
- protected void showKeyguard(Runnable runnable) {
- if (getWindowManager().isKeyguardLocked()) {
- runnable.run();
- return;
- }
- getActivityTaskManagerInternal().registerScreenObserver(
- new ActivityTaskManagerInternal.ScreenObserver() {
- @Override
- public void onAwakeStateChanged(boolean isAwake) {
-
- }
-
- @Override
- public void onKeyguardStateChanged(boolean isShowing) {
- if (isShowing) {
- getActivityTaskManagerInternal().unregisterScreenObserver(this);
- runnable.run();
- }
- }
- }
- );
- getWindowManager().lockDeviceNow();
- }
-
protected void dismissKeyguard(Runnable runnable) {
+ final AtomicBoolean isFirst = new AtomicBoolean(true);
+ final Runnable runOnce = () -> {
+ if (isFirst.getAndSet(false)) {
+ runnable.run();
+ }
+ };
+
+ mHandler.postDelayed(runOnce, DISMISS_KEYGUARD_TIMEOUT_MS);
getWindowManager().dismissKeyguard(new IKeyguardDismissCallback.Stub() {
@Override
public void onDismissError() throws RemoteException {
- runnable.run();
+ mHandler.post(runOnce);
}
@Override
public void onDismissSucceeded() throws RemoteException {
- runnable.run();
+ mHandler.post(runOnce);
}
@Override
public void onDismissCancelled() throws RemoteException {
- runnable.run();
+ mHandler.post(runOnce);
}
}, /* message= */ null);
}
@@ -4164,5 +4136,43 @@
void onSystemUserVisibilityChanged(boolean visible) {
getUserManagerInternal().onSystemUserVisibilityChanged(visible);
}
+
+ void lockDeviceNowAndWaitForKeyguardShown() {
+ if (getWindowManager().isKeyguardLocked()) {
+ return;
+ }
+
+ final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
+ t.traceBegin("lockDeviceNowAndWaitForKeyguardShown");
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ ActivityTaskManagerInternal.ScreenObserver screenObserver =
+ new ActivityTaskManagerInternal.ScreenObserver() {
+ @Override
+ public void onAwakeStateChanged(boolean isAwake) {
+
+ }
+
+ @Override
+ public void onKeyguardStateChanged(boolean isShowing) {
+ if (isShowing) {
+ latch.countDown();
+ }
+ }
+ };
+
+ getActivityTaskManagerInternal().registerScreenObserver(screenObserver);
+ getWindowManager().lockDeviceNow();
+ try {
+ if (!latch.await(20, TimeUnit.SECONDS)) {
+ throw new RuntimeException("Keyguard is not shown in 20 seconds");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } finally {
+ getActivityTaskManagerInternal().unregisterScreenObserver(screenObserver);
+ t.traceEnd();
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 6ae6f3d..6af4be5 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -619,7 +619,7 @@
this.op = op;
this.uid = uid;
this.uidState = uidState;
- this.packageName = packageName;
+ this.packageName = packageName.intern();
// We keep an invariant that the persistent device will always have an entry in
// mDeviceAttributedOps.
mDeviceAttributedOps.put(PERSISTENT_DEVICE_ID_DEFAULT,
@@ -1031,7 +1031,7 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- String pkgName = intent.getData().getEncodedSchemeSpecificPart();
+ String pkgName = intent.getData().getEncodedSchemeSpecificPart().intern();
int uid = intent.getIntExtra(Intent.EXTRA_UID, Process.INVALID_UID);
if (action.equals(ACTION_PACKAGE_ADDED)
@@ -1235,7 +1235,7 @@
Ops ops = uidState.pkgOps.get(packageName);
if (ops == null) {
ops = new Ops(packageName, uidState);
- uidState.pkgOps.put(packageName, ops);
+ uidState.pkgOps.put(packageName.intern(), ops);
}
SparseIntArray packageModes =
@@ -4739,7 +4739,7 @@
return null;
}
ops = new Ops(packageName, uidState);
- uidState.pkgOps.put(packageName, ops);
+ uidState.pkgOps.put(packageName.intern(), ops);
}
if (edit) {
@@ -5076,7 +5076,7 @@
Ops ops = uidState.pkgOps.get(pkgName);
if (ops == null) {
ops = new Ops(pkgName, uidState);
- uidState.pkgOps.put(pkgName, ops);
+ uidState.pkgOps.put(pkgName.intern(), ops);
}
ops.put(op.op, op);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 99404428..df69afe 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -10809,7 +10809,8 @@
//TODO move inside HardeningEnforcer after refactor that moves permission checks
// in the blockFocusMethod
if (permissionOverridesCheck) {
- mHardeningEnforcer.metricsLogFocusReq(/*blocked*/false, focusReqType, uid);
+ mHardeningEnforcer.metricsLogFocusReq(/*blocked*/ false, focusReqType, uid,
+ /*unblockedBySdk*/ false);
}
if (!permissionOverridesCheck && mHardeningEnforcer.blockFocusMethod(uid,
HardeningEnforcer.METHOD_AUDIO_MANAGER_REQUEST_AUDIO_FOCUS,
@@ -13383,19 +13384,39 @@
}
@android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING)
- /** @see AudioPolicy#getFocusStack() */
+ /* @see AudioPolicy#getFocusStack() */
public List<AudioFocusInfo> getFocusStack() {
super.getFocusStack_enforcePermission();
return mMediaFocusControl.getFocusStack();
}
- /** @see AudioPolicy#sendFocusLoss */
+ /**
+ * @param focusLoser non-null entry that may be in the stack
+ * @see AudioPolicy#sendFocusLossAndUpdate(AudioFocusInfo)
+ */
+ @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING)
+ public void sendFocusLossAndUpdate(@NonNull AudioFocusInfo focusLoser,
+ @NonNull IAudioPolicyCallback apcb) {
+ super.sendFocusLossAndUpdate_enforcePermission();
+ Objects.requireNonNull(apcb);
+ if (!mAudioPolicies.containsKey(apcb.asBinder())) {
+ throw new IllegalStateException("Only registered AudioPolicy can change focus");
+ }
+ if (!mAudioPolicies.get(apcb.asBinder()).mHasFocusListener) {
+ throw new IllegalStateException("AudioPolicy must have focus listener to change focus");
+ }
+
+ mMediaFocusControl.sendFocusLossAndUpdate(Objects.requireNonNull(focusLoser));
+ }
+
+ /* @see AudioPolicy#sendFocusLoss(AudioFocusInfo) */
+ @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING)
public boolean sendFocusLoss(@NonNull AudioFocusInfo focusLoser,
@NonNull IAudioPolicyCallback apcb) {
+ super.sendFocusLoss_enforcePermission();
Objects.requireNonNull(focusLoser);
Objects.requireNonNull(apcb);
- enforceModifyAudioRoutingPermission();
if (!mAudioPolicies.containsKey(apcb.asBinder())) {
throw new IllegalStateException("Only registered AudioPolicy can change focus");
}
diff --git a/services/core/java/com/android/server/audio/HardeningEnforcer.java b/services/core/java/com/android/server/audio/HardeningEnforcer.java
index faeba5d..6611110 100644
--- a/services/core/java/com/android/server/audio/HardeningEnforcer.java
+++ b/services/core/java/com/android/server/audio/HardeningEnforcer.java
@@ -168,6 +168,8 @@
}
boolean blocked = true;
+ // indicates the focus request was not blocked because of the SDK version
+ boolean unblockedBySdk = false;
if (noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, callingUid, packageName, attributionTag)) {
if (DEBUG) {
Slog.i(TAG, "blockFocusMethod pack:" + packageName + " NOT blocking");
@@ -179,9 +181,10 @@
+ targetSdk);
}
blocked = false;
+ unblockedBySdk = true;
}
- metricsLogFocusReq(blocked, focusReqType, callingUid);
+ metricsLogFocusReq(blocked, focusReqType, callingUid, unblockedBySdk);
if (!blocked) {
return false;
@@ -195,7 +198,16 @@
return true;
}
- /*package*/ void metricsLogFocusReq(boolean blocked, int focusReq, int callingUid) {
+ /**
+ * Log metrics for the focus request
+ * @param blocked true if the call blocked
+ * @param focusReq the type of focus request
+ * @param callingUid the UID of the caller
+ * @param unblockedBySdk if blocked is false,
+ * true indicates it was unblocked thanks to an older SDK
+ */
+ /*package*/ void metricsLogFocusReq(boolean blocked, int focusReq, int callingUid,
+ boolean unblockedBySdk) {
final String metricId = blocked ? METRIC_COUNTERS_FOCUS_DENIAL.get(focusReq)
: METRIC_COUNTERS_FOCUS_GRANT.get(focusReq);
if (TextUtils.isEmpty(metricId)) {
@@ -204,6 +216,12 @@
}
try {
Counter.logIncrementWithUid(metricId, callingUid);
+ if (!blocked && unblockedBySdk) {
+ // additional metric to capture focus requests that are currently granted
+ // because the app is on an older SDK, but would have been blocked otherwise
+ Counter.logIncrementWithUid(
+ "media_audio.value_audio_focus_grant_hardening_waived_by_sdk", callingUid);
+ }
} catch (Exception e) {
Slog.e(TAG, "Counter error metricId:" + metricId + " for focus req:" + focusReq
+ " from uid:" + callingUid, e);
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index 7e26356..b4af46e 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -280,6 +280,37 @@
}
/**
+ * Like {@link #sendFocusLoss(AudioFocusInfo)} but if the loser was at the top of stack,
+ * make the next entry gain focus with {@link AudioManager#AUDIOFOCUS_GAIN}.
+ * @param focusInfo the focus owner to discard
+ * @see AudioPolicy#sendFocusLossAndUpdate(AudioFocusInfo)
+ */
+ protected void sendFocusLossAndUpdate(@NonNull AudioFocusInfo focusInfo) {
+ synchronized (mAudioFocusLock) {
+ if (mFocusStack.isEmpty()) {
+ return;
+ }
+ final FocusRequester currentFocusOwner = mFocusStack.peek();
+ if (currentFocusOwner.toAudioFocusInfo().equals(focusInfo)) {
+ // focus loss is for the top of the stack
+ currentFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS, null,
+ false /*forceDuck*/);
+ currentFocusOwner.release();
+
+ mFocusStack.pop();
+ // is there a new focus owner?
+ if (!mFocusStack.isEmpty()) {
+ mFocusStack.peek().handleFocusGain(AudioManager.AUDIOFOCUS_GAIN);
+ }
+ } else {
+ // focus loss if for another entry that's not at the top of the stack,
+ // just remove it from the stack and make it lose focus
+ sendFocusLoss(focusInfo);
+ }
+ }
+ }
+
+ /**
* Return a copy of the focus stack for external consumption (composed of AudioFocusInfo
* instead of FocusRequester instances)
* @return a SystemApi-friendly version of the focus stack, in the same order (last entry
diff --git a/services/core/java/com/android/server/cpu/CpuMonitorService.java b/services/core/java/com/android/server/cpu/CpuMonitorService.java
index 88ff7e4..2cadbc58 100644
--- a/services/core/java/com/android/server/cpu/CpuMonitorService.java
+++ b/services/core/java/com/android/server/cpu/CpuMonitorService.java
@@ -216,7 +216,7 @@
@Override
public void onBootPhase(int phase) {
- if (phase != PHASE_BOOT_COMPLETED) {
+ if (phase != PHASE_BOOT_COMPLETED || mHandler == null) {
return;
}
Slogf.i(TAG, "Stopping periodic cpuset reading on boot complete");
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamper.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamper.java
index cf44ac0..a1fd164 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamper.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamper.java
@@ -74,6 +74,5 @@
protected enum Type {
POWER,
- WEAR_BEDTIME_MODE,
}
}
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
index 9404034..a10094f 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
@@ -218,9 +218,7 @@
return BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
} else if (mClamperType == Type.POWER) {
return BrightnessInfo.BRIGHTNESS_MAX_REASON_POWER_IC;
- } else if (mClamperType == Type.WEAR_BEDTIME_MODE) {
- return BrightnessInfo.BRIGHTNESS_MAX_REASON_WEAR_BEDTIME_MODE;
- } else {
+ } else {
Slog.wtf(TAG, "BrightnessMaxReason not mapped for type=" + mClamperType);
return BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
}
@@ -350,10 +348,6 @@
data, currentBrightness));
}
}
- if (flags.isBrightnessWearBedtimeModeClamperEnabled()) {
- clampers.add(new BrightnessWearBedtimeModeClamper(handler, context,
- clamperChangeListener, data));
- }
return clampers;
}
@@ -362,6 +356,10 @@
DisplayDeviceData data) {
List<BrightnessStateModifier> modifiers = new ArrayList<>();
modifiers.add(new BrightnessThermalModifier(handler, listener, data));
+ if (flags.isBrightnessWearBedtimeModeClamperEnabled()) {
+ modifiers.add(new BrightnessWearBedtimeModeModifier(handler, context,
+ listener, data));
+ }
modifiers.add(new DisplayDimModifier(context));
modifiers.add(new BrightnessLowPowerModeModifier());
@@ -395,7 +393,7 @@
*/
public static class DisplayDeviceData implements BrightnessThermalModifier.ThermalData,
BrightnessPowerClamper.PowerData,
- BrightnessWearBedtimeModeClamper.WearBedtimeModeData {
+ BrightnessWearBedtimeModeModifier.WearBedtimeModeData {
@NonNull
private final String mUniqueDisplayId;
@NonNull
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeClamper.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeClamper.java
deleted file mode 100644
index 1902e35..0000000
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeClamper.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.display.brightness.clamper;
-
-import android.annotation.NonNull;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-public class BrightnessWearBedtimeModeClamper extends
- BrightnessClamper<BrightnessWearBedtimeModeClamper.WearBedtimeModeData> {
-
- public static final int BEDTIME_MODE_OFF = 0;
- public static final int BEDTIME_MODE_ON = 1;
-
- private final Context mContext;
-
- private final ContentObserver mSettingsObserver;
-
- BrightnessWearBedtimeModeClamper(Handler handler, Context context,
- BrightnessClamperController.ClamperChangeListener listener, WearBedtimeModeData data) {
- this(new Injector(), handler, context, listener, data);
- }
-
- @VisibleForTesting
- BrightnessWearBedtimeModeClamper(Injector injector, Handler handler, Context context,
- BrightnessClamperController.ClamperChangeListener listener, WearBedtimeModeData data) {
- super(handler, listener);
- mContext = context;
- mBrightnessCap = data.getBrightnessWearBedtimeModeCap();
- mSettingsObserver = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- final int bedtimeModeSetting = Settings.Global.getInt(
- mContext.getContentResolver(),
- Settings.Global.Wearable.BEDTIME_MODE,
- BEDTIME_MODE_OFF);
- mIsActive = bedtimeModeSetting == BEDTIME_MODE_ON;
- mChangeListener.onChanged();
- }
- };
- injector.registerBedtimeModeObserver(context.getContentResolver(), mSettingsObserver);
- }
-
- @NonNull
- @Override
- Type getType() {
- return Type.WEAR_BEDTIME_MODE;
- }
-
- @Override
- void onDeviceConfigChanged() {}
-
- @Override
- void onDisplayChanged(WearBedtimeModeData displayData) {
- mHandler.post(() -> {
- mBrightnessCap = displayData.getBrightnessWearBedtimeModeCap();
- mChangeListener.onChanged();
- });
- }
-
- @Override
- void stop() {
- mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
- }
-
- interface WearBedtimeModeData {
- float getBrightnessWearBedtimeModeCap();
- }
-
- @VisibleForTesting
- static class Injector {
- void registerBedtimeModeObserver(@NonNull ContentResolver cr,
- @NonNull ContentObserver observer) {
- cr.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.Wearable.BEDTIME_MODE),
- /* notifyForDescendants= */ false, observer, UserHandle.USER_ALL);
- }
- }
-}
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeModifier.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeModifier.java
new file mode 100644
index 0000000..c9c8c33
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeModifier.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.clamper;
+
+import android.annotation.NonNull;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.hardware.display.BrightnessInfo;
+import android.hardware.display.DisplayManagerInternal;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.BrightnessReason;
+
+import java.io.PrintWriter;
+
+public class BrightnessWearBedtimeModeModifier implements BrightnessStateModifier,
+ BrightnessClamperController.DisplayDeviceDataListener,
+ BrightnessClamperController.StatefulModifier {
+
+ public static final int BEDTIME_MODE_OFF = 0;
+ public static final int BEDTIME_MODE_ON = 1;
+
+ private final Context mContext;
+
+ private final ContentObserver mSettingsObserver;
+ protected final Handler mHandler;
+ protected final BrightnessClamperController.ClamperChangeListener mChangeListener;
+
+ private float mBrightnessCap;
+ private boolean mIsActive = false;
+ private boolean mApplied = false;
+
+ BrightnessWearBedtimeModeModifier(Handler handler, Context context,
+ BrightnessClamperController.ClamperChangeListener listener, WearBedtimeModeData data) {
+ this(new Injector(), handler, context, listener, data);
+ }
+
+ @VisibleForTesting
+ BrightnessWearBedtimeModeModifier(Injector injector, Handler handler, Context context,
+ BrightnessClamperController.ClamperChangeListener listener, WearBedtimeModeData data) {
+ mHandler = handler;
+ mChangeListener = listener;
+ mContext = context;
+ mBrightnessCap = data.getBrightnessWearBedtimeModeCap();
+ mSettingsObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ final int bedtimeModeSetting = Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.Wearable.BEDTIME_MODE,
+ BEDTIME_MODE_OFF);
+ mIsActive = bedtimeModeSetting == BEDTIME_MODE_ON;
+ mChangeListener.onChanged();
+ }
+ };
+ injector.registerBedtimeModeObserver(context.getContentResolver(), mSettingsObserver);
+ }
+
+ //region BrightnessStateModifier
+ @Override
+ public void apply(DisplayManagerInternal.DisplayPowerRequest request,
+ DisplayBrightnessState.Builder stateBuilder) {
+ if (mIsActive && stateBuilder.getMaxBrightness() > mBrightnessCap) {
+ stateBuilder.setMaxBrightness(mBrightnessCap);
+ stateBuilder.setBrightness(Math.min(stateBuilder.getBrightness(), mBrightnessCap));
+ stateBuilder.setBrightnessMaxReason(
+ BrightnessInfo.BRIGHTNESS_MAX_REASON_WEAR_BEDTIME_MODE);
+ stateBuilder.getBrightnessReason().addModifier(BrightnessReason.MODIFIER_THROTTLED);
+ // set fast change only when modifier is activated.
+ // this will allow auto brightness to apply slow change even when modifier is active
+ if (!mApplied) {
+ stateBuilder.setIsSlowChange(false);
+ }
+ mApplied = true;
+ } else {
+ mApplied = false;
+ }
+ }
+
+ @Override
+ public void stop() {
+ mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
+ }
+
+ @Override
+ public void dump(PrintWriter writer) {
+ writer.println("BrightnessWearBedtimeModeModifier:");
+ writer.println(" mBrightnessCap: " + mBrightnessCap);
+ writer.println(" mIsActive: " + mIsActive);
+ writer.println(" mApplied: " + mApplied);
+ }
+
+ @Override
+ public boolean shouldListenToLightSensor() {
+ return false;
+ }
+
+ @Override
+ public void setAmbientLux(float lux) {
+ // noop
+ }
+ //endregion
+
+ //region DisplayDeviceDataListener
+ @Override
+ public void onDisplayChanged(BrightnessClamperController.DisplayDeviceData data) {
+ mHandler.post(() -> {
+ mBrightnessCap = data.getBrightnessWearBedtimeModeCap();
+ mChangeListener.onChanged();
+ });
+ }
+ //endregion
+
+ //region StatefulModifier
+ @Override
+ public void applyStateChange(
+ BrightnessClamperController.ModifiersAggregatedState aggregatedState) {
+ if (mIsActive && aggregatedState.mMaxBrightness > mBrightnessCap) {
+ aggregatedState.mMaxBrightness = mBrightnessCap;
+ aggregatedState.mMaxBrightnessReason =
+ BrightnessInfo.BRIGHTNESS_MAX_REASON_WEAR_BEDTIME_MODE;
+ }
+ }
+ //endregion
+
+ interface WearBedtimeModeData {
+ float getBrightnessWearBedtimeModeCap();
+ }
+
+ @VisibleForTesting
+ static class Injector {
+ void registerBedtimeModeObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer) {
+ cr.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.Wearable.BEDTIME_MODE),
+ /* notifyForDescendants= */ false, observer, UserHandle.USER_ALL);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 5696fba..f2e2f65 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -1207,9 +1207,11 @@
@Override
public void onValues(int result, short addr) {
- if (result == Result.SUCCESS) {
- synchronized (mLock) {
- mPhysicalAddress = new Short(addr).intValue();
+ synchronized (mLock) {
+ if (result == Result.SUCCESS) {
+ mPhysicalAddress = Short.toUnsignedInt(addr);
+ } else {
+ mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
}
}
}
@@ -1605,9 +1607,11 @@
@Override
public void onValues(int result, short addr) {
- if (result == Result.SUCCESS) {
- synchronized (mLock) {
- mPhysicalAddress = new Short(addr).intValue();
+ synchronized (mLock) {
+ if (result == Result.SUCCESS) {
+ mPhysicalAddress = Short.toUnsignedInt(addr);
+ } else {
+ mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
}
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index ac75ef7..8e41d18 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1688,7 +1688,11 @@
private void sendCecCommandWithRetries(HdmiCecMessage command,
@Nullable SendMessageCallback callback) {
assertRunOnServiceThread();
- HdmiCecLocalDevice localDevice = getAllCecLocalDevices().get(0);
+ List<HdmiCecLocalDevice> devices = getAllCecLocalDevices();
+ if (devices.isEmpty()) {
+ return;
+ }
+ HdmiCecLocalDevice localDevice = devices.get(0);
if (localDevice != null) {
sendCecCommandWithoutRetries(command, new SendMessageCallback() {
@Override
diff --git a/services/core/java/com/android/server/input/InputManagerInternal.java b/services/core/java/com/android/server/input/InputManagerInternal.java
index 73f18d1..9281267 100644
--- a/services/core/java/com/android/server/input/InputManagerInternal.java
+++ b/services/core/java/com/android/server/input/InputManagerInternal.java
@@ -232,6 +232,9 @@
/**
* Notify key gesture was completed by the user.
*
+ * NOTE: This is a temporary API added to assist in a long-term refactor, and is not meant for
+ * general use by system services.
+ *
* @param deviceId the device ID of the keyboard using which the event was completed
* @param keycodes the keys pressed for the event
* @param modifierState the modifier state
@@ -240,4 +243,20 @@
*/
public abstract void notifyKeyGestureCompleted(int deviceId, int[] keycodes, int modifierState,
@KeyGestureEvent.KeyGestureType int event);
+
+ /**
+ * Notify that a key gesture was detected by another system component, and it should be handled
+ * appropriately by KeyGestureController.
+ *
+ * NOTE: This is a temporary API added to assist in a long-term refactor, and is not meant for
+ * general use by system services.
+ *
+ * @param deviceId the device ID of the keyboard using which the event was completed
+ * @param keycodes the keys pressed for the event
+ * @param modifierState the modifier state
+ * @param event the gesture event that was completed
+ *
+ */
+ public abstract void handleKeyGestureInKeyGestureController(int deviceId, int[] keycodes,
+ int modifierState, @KeyGestureEvent.KeyGestureType int event);
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index edc35e5..fd7479e 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -456,6 +456,14 @@
void registerLocalService(InputManagerInternal localService) {
LocalServices.addService(InputManagerInternal.class, localService);
}
+
+ KeyboardBacklightControllerInterface getKeyboardBacklightController(
+ NativeInputManagerService nativeService, PersistentDataStore dataStore) {
+ return InputFeatureFlagProvider.isKeyboardBacklightControlEnabled()
+ ? new KeyboardBacklightController(mContext, nativeService, dataStore,
+ mLooper, mUEventManager)
+ : new KeyboardBacklightControllerInterface() {};
+ }
}
public InputManagerService(Context context) {
@@ -479,10 +487,7 @@
injector.getLooper(), this) : null;
mBatteryController = new BatteryController(mContext, mNative, injector.getLooper(),
injector.getUEventManager());
- mKeyboardBacklightController = InputFeatureFlagProvider.isKeyboardBacklightControlEnabled()
- ? new KeyboardBacklightController(mContext, mNative, mDataStore,
- injector.getLooper(), injector.getUEventManager())
- : new KeyboardBacklightControllerInterface() {};
+ mKeyboardBacklightController = injector.getKeyboardBacklightController(mNative, mDataStore);
mStickyModifierStateController = new StickyModifierStateController();
mKeyGestureController = new KeyGestureController(mContext, injector.getLooper());
mKeyboardLedController = new KeyboardLedController(mContext, injector.getLooper(),
@@ -606,6 +611,8 @@
mKeyRemapper.systemRunning();
mPointerIconCache.systemRunning();
mKeyboardGlyphManager.systemRunning();
+
+ initKeyGestures();
}
private void reloadDeviceAliases() {
@@ -2504,6 +2511,59 @@
null, null, null) == PERMISSION_GRANTED;
}
+ private void initKeyGestures() {
+ if (!useKeyGestureEventHandler()) {
+ return;
+ }
+ InputManager im = Objects.requireNonNull(mContext.getSystemService(InputManager.class));
+ im.registerKeyGestureEventHandler(new InputManager.KeyGestureEventHandler() {
+ @Override
+ public boolean handleKeyGestureEvent(@NonNull KeyGestureEvent event,
+ @Nullable IBinder focussedToken) {
+ int deviceId = event.getDeviceId();
+ boolean complete = event.getAction() == KeyGestureEvent.ACTION_GESTURE_COMPLETE
+ && !event.isCancelled();
+ switch (event.getKeyGestureType()) {
+ case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP:
+ if (complete) {
+ mKeyboardBacklightController.incrementKeyboardBacklight(deviceId);
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN:
+ if (complete) {
+ mKeyboardBacklightController.decrementKeyboardBacklight(deviceId);
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
+ // TODO(b/367748270): Add functionality to turn keyboard backlight on/off.
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK:
+ if (complete) {
+ mNative.toggleCapsLock(deviceId);
+ }
+ return true;
+ default:
+ return false;
+
+ }
+ }
+
+ @Override
+ public boolean isKeyGestureSupported(int gestureType) {
+ switch (gestureType) {
+ case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK:
+ return true;
+ default:
+ return false;
+
+ }
+ }
+ });
+ }
+
// Native callback.
@SuppressWarnings("unused")
private KeyEvent dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags) {
@@ -3207,6 +3267,8 @@
mKeyboardBacklightController.onInteractiveChanged(interactive);
}
+ // TODO(b/358569822): Remove this method from InputManagerInternal after key gesture
+ // handler refactoring complete
@Override
public void toggleCapsLock(int deviceId) {
mNative.toggleCapsLock(deviceId);
@@ -3294,11 +3356,15 @@
mKeyboardBacklightController.notifyUserActivity();
}
+ // TODO(b/358569822): Remove this method from InputManagerInternal after key gesture
+ // handler refactoring complete
@Override
public void incrementKeyboardBacklight(int deviceId) {
mKeyboardBacklightController.incrementKeyboardBacklight(deviceId);
}
+ // TODO(b/358569822): Remove this method from InputManagerInternal after key gesture
+ // handler refactoring complete
@Override
public void decrementKeyboardBacklight(int deviceId) {
mKeyboardBacklightController.decrementKeyboardBacklight(deviceId);
@@ -3342,6 +3408,12 @@
mKeyGestureController.notifyKeyGestureCompleted(deviceId, keycodes, modifierState,
gestureType);
}
+
+ @Override
+ public void handleKeyGestureInKeyGestureController(int deviceId, int[] keycodes,
+ int modifierState, @KeyGestureEvent.KeyGestureType int gestureType) {
+ mKeyGestureController.handleKeyGesture(deviceId, keycodes, modifierState, gestureType);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index 835fb72..d70bd8b 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -94,6 +94,8 @@
(reason) -> updateKeyRepeatInfo()),
Map.entry(Settings.Secure.getUriFor(Settings.Secure.KEY_REPEAT_DELAY_MS),
(reason) -> updateKeyRepeatInfo()),
+ Map.entry(Settings.Secure.getUriFor(Settings.Secure.KEY_REPEAT_ENABLED),
+ (reason) -> updateKeyRepeatInfo()),
Map.entry(Settings.System.getUriFor(Settings.System.SHOW_ROTARY_INPUT),
(reason) -> updateShowRotaryInput()),
Map.entry(Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS),
@@ -230,6 +232,11 @@
}
private void updateKeyRepeatInfo() {
+ // Key repeat is enabled by default
+ final boolean keyRepeatEnabled = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(), Settings.Secure.KEY_REPEAT_ENABLED, 1,
+ UserHandle.USER_CURRENT) != 0;
+
// Use ViewConfiguration getters only as fallbacks because they may return stale values.
final int timeoutMs = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.KEY_REPEAT_TIMEOUT_MS, ViewConfiguration.getKeyRepeatTimeout(),
@@ -237,7 +244,7 @@
final int delayMs = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.KEY_REPEAT_DELAY_MS, ViewConfiguration.getKeyRepeatDelay(),
UserHandle.USER_CURRENT);
- mNative.setKeyRepeatConfiguration(timeoutMs, delayMs);
+ mNative.setKeyRepeatConfiguration(timeoutMs, delayMs, keyRepeatEnabled);
}
private void updateMaximumObscuringOpacityForTouch() {
diff --git a/services/core/java/com/android/server/input/KeyGestureController.java b/services/core/java/com/android/server/input/KeyGestureController.java
index 7fe7891..4538b49 100644
--- a/services/core/java/com/android/server/input/KeyGestureController.java
+++ b/services/core/java/com/android/server/input/KeyGestureController.java
@@ -24,7 +24,6 @@
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
-
import android.hardware.input.AidlKeyGestureEvent;
import android.hardware.input.IKeyGestureEventListener;
import android.hardware.input.IKeyGestureHandler;
@@ -582,8 +581,11 @@
boolean handleKeyGesture(int deviceId, int[] keycodes, int modifierState,
@KeyGestureEvent.KeyGestureType int gestureType, int action, int displayId,
IBinder focusedToken, int flags) {
- AidlKeyGestureEvent event = createKeyGestureEvent(deviceId, keycodes,
- modifierState, gestureType, action, displayId, flags);
+ return handleKeyGesture(createKeyGestureEvent(deviceId, keycodes,
+ modifierState, gestureType, action, displayId, flags), focusedToken);
+ }
+
+ private boolean handleKeyGesture(AidlKeyGestureEvent event, @Nullable IBinder focusedToken) {
synchronized (mKeyGestureHandlerRecords) {
for (KeyGestureHandlerRecord handler : mKeyGestureHandlerRecords.values()) {
if (handler.handleKeyGesture(event, focusedToken)) {
@@ -616,6 +618,13 @@
mHandler.obtainMessage(MSG_NOTIFY_KEY_GESTURE_EVENT, event).sendToTarget();
}
+ public void handleKeyGesture(int deviceId, int[] keycodes, int modifierState,
+ @KeyGestureEvent.KeyGestureType int gestureType) {
+ AidlKeyGestureEvent event = createKeyGestureEvent(deviceId, keycodes, modifierState,
+ gestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, Display.DEFAULT_DISPLAY, 0);
+ handleKeyGesture(event, null /*focusedToken*/);
+ }
+
@MainThread
private void notifyKeyGestureEvent(AidlKeyGestureEvent event) {
InputDevice device = getInputDevice(event.deviceId);
diff --git a/services/core/java/com/android/server/input/KeyRemapper.java b/services/core/java/com/android/server/input/KeyRemapper.java
index 7ba7769..82b36af 100644
--- a/services/core/java/com/android/server/input/KeyRemapper.java
+++ b/services/core/java/com/android/server/input/KeyRemapper.java
@@ -17,27 +17,24 @@
package com.android.server.input;
import android.content.Context;
-import android.hardware.input.InputManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.ArrayMap;
import android.util.FeatureFlagUtils;
-import android.view.InputDevice;
import com.android.internal.annotations.GuardedBy;
import java.util.Map;
-import java.util.Objects;
/**
* A component of {@link InputManagerService} responsible for managing key remappings.
*
* @hide
*/
-final class KeyRemapper implements InputManager.InputDeviceListener {
+final class KeyRemapper {
- private static final int MSG_UPDATE_EXISTING_DEVICES = 1;
+ private static final int MSG_UPDATE_EXISTING_KEY_REMAPPING = 1;
private static final int MSG_REMAP_KEY = 2;
private static final int MSG_CLEAR_ALL_REMAPPING = 3;
@@ -49,7 +46,7 @@
private final Handler mHandler;
KeyRemapper(Context context, NativeInputManagerService nativeService,
- PersistentDataStore dataStore, Looper looper) {
+ PersistentDataStore dataStore, Looper looper) {
mContext = context;
mNative = nativeService;
mDataStore = dataStore;
@@ -57,13 +54,7 @@
}
public void systemRunning() {
- InputManager inputManager = Objects.requireNonNull(
- mContext.getSystemService(InputManager.class));
- inputManager.registerInputDeviceListener(this, mHandler);
-
- Message msg = Message.obtain(mHandler, MSG_UPDATE_EXISTING_DEVICES,
- inputManager.getInputDeviceIds());
- mHandler.sendMessage(msg);
+ Message.obtain(mHandler, MSG_UPDATE_EXISTING_KEY_REMAPPING).sendToTarget();
}
public void remapKey(int fromKey, int toKey) {
@@ -91,19 +82,19 @@
}
}
- private void addKeyRemapping(int fromKey, int toKey) {
- InputManager inputManager = Objects.requireNonNull(
- mContext.getSystemService(InputManager.class));
- for (int deviceId : inputManager.getInputDeviceIds()) {
- InputDevice inputDevice = inputManager.getInputDevice(deviceId);
- if (inputDevice != null && !inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
- mNative.addKeyRemapping(deviceId, fromKey, toKey);
- }
+ private void setKeyRemapping(Map<Integer, Integer> keyRemapping) {
+ int index = 0;
+ int[] fromKeycodesArr = new int[keyRemapping.size()];
+ int[] toKeycodesArr = new int[keyRemapping.size()];
+ for (Map.Entry<Integer, Integer> entry : keyRemapping.entrySet()) {
+ fromKeycodesArr[index] = entry.getKey();
+ toKeycodesArr[index] = entry.getValue();
+ index++;
}
+ mNative.setKeyRemapping(fromKeycodesArr, toKeycodesArr);
}
private void remapKeyInternal(int fromKey, int toKey) {
- addKeyRemapping(fromKey, toKey);
synchronized (mDataStore) {
try {
if (fromKey == toKey) {
@@ -114,6 +105,7 @@
} finally {
mDataStore.saveIfNeeded();
}
+ setKeyRemapping(mDataStore.getKeyRemapping());
}
}
@@ -123,45 +115,25 @@
Map<Integer, Integer> keyRemapping = mDataStore.getKeyRemapping();
for (int fromKey : keyRemapping.keySet()) {
mDataStore.clearMappedKey(fromKey);
-
- // Remapping to itself will clear the remapping on native side
- addKeyRemapping(fromKey, fromKey);
}
} finally {
mDataStore.saveIfNeeded();
}
+ setKeyRemapping(mDataStore.getKeyRemapping());
}
}
- @Override
- public void onInputDeviceAdded(int deviceId) {
+ public void updateExistingKeyMapping() {
if (!supportRemapping()) {
return;
}
- InputManager inputManager = Objects.requireNonNull(
- mContext.getSystemService(InputManager.class));
- InputDevice inputDevice = inputManager.getInputDevice(deviceId);
- if (inputDevice != null && !inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
- Map<Integer, Integer> remapping = getKeyRemapping();
- remapping.forEach(
- (fromKey, toKey) -> mNative.addKeyRemapping(deviceId, fromKey, toKey));
- }
- }
-
- @Override
- public void onInputDeviceRemoved(int deviceId) {
- }
-
- @Override
- public void onInputDeviceChanged(int deviceId) {
+ setKeyRemapping(getKeyRemapping());
}
private boolean handleMessage(Message msg) {
switch (msg.what) {
- case MSG_UPDATE_EXISTING_DEVICES:
- for (int deviceId : (int[]) msg.obj) {
- onInputDeviceAdded(deviceId);
- }
+ case MSG_UPDATE_EXISTING_KEY_REMAPPING:
+ updateExistingKeyMapping();
return true;
case MSG_REMAP_KEY:
remapKeyInternal(msg.arg1, msg.arg2);
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index 1e7c97f9..d17e256 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -48,7 +48,7 @@
int getSwitchState(int deviceId, int sourceMask, int sw);
- void addKeyRemapping(int deviceId, int fromKeyCode, int toKeyCode);
+ void setKeyRemapping(int[] fromKeyCodes, int[] toKeyCodes);
boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
@@ -212,7 +212,7 @@
void setMotionClassifierEnabled(boolean enabled);
- void setKeyRepeatConfiguration(int timeoutMs, int delayMs);
+ void setKeyRepeatConfiguration(int timeoutMs, int delayMs, boolean keyRepeatEnabled);
InputSensorInfo[] getSensorList(int deviceId);
@@ -311,7 +311,7 @@
public native int getSwitchState(int deviceId, int sourceMask, int sw);
@Override
- public native void addKeyRemapping(int deviceId, int fromKeyCode, int toKeyCode);
+ public native void setKeyRemapping(int[] fromKeyCodes, int[] toKeyCodes);
@Override
public native boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes,
@@ -509,7 +509,8 @@
public native void setMotionClassifierEnabled(boolean enabled);
@Override
- public native void setKeyRepeatConfiguration(int timeoutMs, int delayMs);
+ public native void setKeyRepeatConfiguration(int timeoutMs, int delayMs,
+ boolean keyRepeatEnabled);
@Override
public native InputSensorInfo[] getSensorList(int deviceId);
diff --git a/services/core/java/com/android/server/input/debug/TouchpadDebugView.java b/services/core/java/com/android/server/input/debug/TouchpadDebugView.java
index 5ff8568..f351465 100644
--- a/services/core/java/com/android/server/input/debug/TouchpadDebugView.java
+++ b/services/core/java/com/android/server/input/debug/TouchpadDebugView.java
@@ -52,6 +52,8 @@
private static final float DEFAULT_RES_Y = 45f;
private static final int TEXT_PADDING_DP = 12;
private static final int ROUNDED_CORNER_RADIUS_DP = 24;
+ private static final int BUTTON_PRESSED_BACKGROUND_COLOR = Color.rgb(118, 151, 99);
+ private static final int BUTTON_RELEASED_BACKGROUND_COLOR = Color.rgb(84, 85, 169);
/**
* Input device ID for the touchpad that this debug view is displaying.
@@ -75,6 +77,8 @@
private int mWindowLocationBeforeDragY;
private int mLatestGestureType = 0;
private TextView mGestureInfoView;
+ private TextView mNameView;
+
@NonNull
private TouchpadHardwareState mLastTouchpadState =
new TouchpadHardwareState(0, 0 /* buttonsDown */, 0, 0,
@@ -119,35 +123,34 @@
LayoutParams.WRAP_CONTENT));
setBackgroundColor(Color.TRANSPARENT);
- TextView nameView = new TextView(context);
- nameView.setBackgroundColor(Color.RED);
- nameView.setTextSize(TEXT_SIZE_SP);
- nameView.setText(Objects.requireNonNull(Objects.requireNonNull(
+ mNameView = new TextView(context);
+ mNameView.setBackgroundColor(BUTTON_RELEASED_BACKGROUND_COLOR);
+ mNameView.setTextSize(TEXT_SIZE_SP);
+ mNameView.setText(Objects.requireNonNull(Objects.requireNonNull(
mContext.getSystemService(InputManager.class))
.getInputDevice(touchpadId)).getName());
- nameView.setGravity(Gravity.CENTER);
- nameView.setTextColor(Color.WHITE);
+ mNameView.setGravity(Gravity.CENTER);
+ mNameView.setTextColor(Color.WHITE);
int paddingInDP = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, TEXT_PADDING_DP,
getResources().getDisplayMetrics());
- nameView.setPadding(paddingInDP, paddingInDP, paddingInDP, paddingInDP);
- nameView.setLayoutParams(
+ mNameView.setPadding(paddingInDP, paddingInDP, paddingInDP, paddingInDP);
+ mNameView.setLayoutParams(
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
mTouchpadVisualizationView = new TouchpadVisualizationView(context,
mTouchpadHardwareProperties);
- mTouchpadVisualizationView.setBackgroundColor(Color.WHITE);
mGestureInfoView = new TextView(context);
- mGestureInfoView.setBackgroundColor(Color.BLACK);
mGestureInfoView.setTextSize(TEXT_SIZE_SP);
mGestureInfoView.setText("Latest Gesture: ");
mGestureInfoView.setGravity(Gravity.CENTER);
- mGestureInfoView.setTextColor(Color.WHITE);
mGestureInfoView.setPadding(paddingInDP, paddingInDP, paddingInDP, paddingInDP);
mGestureInfoView.setLayoutParams(
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
- addView(nameView);
+ updateTheme(getResources().getConfiguration().uiMode);
+
+ addView(mNameView);
addView(mTouchpadVisualizationView);
addView(mGestureInfoView);
@@ -180,6 +183,10 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
+ if (event.getClassification() == MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE) {
+ return false;
+ }
+
float deltaX;
float deltaY;
switch (event.getAction()) {
@@ -235,6 +242,8 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+
+ updateTheme(newConfig.uiMode);
updateScreenDimensions();
updateViewsDimensions();
@@ -246,6 +255,27 @@
mWindowManager.updateViewLayout(this, mWindowLayoutParams);
}
+ private void updateTheme(int uiMode) {
+ int currentNightMode = uiMode & Configuration.UI_MODE_NIGHT_MASK;
+ if (currentNightMode == Configuration.UI_MODE_NIGHT_YES) {
+ setNightModeTheme();
+ } else {
+ setLightModeTheme();
+ }
+ }
+
+ private void setLightModeTheme() {
+ mTouchpadVisualizationView.setLightModeTheme();
+ mGestureInfoView.setBackgroundColor(Color.WHITE);
+ mGestureInfoView.setTextColor(Color.BLACK);
+ }
+
+ private void setNightModeTheme() {
+ mTouchpadVisualizationView.setNightModeTheme();
+ mGestureInfoView.setBackgroundColor(Color.BLACK);
+ mGestureInfoView.setTextColor(Color.WHITE);
+ }
+
private boolean isSlopExceeded(float deltaX, float deltaY) {
return deltaX * deltaX + deltaY * deltaY >= mTouchSlop * mTouchSlop;
}
@@ -329,12 +359,12 @@
private void onTouchpadButtonPress() {
Slog.d(TAG, "You clicked me!");
- getChildAt(0).setBackgroundColor(Color.BLUE);
+ mNameView.setBackgroundColor(BUTTON_PRESSED_BACKGROUND_COLOR);
}
private void onTouchpadButtonRelease() {
Slog.d(TAG, "You released the click");
- getChildAt(0).setBackgroundColor(Color.RED);
+ mNameView.setBackgroundColor(BUTTON_RELEASED_BACKGROUND_COLOR);
}
/**
diff --git a/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java b/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
index 2eed9ba..96426bb 100644
--- a/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
+++ b/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.Slog;
@@ -58,11 +59,9 @@
mScaleFactor = 1;
mOvalStrokePaint = new Paint();
mOvalStrokePaint.setAntiAlias(true);
- mOvalStrokePaint.setARGB(255, 0, 0, 0);
mOvalStrokePaint.setStyle(Paint.Style.STROKE);
mOvalFillPaint = new Paint();
mOvalFillPaint.setAntiAlias(true);
- mOvalFillPaint.setARGB(255, 0, 0, 0);
mTracePaint = new Paint();
mTracePaint.setAntiAlias(false);
mTracePaint.setARGB(255, 0, 0, 255);
@@ -195,6 +194,24 @@
mScaleFactor = scaleFactor;
}
+ /**
+ * Change the colors of the objects inside the view to light mode theme.
+ */
+ public void setLightModeTheme() {
+ this.setBackgroundColor(Color.rgb(20, 20, 20));
+ mOvalFillPaint.setARGB(255, 255, 255, 255);
+ mOvalStrokePaint.setARGB(255, 255, 255, 255);
+ }
+
+ /**
+ * Change the colors of the objects inside the view to night mode theme.
+ */
+ public void setNightModeTheme() {
+ this.setBackgroundColor(Color.rgb(240, 240, 240));
+ mOvalFillPaint.setARGB(255, 0, 0, 0);
+ mOvalStrokePaint.setARGB(255, 0, 0, 0);
+ }
+
private float translateX(float x) {
return translateRange(mTouchpadHardwareProperties.getLeft(),
mTouchpadHardwareProperties.getRight(), 0, getWidth(), x);
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 4b2c12a..63bd9ab 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -389,7 +389,7 @@
// Reload gnss config for no SIM case
mGnssConfiguration.reloadGpsProperties();
}
- if (Flags.enableNiSuplMessageInjectionByCarrierConfig()) {
+ if (Flags.enableNiSuplMessageInjectionByCarrierConfigBugfix()) {
updateNiSuplMessageListenerRegistration(
mGnssConfiguration.isNiSuplMessageInjectionEnabled());
}
@@ -538,7 +538,7 @@
intentFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
mContext.registerReceiver(mIntentReceiver, intentFilter, null, mHandler);
- if (!Flags.enableNiSuplMessageInjectionByCarrierConfig()) {
+ if (!Flags.enableNiSuplMessageInjectionByCarrierConfigBugfix()) {
updateNiSuplMessageListenerRegistration(
mGnssConfiguration.isNiSuplMessageInjectionEnabled());
}
@@ -1672,7 +1672,7 @@
if (dumpAll) {
mNetworkTimeHelper.dump(pw);
pw.println("mSupportsPsds=" + mSupportsPsds);
- if (Flags.enableNiSuplMessageInjectionByCarrierConfig()) {
+ if (Flags.enableNiSuplMessageInjectionByCarrierConfigBugfix()) {
pw.println("mNiSuplMessageListenerRegistered="
+ mNiSuplMessageListenerRegistered);
}
diff --git a/services/core/java/com/android/server/location/gnss/NetworkTimeHelper.java b/services/core/java/com/android/server/location/gnss/NetworkTimeHelper.java
index 01c108b..494ea77 100644
--- a/services/core/java/com/android/server/location/gnss/NetworkTimeHelper.java
+++ b/services/core/java/com/android/server/location/gnss/NetworkTimeHelper.java
@@ -19,6 +19,7 @@
import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.content.Context;
+import android.location.flags.Flags;
import android.os.Looper;
import java.io.PrintWriter;
@@ -55,7 +56,7 @@
static NetworkTimeHelper create(
@NonNull Context context, @NonNull Looper looper,
@NonNull InjectTimeCallback injectTimeCallback) {
- if (USE_TIME_DETECTOR_IMPL) {
+ if (!Flags.useLegacyNtpTime()) {
TimeDetectorNetworkTimeHelper.Environment environment =
new TimeDetectorNetworkTimeHelper.EnvironmentImpl(looper);
return new TimeDetectorNetworkTimeHelper(environment, injectTimeCallback);
diff --git a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
index df45a6e..177eefb 100644
--- a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
+++ b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
@@ -76,11 +76,12 @@
try {
mIsInEmergencyCall = mTelephonyManager.isEmergencyNumber(
intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER));
- dispatchEmergencyStateChanged();
} catch (IllegalStateException | UnsupportedOperationException e) {
Log.w(TAG, "Failed to call TelephonyManager.isEmergencyNumber().", e);
}
}
+
+ dispatchEmergencyStateChanged();
}
}, new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL));
@@ -140,9 +141,10 @@
if (mIsInEmergencyCall) {
mEmergencyCallEndRealtimeMs = SystemClock.elapsedRealtime();
mIsInEmergencyCall = false;
- dispatchEmergencyStateChanged();
}
}
+
+ dispatchEmergencyStateChanged();
}
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 158d444..1e25f1c 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -140,7 +140,7 @@
try {
db.delete(TABLE, COLUMN_KEY + "=? AND " + COLUMN_USERID + "=?",
new String[] {key, Integer.toString(userId)});
- db.insert(TABLE, null, cv);
+ db.insertOrThrow(TABLE, null, cv);
db.setTransactionSuccessful();
mCache.putKeyValue(key, value, userId);
} finally {
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 621c090..48d24f2 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -179,7 +179,8 @@
/**
* In order to record the keyguard, the MediaProjection package must be either:
* - a holder of RECORD_SENSITIVE_CONTENT permission, or
- * - be one of the bugreport whitelisted packages
+ * - be one of the bugreport allowlisted packages, or
+ * - hold the OP_PROJECT_MEDIA AppOp.
*/
private boolean canCaptureKeyguard() {
if (!android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions()) {
@@ -194,6 +195,14 @@
== PackageManager.PERMISSION_GRANTED) {
return true;
}
+ boolean operationActive = mAppOps.isOperationActive(AppOpsManager.OP_PROJECT_MEDIA,
+ mProjectionGrant.uid,
+ mProjectionGrant.packageName);
+ if (operationActive) {
+ // Some tools use media projection by granting the OP_PROJECT_MEDIA app
+ // op via a shell command. Those tools can be granted keyguard capture
+ return true;
+ }
return SystemConfig.getInstance().getBugreportWhitelistedPackages()
.contains(mProjectionGrant.packageName);
}
diff --git a/services/core/java/com/android/server/notification/VibratorHelper.java b/services/core/java/com/android/server/notification/VibratorHelper.java
index fbe7772..f54c1f7 100644
--- a/services/core/java/com/android/server/notification/VibratorHelper.java
+++ b/services/core/java/com/android/server/notification/VibratorHelper.java
@@ -218,10 +218,16 @@
* @param uri {@code Uri} an uri including query parameter "vibraiton_uri"
*/
public @Nullable VibrationEffect createVibrationEffectFromSoundUri(Uri uri) {
- if (uri == null) {
+ if (uri == null || uri.isOpaque()) {
return null;
}
- return Utils.parseVibrationEffect(mVibrator, Utils.getVibrationUri(uri));
+
+ try {
+ return Utils.parseVibrationEffect(mVibrator, Utils.getVibrationUri(uri));
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to get vibration effect: ", e);
+ }
+ return null;
}
/** Returns if a given vibration can be played by the vibrator that does notification buzz. */
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index e9db1b5..0eb4cbd 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1358,7 +1358,8 @@
if (isNew) {
// Newly created rule with no provided policy; fill in with the default.
zenRule.zenPolicy =
- Flags.modesUi() ? mDefaultConfig.getZenPolicy() : mConfig.getZenPolicy();
+ (Flags.modesUi() ? mDefaultConfig.getZenPolicy() : mConfig.getZenPolicy())
+ .copy();
return true;
}
// Otherwise, a null policy means no policy changes, so we can stop here.
@@ -1773,7 +1774,7 @@
// definition cannot have a rule with TYPE_BEDTIME (or any other type).
config.automaticRules = new ArrayMap<>();
for (ZenRule rule : mDefaultConfig.automaticRules.values()) {
- config.automaticRules.put(rule.id, rule);
+ config.automaticRules.put(rule.id, rule.copy());
}
reason += ", reset to default rules";
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index a41675a..6303ecd 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -298,13 +298,12 @@
restoreSettings();
- if (Build.IS_USER) {
- // Wipe all shell overlays on boot, to recover from a potentially broken device
- String shellPkgName = TextUtils.emptyIfNull(
- getContext().getString(android.R.string.config_systemShell));
- mSettings.removeIf(overlayInfo -> overlayInfo.isFabricated
- && shellPkgName.equals(overlayInfo.packageName));
- }
+ // Wipe all shell overlays on boot, to recover from a potentially broken device
+ String shellPkgName = TextUtils.emptyIfNull(
+ getContext().getString(android.R.string.config_systemShell));
+ mSettings.removeIf(overlayInfo -> overlayInfo.isFabricated
+ && shellPkgName.equals(overlayInfo.packageName));
+
initIfNeeded();
onStartUser(UserHandle.USER_SYSTEM);
diff --git a/services/core/java/com/android/server/pm/Android.bp b/services/core/java/com/android/server/pm/Android.bp
new file mode 100644
index 0000000..d625cf2
--- /dev/null
+++ b/services/core/java/com/android/server/pm/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * 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 {
+ default_team: "trendy_team_framework_android_packages",
+ // 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"],
+}
+
+filegroup {
+ name: "framework-pm-service-sources",
+ srcs: [
+ "**/*.java",
+ "**/*.aidl",
+ ],
+ exclude_srcs: [
+ "dex/**/*.java",
+ "User*.java",
+ "Shortcut*.java",
+ ],
+ visibility: ["//frameworks/base"],
+}
diff --git a/services/core/java/com/android/server/pm/BackgroundUserSoundNotifier.java b/services/core/java/com/android/server/pm/BackgroundUserSoundNotifier.java
index 5aea356..49a6ffd 100644
--- a/services/core/java/com/android/server/pm/BackgroundUserSoundNotifier.java
+++ b/services/core/java/com/android/server/pm/BackgroundUserSoundNotifier.java
@@ -191,6 +191,7 @@
/**
* Stop player proxy for the ongoing alarm and drop focus for its AudioFocusInfo.
*/
+ @SuppressLint("MissingPermission")
@VisibleForTesting
void muteAlarmSounds(Context context) {
AudioManager audioManager = context.getSystemService(AudioManager.class);
@@ -201,6 +202,11 @@
}
}
}
+
+ AudioFocusInfo currentAfi = getAudioFocusInfoForNotification();
+ if (currentAfi != null) {
+ mFocusControlAudioPolicy.sendFocusLossAndUpdate(currentAfi);
+ }
}
/**
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index c75622c..21a6df2 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -208,6 +208,22 @@
"name": "CtsUpdateOwnershipEnforcementTestCases"
},
{
+ "name": "CtsPackageInstallerCUJDeviceAdminTestCases",
+ "file_patterns": [
+ "core/java/.*Install.*",
+ "services/core/.*Install.*",
+ "services/core/java/com/android/server/pm/.*"
+ ],
+ "options":[
+ {
+ "exclude-annotation":"androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation":"org.junit.Ignore"
+ }
+ ]
+ },
+ {
"name": "CtsPackageInstallerCUJInstallationTestCases",
"file_patterns": [
"core/java/.*Install.*",
@@ -224,6 +240,22 @@
]
},
{
+ "name": "CtsPackageInstallerCUJMultiUsersTestCases",
+ "file_patterns": [
+ "core/java/.*Install.*",
+ "services/core/.*Install.*",
+ "services/core/java/com/android/server/pm/.*"
+ ],
+ "options":[
+ {
+ "exclude-annotation":"androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation":"org.junit.Ignore"
+ }
+ ]
+ },
+ {
"name": "CtsPackageInstallerCUJUninstallationTestCases",
"file_patterns": [
"core/java/.*Install.*",
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 89417f3..8bab9de 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1101,8 +1101,6 @@
if (android.multiuser.Flags.cachesNotInvalidatedAtStartReadOnly()) {
UserManager.invalidateIsUserUnlockedCache();
UserManager.invalidateQuietModeEnabledCache();
- UserManager.invalidateStaticUserProperties();
- UserManager.invalidateUserPropertiesCache();
UserManager.invalidateUserSerialNumberCache();
}
}
@@ -2647,11 +2645,15 @@
}
@Override
- public int getMainDisplayIdAssignedToUser() {
- // Not checking for any permission as it returns info about calling user
- int userId = UserHandle.getUserId(Binder.getCallingUid());
- int displayId = mUserVisibilityMediator.getMainDisplayAssignedToUser(userId);
- return displayId;
+ public int getMainDisplayIdAssignedToUser(int userId) {
+ final int callingUserId = UserHandle.getCallingUserId();
+ if (callingUserId != userId
+ && !hasManageUsersOrPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)) {
+ throw new SecurityException("Caller from user " + callingUserId + " needs MANAGE_USERS "
+ + "or INTERACT_ACROSS_USERS permission to get the main display for (" + userId
+ + ")");
+ }
+ return mUserVisibilityMediator.getMainDisplayAssignedToUser(userId);
}
@Override
diff --git a/services/core/java/com/android/server/pm/UserVisibilityMediator.java b/services/core/java/com/android/server/pm/UserVisibilityMediator.java
index 46207c18..b43ddaa 100644
--- a/services/core/java/com/android/server/pm/UserVisibilityMediator.java
+++ b/services/core/java/com/android/server/pm/UserVisibilityMediator.java
@@ -572,7 +572,7 @@
return false;
}
- // First check if the user started on display
+ // First check if the user is assigned to a display
int userAssignedToDisplay = getUserStartedOnDisplay(displayId);
if (userAssignedToDisplay != USER_NULL) {
Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because display was assigned"
@@ -918,10 +918,16 @@
if (!isStartedVisibleProfileLocked(userId)) {
return userId;
} else if (DBG) {
- Slogf.d(TAG, "getUserAssignedToDisplay(%d): skipping user %d because it's "
- + "a profile", displayId, userId);
+ Slogf.d(TAG,
+ "getUserAssignedToDisplay(%d): skipping user %d because it's a profile",
+ displayId, userId);
}
}
+ int userAssignedToExtraDisplay = mExtraDisplaysAssignedToUsers.get(displayId,
+ USER_NULL);
+ if (userAssignedToExtraDisplay != USER_NULL) {
+ return userAssignedToExtraDisplay;
+ }
}
if (!returnCurrentUserByDefault) {
if (DBG) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index ef37464..63491e8 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -47,6 +47,7 @@
import static android.view.KeyEvent.KEYCODE_HOME;
import static android.view.KeyEvent.KEYCODE_POWER;
import static android.view.KeyEvent.KEYCODE_STEM_PRIMARY;
+import static android.view.KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL;
import static android.view.KeyEvent.KEYCODE_UNKNOWN;
import static android.view.KeyEvent.KEYCODE_VOLUME_DOWN;
import static android.view.KeyEvent.KEYCODE_VOLUME_UP;
@@ -2643,7 +2644,7 @@
}
@Override
- void onKeyUp(long eventTime, int count, int displayId) {
+ void onKeyUp(long eventTime, int count, int displayId, int deviceId, int metaState) {
if (mShouldEarlyShortPressOnPower && count == 1) {
powerPress(eventTime, 1 /*pressCount*/, displayId);
}
@@ -2763,7 +2764,7 @@
}
@Override
- void onKeyUp(long eventTime, int count, int unusedDisplayId) {
+ void onKeyUp(long eventTime, int count, int displayId, int deviceId, int metaState) {
if (count == 1) {
// Save info about the most recent task on the first press of the stem key. This
// may be used later to switch to the most recent app using double press gesture.
@@ -2816,6 +2817,33 @@
}
}
+ // TODO(b/358569822): Move to KeyGestureController.
+ private final class StylusTailButtonRule extends SingleKeyGestureDetector.SingleKeyRule {
+ StylusTailButtonRule() {
+ super(KEYCODE_STYLUS_BUTTON_TAIL);
+ }
+
+ @Override
+ int getMaxMultiPressCount() {
+ return 2;
+ }
+
+ @Override
+ void onPress(long downTime, int displayId) {
+
+ }
+
+ @Override
+ void onKeyUp(long eventTime, int pressCount, int displayId, int deviceId, int metaState) {
+ if (pressCount != 1) {
+ return;
+ }
+ // Single press on tail button triggers the open notes gesture.
+ handleKeyGestureInKeyGestureController(KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES,
+ deviceId, KEYCODE_STYLUS_BUTTON_TAIL, metaState);
+ }
+ }
+
private void initSingleKeyGestureRules(Looper looper) {
mSingleKeyGestureDetector = SingleKeyGestureDetector.get(mContext, looper);
mSingleKeyGestureDetector.addRule(new PowerKeyRule());
@@ -2825,6 +2853,7 @@
if (hasStemPrimaryBehavior()) {
mSingleKeyGestureDetector.addRule(new StemPrimaryKeyRule());
}
+ mSingleKeyGestureDetector.addRule(new StylusTailButtonRule());
}
/**
@@ -3314,6 +3343,16 @@
new int[]{event.getKeyCode()}, event.getMetaState(), gestureType);
}
+ private void handleKeyGestureInKeyGestureController(
+ @KeyGestureEvent.KeyGestureType int gestureType, int deviceId, int keyCode,
+ int metaState) {
+ if (gestureType == KeyGestureEvent.KEY_GESTURE_TYPE_UNSPECIFIED) {
+ return;
+ }
+ mInputManagerInternal.handleKeyGestureInKeyGestureController(deviceId, new int[]{keyCode},
+ metaState, gestureType);
+ }
+
@Override
public KeyboardShortcutGroup getApplicationLaunchKeyboardShortcuts(int deviceId) {
return mModifierShortcutManager.getApplicationLaunchKeyboardShortcuts(deviceId);
@@ -3849,10 +3888,6 @@
case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS:
case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH:
case KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH:
- case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP:
- case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN:
- case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
- case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK:
return true;
default:
return false;
@@ -4010,25 +4045,6 @@
sendSwitchKeyboardLayout(displayId, focusedToken, direction);
}
return true;
- // TODO (b/358569822): Move these input specific gesture handling to IMS since we
- // are calling into InputManager through internal API anyways
- case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP:
- if (complete) {
- mInputManagerInternal.incrementKeyboardBacklight(deviceId);
- }
- return true;
- case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN:
- if (complete) {
- mInputManagerInternal.decrementKeyboardBacklight(deviceId);
- }
- return true;
- case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
- return true;
- case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK:
- if (complete) {
- mInputManagerInternal.toggleCapsLock(deviceId);
- }
- return true;
}
return false;
}
diff --git a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
index a060f50..441d3ea 100644
--- a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
+++ b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
@@ -105,9 +105,9 @@
/**
* Maximum count of multi presses.
- * Return 1 will trigger onPress immediately when {@link KeyEvent.ACTION_UP}.
+ * Return 1 will trigger onPress immediately when {@link KeyEvent#ACTION_UP}.
* Otherwise trigger onMultiPress immediately when reach max count when
- * {@link KeyEvent.ACTION_DOWN}.
+ * {@link KeyEvent#ACTION_DOWN}.
*/
int getMaxMultiPressCount() {
return 1;
@@ -153,8 +153,10 @@
* @param eventTime the timestamp of this event
* @param pressCount the number of presses detected leading up to this key up event
* @param displayId the display ID of the event
+ * @param deviceId the ID of the input device that generated this event
+ * @param metaState the state of the modifiers when this gesture was detected
*/
- void onKeyUp(long eventTime, int pressCount, int displayId) {}
+ void onKeyUp(long eventTime, int pressCount, int displayId, int deviceId, int metaState) {}
@Override
public String toString() {
@@ -183,7 +185,11 @@
}
private record MessageObject(SingleKeyRule activeRule, int keyCode, int pressCount,
- int displayId) {
+ int displayId, int metaState, int deviceId) {
+ MessageObject(SingleKeyRule activeRule, int keyCode, int pressCount, KeyEvent event) {
+ this(activeRule, keyCode, pressCount, event.getDisplayId(), event.getMetaState(),
+ event.getDeviceId());
+ }
}
static SingleKeyGestureDetector get(Context context, Looper looper) {
@@ -236,7 +242,7 @@
mHandler.removeMessages(MSG_KEY_LONG_PRESS);
mHandler.removeMessages(MSG_KEY_VERY_LONG_PRESS);
MessageObject object = new MessageObject(mActiveRule, keyCode, /* pressCount= */ 1,
- event.getDisplayId());
+ event);
final Message msg = mHandler.obtainMessage(MSG_KEY_LONG_PRESS, object);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
@@ -284,7 +290,7 @@
if (mKeyPressCounter == 1) {
if (mActiveRule.supportLongPress()) {
MessageObject object = new MessageObject(mActiveRule, keyCode, mKeyPressCounter,
- event.getDisplayId());
+ event);
final Message msg = mHandler.obtainMessage(MSG_KEY_LONG_PRESS, object);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg, mActiveRule.getLongPressTimeoutMs());
@@ -292,7 +298,7 @@
if (mActiveRule.supportVeryLongPress()) {
MessageObject object = new MessageObject(mActiveRule, keyCode, mKeyPressCounter,
- event.getDisplayId());
+ event);
final Message msg = mHandler.obtainMessage(MSG_KEY_VERY_LONG_PRESS, object);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg, mActiveRule.getVeryLongPressTimeoutMs());
@@ -310,7 +316,7 @@
+ " reached the max count " + mKeyPressCounter);
}
MessageObject object = new MessageObject(mActiveRule, keyCode, mKeyPressCounter,
- event.getDisplayId());
+ event);
final Message msg = mHandler.obtainMessage(MSG_KEY_DELAYED_PRESS, object);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
@@ -351,7 +357,7 @@
if (event.getKeyCode() == mActiveRule.mKeyCode) {
// key-up action should always be triggered if not processed by long press.
MessageObject object = new MessageObject(mActiveRule, mActiveRule.mKeyCode,
- mKeyPressCounter, event.getDisplayId());
+ mKeyPressCounter, event);
Message msgKeyUp = mHandler.obtainMessage(MSG_KEY_UP, object);
msgKeyUp.setAsynchronous(true);
mHandler.sendMessage(msgKeyUp);
@@ -362,7 +368,7 @@
Log.i(TAG, "press key " + KeyEvent.keyCodeToString(event.getKeyCode()));
}
object = new MessageObject(mActiveRule, mActiveRule.mKeyCode,
- /* pressCount= */ 1, event.getDisplayId());
+ /* pressCount= */ 1, event);
Message msg = mHandler.obtainMessage(MSG_KEY_DELAYED_PRESS, object);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
@@ -373,7 +379,7 @@
// This could be a multi-press. Wait a little bit longer to confirm.
if (mKeyPressCounter < mActiveRule.getMaxMultiPressCount()) {
object = new MessageObject(mActiveRule, mActiveRule.mKeyCode,
- mKeyPressCounter, event.getDisplayId());
+ mKeyPressCounter, event);
Message msg = mHandler.obtainMessage(MSG_KEY_DELAYED_PRESS, object);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg, MULTI_PRESS_TIMEOUT);
@@ -452,7 +458,8 @@
Log.i(TAG, "Detect key up " + KeyEvent.keyCodeToString(keyCode)
+ " on display " + displayId);
}
- rule.onKeyUp(mLastDownTime, pressCount, displayId);
+ rule.onKeyUp(mLastDownTime, pressCount, displayId, object.deviceId,
+ object.metaState);
break;
case MSG_KEY_LONG_PRESS:
if (DEBUG) {
diff --git a/services/core/java/com/android/server/power/PowerManagerShellCommand.java b/services/core/java/com/android/server/power/PowerManagerShellCommand.java
index 20184e9f..f69a017 100644
--- a/services/core/java/com/android/server/power/PowerManagerShellCommand.java
+++ b/services/core/java/com/android/server/power/PowerManagerShellCommand.java
@@ -16,13 +16,19 @@
package com.android.server.power;
+import android.app.AlarmManager;
+import android.app.IAlarmCompleteListener;
+import android.app.IAlarmListener;
+import android.app.IAlarmManager;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.PowerManagerInternal;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.ShellCommand;
+import android.os.SystemClock;
import android.util.SparseArray;
import android.view.Display;
@@ -34,12 +40,26 @@
private final Context mContext;
private final PowerManagerService.BinderService mService;
+ private final IAlarmListener mAlarmListener;
+ private IAlarmManager mAlarmManager;
private SparseArray<WakeLock> mProxWakelocks = new SparseArray<>();
PowerManagerShellCommand(Context context, PowerManagerService.BinderService service) {
mContext = context;
mService = service;
+ mAlarmManager =
+ IAlarmManager.Stub.asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
+ mAlarmListener = new IAlarmListener.Stub() {
+ @Override
+ public void doAlarm(IAlarmCompleteListener callback) throws RemoteException {
+ mService.wakeUp(
+ SystemClock.uptimeMillis(),
+ PowerManager.WAKE_REASON_APPLICATION,
+ "PowerManagerShellCommand",
+ mContext.getOpPackageName());
+ }
+ };
}
@Override
@@ -65,6 +85,10 @@
return runSetProx();
case "set-face-down-detector":
return runSetFaceDownDetector();
+ case "sleep":
+ return runSleep();
+ case "wakeup":
+ return runWakeUp();
default:
return handleDefaultCommands(cmd);
}
@@ -194,6 +218,70 @@
return 0;
}
+ private int runSleep() {
+ try {
+ mService.goToSleep(
+ SystemClock.uptimeMillis(),
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+ } catch (Exception e) {
+ final PrintWriter pw = getOutPrintWriter();
+ pw.println("Error: " + e);
+ return -1;
+ }
+ return 0;
+ }
+
+ private int runWakeUp() {
+ final PrintWriter pw = getOutPrintWriter();
+ String delay = getNextArg();
+ if (delay == null) {
+ try {
+ mService.wakeUp(
+ SystemClock.uptimeMillis(),
+ PowerManager.WAKE_REASON_APPLICATION,
+ "PowerManagerShellCommand",
+ mContext.getOpPackageName());
+ } catch (Exception e) {
+ pw.println("Error: " + e);
+ return -1;
+ }
+ } else {
+ long delayMillis;
+ try {
+ delayMillis = Long.parseLong(delay);
+ } catch (NumberFormatException e) {
+ pw.println("Error: Can't parse arg " + delay + " as a long: " + e);
+ return -1;
+ }
+ if (delayMillis < 0) {
+ pw.println("Error: Can't set a negative delay: " + delayMillis);
+ return -1;
+ }
+ long wakeUpTime = System.currentTimeMillis() + delayMillis;
+ if (mAlarmManager == null) {
+ // PowerManagerShellCommand may be initialized before AlarmManagerService
+ // is brought up. Make sure mAlarmManager exists.
+ mAlarmManager = IAlarmManager.Stub.asInterface(
+ ServiceManager.getService(Context.ALARM_SERVICE));
+ }
+ try {
+ // This command is called by the shell, which has "com.android.shell" as package
+ // name.
+ pw.println("Schedule an alarm to wakeup in "
+ + delayMillis + " ms, on behalf of shell.");
+ mAlarmManager.set("com.android.shell",
+ AlarmManager.RTC_WAKEUP, wakeUpTime,
+ 0, 0, AlarmManager.FLAG_PRIORITIZE,
+ null, mAlarmListener, "PowerManagerShellCommand", null, null);
+ } catch (Exception e) {
+ pw.println("Error: " + e);
+ return -1;
+ }
+ }
+ return 0;
+ }
+
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
@@ -221,6 +309,11 @@
pw.println(" created by set-prox including their held status.");
pw.println(" set-face-down-detector [true|false]");
pw.println(" sets whether we use face down detector timeouts or not");
+ pw.println(" sleep");
+ pw.println(" requests to sleep the device");
+ pw.println(" wakeup <delay>");
+ pw.println(" requests to wake up the device. If a delay of milliseconds is specified,");
+ pw.println(" alarm manager will schedule a wake up after the delay.");
pw.println();
Intent.printIntentArgsHelp(pw , "");
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 68026ea..e3d71e4 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -24,8 +24,11 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -78,6 +81,8 @@
public final class RollbackPackageHealthObserver implements PackageHealthObserver {
private static final String TAG = "RollbackPackageHealthObserver";
private static final String NAME = "rollback-observer";
+ private static final String ACTION_NAME = RollbackPackageHealthObserver.class.getName();
+
private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
| ApplicationInfo.FLAG_SYSTEM;
@@ -596,12 +601,40 @@
}
};
- final LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver(result -> {
- mHandler.post(() -> onResult.accept(result));
- });
+ if (Flags.refactorCrashrecovery()) {
+ // Define a BroadcastReceiver to handle the result
+ BroadcastReceiver rollbackReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent result) {
+ mHandler.post(() -> onResult.accept(result));
+ }
+ };
- rollbackManager.commitRollback(rollback.getRollbackId(),
- Collections.singletonList(failedPackage), rollbackReceiver.getIntentSender());
+ // Register the BroadcastReceiver
+ mContext.registerReceiver(rollbackReceiver,
+ new IntentFilter(ACTION_NAME),
+ Context.RECEIVER_NOT_EXPORTED);
+
+ Intent intentReceiver = new Intent(ACTION_NAME);
+ intentReceiver.putExtra("rollbackId", rollback.getRollbackId());
+ intentReceiver.setPackage(mContext.getPackageName());
+
+ PendingIntent rollbackPendingIntent = PendingIntent.getBroadcast(mContext,
+ rollback.getRollbackId(),
+ intentReceiver,
+ PendingIntent.FLAG_MUTABLE);
+
+ rollbackManager.commitRollback(rollback.getRollbackId(),
+ Collections.singletonList(failedPackage),
+ rollbackPendingIntent.getIntentSender());
+ } else {
+ final LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver(result -> {
+ mHandler.post(() -> onResult.accept(result));
+ });
+
+ rollbackManager.commitRollback(rollback.getRollbackId(),
+ Collections.singletonList(failedPackage), rollbackReceiver.getIntentSender());
+ }
}
/**
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index 96a25da..1e82b89 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -322,9 +322,16 @@
if (SubscriptionManager.isValidSubscriptionId(subId)) {
// Get only configs as needed to save memory.
- final PersistableBundle carrierConfig =
- CarrierConfigManager.getCarrierConfigSubset(mContext, subId,
- VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS);
+ PersistableBundle carrierConfig = new PersistableBundle();
+ try {
+ carrierConfig =
+ mCarrierConfigManager.getConfigForSubId(
+ subId, VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS);
+
+ } catch (RuntimeException exception) {
+ Slog.w(TAG, "CarrierConfigLoader is not available.");
+ }
+
if (mDeps.isConfigForIdentifiedCarrier(carrierConfig)) {
mReadySubIdsBySlotId.put(slotId, subId);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperData.java b/services/core/java/com/android/server/wallpaper/WallpaperData.java
index a698429..15f86e9 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperData.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperData.java
@@ -78,7 +78,7 @@
/**
* The component name of the currently set live wallpaper.
*/
- ComponentName wallpaperComponent;
+ private ComponentName mWallpaperComponent;
// TODO(b/347235611) Remove this field
/**
@@ -195,7 +195,7 @@
*/
WallpaperData(WallpaperData source) {
this.userId = source.userId;
- this.wallpaperComponent = source.wallpaperComponent;
+ this.mWallpaperComponent = source.mWallpaperComponent;
this.mWhich = source.mWhich;
this.wallpaperId = source.wallpaperId;
this.cropHint.set(source.cropHint);
@@ -230,6 +230,14 @@
return result;
}
+ ComponentName getComponent() {
+ return mWallpaperComponent;
+ }
+
+ void setComponent(ComponentName componentName) {
+ this.mWallpaperComponent = componentName;
+ }
+
@Override
public String toString() {
StringBuilder out = new StringBuilder(defaultString(this));
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java b/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
index b15facb..74ca230 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
@@ -171,63 +171,9 @@
stream = new FileInputStream(file);
TypedXmlPullParser parser = Xml.resolvePullParser(stream);
- int type;
- do {
- type = parser.next();
- if (type == XmlPullParser.START_TAG) {
- String tag = parser.getName();
- if (("wp".equals(tag) && loadSystem) || ("kwp".equals(tag) && loadLock)) {
- if ("kwp".equals(tag)) {
- lockWallpaper = new WallpaperData(userId, FLAG_LOCK);
- }
- WallpaperData wallpaperToParse =
- "wp".equals(tag) ? wallpaper : lockWallpaper;
+ lockWallpaper = loadSettingsFromSerializer(parser, wallpaper, userId, loadSystem,
+ loadLock, keepDimensionHints, wpdData);
- if (!multiCrop()) {
- parseWallpaperAttributes(parser, wallpaperToParse, keepDimensionHints);
- }
-
- String comp = parser.getAttributeValue(null, "component");
- if (removeNextWallpaperComponent()) {
- wallpaperToParse.wallpaperComponent = comp != null
- ? ComponentName.unflattenFromString(comp)
- : null;
- if (wallpaperToParse.wallpaperComponent == null
- || "android".equals(wallpaperToParse.wallpaperComponent
- .getPackageName())) {
- wallpaperToParse.wallpaperComponent = mImageWallpaper;
- }
- } else {
- wallpaperToParse.nextWallpaperComponent = comp != null
- ? ComponentName.unflattenFromString(comp)
- : null;
- if (wallpaperToParse.nextWallpaperComponent == null
- || "android".equals(wallpaperToParse.nextWallpaperComponent
- .getPackageName())) {
- wallpaperToParse.nextWallpaperComponent = mImageWallpaper;
- }
- }
-
- if (multiCrop()) {
- parseWallpaperAttributes(parser, wallpaperToParse, keepDimensionHints);
- }
-
- if (DEBUG) {
- Slog.v(TAG, "mWidth:" + wpdData.mWidth);
- Slog.v(TAG, "mHeight:" + wpdData.mHeight);
- Slog.v(TAG, "cropRect:" + wallpaper.cropHint);
- Slog.v(TAG, "primaryColors:" + wallpaper.primaryColors);
- Slog.v(TAG, "mName:" + wallpaper.name);
- if (removeNextWallpaperComponent()) {
- Slog.v(TAG, "mWallpaperComponent:" + wallpaper.wallpaperComponent);
- } else {
- Slog.v(TAG, "mNextWallpaperComponent:"
- + wallpaper.nextWallpaperComponent);
- }
- }
- }
- }
- } while (type != XmlPullParser.END_DOCUMENT);
success = true;
} catch (FileNotFoundException e) {
Slog.w(TAG, "no current wallpaper -- first boot?");
@@ -275,6 +221,75 @@
return new WallpaperLoadingResult(wallpaper, lockWallpaper, success);
}
+ // This method updates `wallpaper` in place, but returns `lockWallpaper`. This is because
+ // `wallpaper` already exists if it's being read per `loadSystem`, but `lockWallpaper` is
+ // created conditionally if there is lock screen wallpaper data to read.
+ @VisibleForTesting
+ WallpaperData loadSettingsFromSerializer(TypedXmlPullParser parser, WallpaperData wallpaper,
+ int userId, boolean loadSystem, boolean loadLock, boolean keepDimensionHints,
+ DisplayData wpdData) throws IOException, XmlPullParserException {
+ WallpaperData lockWallpaper = null;
+ int type;
+ do {
+ type = parser.next();
+ if (type == XmlPullParser.START_TAG) {
+ String tag = parser.getName();
+ if (("wp".equals(tag) && loadSystem) || ("kwp".equals(tag) && loadLock)) {
+ if ("kwp".equals(tag)) {
+ lockWallpaper = new WallpaperData(userId, FLAG_LOCK);
+ }
+ WallpaperData wallpaperToParse =
+ "wp".equals(tag) ? wallpaper : lockWallpaper;
+
+ if (!multiCrop()) {
+ parseWallpaperAttributes(parser, wallpaperToParse, keepDimensionHints);
+ }
+
+ String comp = parser.getAttributeValue(null, "component");
+ if (removeNextWallpaperComponent()) {
+ wallpaperToParse.setComponent(comp != null
+ ? ComponentName.unflattenFromString(comp)
+ : null);
+ if (wallpaperToParse.getComponent() == null
+ || "android".equals(wallpaperToParse.getComponent()
+ .getPackageName())) {
+ wallpaperToParse.setComponent(mImageWallpaper);
+ }
+ } else {
+ wallpaperToParse.nextWallpaperComponent = comp != null
+ ? ComponentName.unflattenFromString(comp)
+ : null;
+ if (wallpaperToParse.nextWallpaperComponent == null
+ || "android".equals(wallpaperToParse.nextWallpaperComponent
+ .getPackageName())) {
+ wallpaperToParse.nextWallpaperComponent = mImageWallpaper;
+ }
+ }
+
+ if (multiCrop()) {
+ parseWallpaperAttributes(parser, wallpaperToParse, keepDimensionHints);
+ }
+
+ if (DEBUG) {
+ Slog.v(TAG, "mWidth:" + wpdData.mWidth);
+ Slog.v(TAG, "mHeight:" + wpdData.mHeight);
+ Slog.v(TAG, "cropRect:" + wallpaper.cropHint);
+ Slog.v(TAG, "primaryColors:" + wallpaper.primaryColors);
+ Slog.v(TAG, "mName:" + wallpaper.name);
+ if (removeNextWallpaperComponent()) {
+ Slog.v(TAG, "mWallpaperComponent:" + wallpaper.getComponent());
+ } else {
+ Slog.v(TAG, "mNextWallpaperComponent:"
+ + wallpaper.nextWallpaperComponent);
+ }
+ }
+ }
+ }
+ } while (type != XmlPullParser.END_DOCUMENT);
+
+ return lockWallpaper;
+ }
+
private void ensureSaneWallpaperData(WallpaperData wallpaper) {
// Only overwrite cropHint if the rectangle is invalid.
if (wallpaper.cropHint.width() < 0
@@ -340,7 +355,7 @@
getAttributeInt(parser, "totalCropTop", 0),
getAttributeInt(parser, "totalCropRight", 0),
getAttributeInt(parser, "totalCropBottom", 0));
- ComponentName componentName = removeNextWallpaperComponent() ? wallpaper.wallpaperComponent
+ ComponentName componentName = removeNextWallpaperComponent() ? wallpaper.getComponent()
: wallpaper.nextWallpaperComponent;
if (multiCrop() && mImageWallpaper.equals(componentName)) {
wallpaper.mCropHints = new SparseArray<>();
@@ -449,18 +464,7 @@
try {
fstream = new FileOutputStream(journal.chooseForWrite(), false);
TypedXmlSerializer out = Xml.resolveSerializer(fstream);
- out.startDocument(null, true);
-
- if (wallpaper != null) {
- writeWallpaperAttributes(out, "wp", wallpaper);
- }
-
- if (lockWallpaper != null) {
- writeWallpaperAttributes(out, "kwp", lockWallpaper);
- }
-
- out.endDocument();
-
+ saveSettingsToSerializer(out, wallpaper, lockWallpaper);
fstream.flush();
FileUtils.sync(fstream);
fstream.close();
@@ -472,6 +476,22 @@
}
@VisibleForTesting
+ void saveSettingsToSerializer(TypedXmlSerializer out, WallpaperData wallpaper,
+ WallpaperData lockWallpaper) throws IOException {
+ out.startDocument(null, true);
+
+ if (wallpaper != null) {
+ writeWallpaperAttributes(out, "wp", wallpaper);
+ }
+
+ if (lockWallpaper != null) {
+ writeWallpaperAttributes(out, "kwp", lockWallpaper);
+ }
+
+ out.endDocument();
+ }
+
+ @VisibleForTesting
void writeWallpaperAttributes(TypedXmlSerializer out, String tag, WallpaperData wallpaper)
throws IllegalArgumentException, IllegalStateException, IOException {
if (DEBUG) {
@@ -480,7 +500,7 @@
out.startTag(null, tag);
out.attributeInt(null, "id", wallpaper.wallpaperId);
- if (multiCrop() && mImageWallpaper.equals(wallpaper.wallpaperComponent)) {
+ if (multiCrop() && mImageWallpaper.equals(wallpaper.getComponent())) {
if (wallpaper.mCropHints == null) {
Slog.e(TAG, "cropHints should not be null when saved");
wallpaper.mCropHints = new SparseArray<>();
@@ -580,10 +600,10 @@
}
out.attribute(null, "name", wallpaper.name);
- if (wallpaper.wallpaperComponent != null
- && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) {
+ if (wallpaper.getComponent() != null
+ && !wallpaper.getComponent().equals(mImageWallpaper)) {
out.attribute(null, "component",
- wallpaper.wallpaperComponent.flattenToShortString());
+ wallpaper.getComponent().flattenToShortString());
}
if (wallpaper.allowBackup) {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 6cc37dd..4754ffb 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -276,7 +276,7 @@
final boolean isMigration = moved && lockWallpaperChanged;
final boolean isRestore = moved && !isMigration;
final boolean isAppliedToLock = (wallpaper.mWhich & FLAG_LOCK) != 0;
- final boolean needsUpdate = wallpaper.wallpaperComponent == null
+ final boolean needsUpdate = wallpaper.getComponent() == null
|| event != CLOSE_WRITE // includes the MOVED_TO case
|| wallpaper.imageWallpaperPending;
@@ -527,7 +527,7 @@
* @return true unless the wallpaper changed during the color computation
*/
private boolean extractColors(WallpaperData wallpaper) {
- if (offloadColorExtraction()) return !mImageWallpaper.equals(wallpaper.wallpaperComponent);
+ if (offloadColorExtraction()) return !mImageWallpaper.equals(wallpaper.getComponent());
String cropFile = null;
boolean defaultImageWallpaper = false;
int wallpaperId;
@@ -550,8 +550,8 @@
synchronized (mLock) {
// Not having a wallpaperComponent means it's a lock screen wallpaper.
- final boolean imageWallpaper = mImageWallpaper.equals(wallpaper.wallpaperComponent)
- || wallpaper.wallpaperComponent == null;
+ final boolean imageWallpaper = mImageWallpaper.equals(wallpaper.getComponent())
+ || wallpaper.getComponent() == null;
if (imageWallpaper && wallpaper.getCropFile().exists()) {
cropFile = wallpaper.getCropFile().getAbsolutePath();
} else if (imageWallpaper && !wallpaper.cropExists() && !wallpaper.sourceExists()) {
@@ -824,13 +824,13 @@
return;
}
TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
- t.traceBegin("WPMS.connectLocked-" + wallpaper.wallpaperComponent);
+ t.traceBegin("WPMS.connectLocked-" + wallpaper.getComponent());
if (DEBUG) Slog.v(TAG, "Adding window token: " + mToken);
mWindowManagerInternal.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId,
null /* options */);
mWindowManagerInternal.setWallpaperShowWhenLocked(
mToken, (wallpaper.mWhich & FLAG_LOCK) != 0);
- if (multiCrop() && mImageWallpaper.equals(wallpaper.wallpaperComponent)) {
+ if (multiCrop() && mImageWallpaper.equals(wallpaper.getComponent())) {
mWindowManagerInternal.setWallpaperCropHints(mToken,
mWallpaperCropper.getRelativeCropHints(wallpaper));
} else {
@@ -906,7 +906,7 @@
}
if (!mWallpaper.wallpaperUpdating && mWallpaper.userId == mCurrentUserId) {
- Slog.w(TAG, "Wallpaper reconnect timed out for " + mWallpaper.wallpaperComponent
+ Slog.w(TAG, "Wallpaper reconnect timed out for " + mWallpaper.getComponent()
+ ", reverting to built-in wallpaper!");
clearWallpaperLocked(mWallpaper.mWhich, mWallpaper.userId, false, null);
}
@@ -1035,9 +1035,9 @@
public void onServiceDisconnected(ComponentName name) {
synchronized (mLock) {
Slog.w(TAG, "Wallpaper service gone: " + name);
- if (!Objects.equals(name, mWallpaper.wallpaperComponent)) {
+ if (!Objects.equals(name, mWallpaper.getComponent())) {
Slog.e(TAG, "Does not match expected wallpaper component "
- + mWallpaper.wallpaperComponent);
+ + mWallpaper.getComponent());
}
mService = null;
forEachDisplayConnector(connector -> connector.mEngine = null);
@@ -1065,7 +1065,7 @@
fgHandler.postDelayed(mResetRunnable, WALLPAPER_RECONNECT_TIMEOUT_MS);
if (DEBUG_LIVE) {
Slog.i(TAG,
- "Started wallpaper reconnect timeout for " + mWallpaper.wallpaperComponent);
+ "Started wallpaper reconnect timeout for " + mWallpaper.getComponent());
}
}
@@ -1081,7 +1081,7 @@
return;
}
- final ComponentName wpService = mWallpaper.wallpaperComponent;
+ final ComponentName wpService = mWallpaper.getComponent();
// The broadcast of package update could be delayed after service disconnected. Try
// to re-bind the service for 10 seconds.
mWallpaper.mBindSource = BindSource.CONNECTION_TRY_TO_REBIND;
@@ -1110,7 +1110,7 @@
// The wallpaper disappeared. If this isn't a system-default one, track
// crashes and fall back to default if it continues to misbehave.
if (this == mWallpaper.connection) {
- final ComponentName wpService = mWallpaper.wallpaperComponent;
+ final ComponentName wpService = mWallpaper.getComponent();
if (!mWallpaper.wallpaperUpdating
&& mWallpaper.userId == mCurrentUserId
&& !Objects.equals(mDefaultWallpaperComponent, wpService)
@@ -1188,7 +1188,7 @@
synchronized (mLock) {
// Do not broadcast changes on ImageWallpaper since it's handled
// internally by this class.
- boolean isImageWallpaper = mImageWallpaper.equals(mWallpaper.wallpaperComponent);
+ boolean isImageWallpaper = mImageWallpaper.equals(mWallpaper.getComponent());
if (isImageWallpaper && (!offloadColorExtraction() || primaryColors == null)) {
return;
}
@@ -1303,7 +1303,7 @@
if (mNewWallpaper.mWhich == FLAG_SYSTEM) {
// New wp is system only, so old system+lock is now lock only
final boolean originalIsStatic = mImageWallpaper.equals(
- mOriginalSystem.wallpaperComponent);
+ mOriginalSystem.getComponent());
if (originalIsStatic) {
// Static wp: image file rename has already been tried via
// migrateStaticSystemToLockWallpaperLocked() and added to the lock wp map
@@ -1314,8 +1314,7 @@
if (DEBUG) {
Slog.v(TAG, "static system+lock to system success");
}
- lockWp.wallpaperComponent =
- mOriginalSystem.wallpaperComponent;
+ lockWp.setComponent(mOriginalSystem.getComponent());
lockWp.connection = mOriginalSystem.connection;
lockWp.connection.mWallpaper = lockWp;
mOriginalSystem.mWhich = FLAG_LOCK;
@@ -1376,7 +1375,7 @@
return;
}
for (WallpaperData wallpaper: getWallpapers()) {
- final ComponentName wpService = wallpaper.wallpaperComponent;
+ final ComponentName wpService = wallpaper.getComponent();
if (wpService != null && wpService.getPackageName().equals(packageName)) {
if (DEBUG_LIVE) {
Slog.i(TAG, "Wallpaper " + wpService + " update has finished");
@@ -1402,8 +1401,8 @@
return;
}
for (WallpaperData wallpaper: getWallpapers()) {
- if (wallpaper.wallpaperComponent != null
- && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
+ if (wallpaper.getComponent() != null
+ && wallpaper.getComponent().getPackageName().equals(packageName)) {
doPackagesChangedLocked(true, wallpaper);
}
}
@@ -1417,10 +1416,10 @@
return;
}
for (WallpaperData wallpaper: getWallpapers()) {
- if (wallpaper.wallpaperComponent != null
- && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
+ if (wallpaper.getComponent() != null
+ && wallpaper.getComponent().getPackageName().equals(packageName)) {
if (DEBUG_LIVE) {
- Slog.i(TAG, "Wallpaper service " + wallpaper.wallpaperComponent
+ Slog.i(TAG, "Wallpaper service " + wallpaper.getComponent()
+ " is updating");
}
wallpaper.wallpaperUpdating = true;
@@ -1462,15 +1461,15 @@
boolean doPackagesChangedLocked(boolean doit, WallpaperData wallpaper) {
boolean changed = false;
- if (wallpaper.wallpaperComponent != null) {
- int change = isPackageDisappearing(wallpaper.wallpaperComponent
+ if (wallpaper.getComponent() != null) {
+ int change = isPackageDisappearing(wallpaper.getComponent()
.getPackageName());
if (change == PACKAGE_PERMANENT_CHANGE
|| change == PACKAGE_TEMPORARY_CHANGE) {
changed = true;
if (doit) {
Slog.w(TAG, "Wallpaper uninstalled, removing: "
- + wallpaper.wallpaperComponent);
+ + wallpaper.getComponent());
clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, false, null);
}
}
@@ -1485,15 +1484,15 @@
}
}
}
- if (wallpaper.wallpaperComponent != null
- && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) {
+ if (wallpaper.getComponent() != null
+ && isPackageModified(wallpaper.getComponent().getPackageName())) {
try {
- mContext.getPackageManager().getServiceInfo(wallpaper.wallpaperComponent,
+ mContext.getPackageManager().getServiceInfo(wallpaper.getComponent(),
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
} catch (NameNotFoundException e) {
Slog.w(TAG, "Wallpaper component gone, removing: "
- + wallpaper.wallpaperComponent);
+ + wallpaper.getComponent());
clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, false, null);
}
}
@@ -1636,8 +1635,8 @@
// sure we have something to render
boolean isImageComponent;
if (removeNextWallpaperComponent()) {
- isImageComponent = wallpaper.wallpaperComponent == null
- || mImageWallpaper.equals(wallpaper.wallpaperComponent);
+ isImageComponent = wallpaper.getComponent() == null
+ || mImageWallpaper.equals(wallpaper.getComponent());
} else {
isImageComponent = mImageWallpaper.equals(wallpaper.nextWallpaperComponent);
}
@@ -1892,10 +1891,10 @@
final ComponentName cname;
if (removeNextWallpaperComponent()) {
- cname = wallpaper.wallpaperComponent;
+ cname = wallpaper.getComponent();
} else {
- cname = (wallpaper.wallpaperComponent != null)
- ? wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
+ cname = (wallpaper.getComponent() != null)
+ ? wallpaper.getComponent() : wallpaper.nextWallpaperComponent;
}
if (!bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) {
// We failed to bind the desired wallpaper, but that might
@@ -1927,7 +1926,7 @@
// We might end up persisting the current wallpaper data
// while locked, so pretend like the component was actually
// bound into place
- wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent;
+ wallpaper.setComponent(wallpaper.nextWallpaperComponent);
}
final WallpaperData fallback = new WallpaperData(wallpaper.userId, wallpaper.mWhich);
@@ -2004,7 +2003,7 @@
// lock only case: set the system wallpaper component to both screens
if (which == FLAG_LOCK) {
- component = wallpaper.wallpaperComponent;
+ component = wallpaper.getComponent();
finalWhich = FLAG_LOCK | FLAG_SYSTEM;
} else {
component = null;
@@ -2310,7 +2309,7 @@
checkPermission(READ_WALLPAPER_INTERNAL);
WallpaperData wallpaper = (which == FLAG_LOCK) ? mLockWallpaperMap.get(userId)
: mWallpaperMap.get(userId);
- if (wallpaper == null || !mImageWallpaper.equals(wallpaper.wallpaperComponent)) {
+ if (wallpaper == null || !mImageWallpaper.equals(wallpaper.getComponent())) {
return null;
}
SparseArray<Rect> relativeSuggestedCrops =
@@ -2760,7 +2759,7 @@
WallpaperData wallpaperData = (which == FLAG_LOCK ? mLockWallpaperMap : mWallpaperMap)
.get(mCurrentUserId);
if (wallpaperData == null) return false;
- return mImageWallpaper.equals(wallpaperData.wallpaperComponent);
+ return mImageWallpaper.equals(wallpaperData.getComponent());
}
}
@@ -2996,7 +2995,7 @@
final WallpaperData originalSystemWallpaper = mWallpaperMap.get(userId);
final boolean systemIsStatic =
originalSystemWallpaper != null && mImageWallpaper.equals(
- originalSystemWallpaper.wallpaperComponent);
+ originalSystemWallpaper.getComponent());
final boolean systemIsBoth = mLockWallpaperMap.get(userId) == null;
/* If we're setting system but not lock, and lock is currently sharing the system
@@ -3190,7 +3189,7 @@
throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
}
final boolean systemIsStatic = mImageWallpaper.equals(
- originalSystemWallpaper.wallpaperComponent);
+ originalSystemWallpaper.getComponent());
final boolean systemIsBoth = mLockWallpaperMap.get(userId) == null;
if (which == FLAG_SYSTEM && systemIsBoth && systemIsStatic) {
@@ -3212,7 +3211,7 @@
liveSync = new WallpaperDestinationChangeHandler(
newWallpaper);
boolean same = changingToSame(name, newWallpaper.connection,
- newWallpaper.wallpaperComponent);
+ newWallpaper.getComponent());
/*
* If we have a shared system+lock wallpaper, and we reapply the same wallpaper
@@ -3243,7 +3242,7 @@
}
}
boolean lockBitmapCleared = false;
- if (!mImageWallpaper.equals(newWallpaper.wallpaperComponent)) {
+ if (!mImageWallpaper.equals(newWallpaper.getComponent())) {
clearWallpaperBitmaps(newWallpaper);
lockBitmapCleared = newWallpaper.mWhich == FLAG_LOCK;
}
@@ -3324,7 +3323,7 @@
}
// Has the component changed?
if (!force && changingToSame(componentName, wallpaper.connection,
- wallpaper.wallpaperComponent)) {
+ wallpaper.getComponent())) {
try {
if (DEBUG_LIVE) {
Slog.v(TAG, "Changing to the same component, ignoring");
@@ -3461,7 +3460,7 @@
return false;
}
maybeDetachLastWallpapers(wallpaper);
- wallpaper.wallpaperComponent = componentName;
+ wallpaper.setComponent(componentName);
wallpaper.connection = newConn;
newConn.mReply = reply;
updateCurrentWallpapers(wallpaper);
@@ -3586,7 +3585,7 @@
}
private void clearWallpaperComponentLocked(WallpaperData wallpaper) {
- wallpaper.wallpaperComponent = null;
+ wallpaper.setComponent(null);
detachWallpaperLocked(wallpaper);
}
@@ -3831,7 +3830,7 @@
wallpaper.wallpaperId = makeWallpaperIdLocked(); // always bump id at restore
wallpaper.allowBackup = true; // by definition if it was restored
ComponentName componentName =
- removeNextWallpaperComponent() ? wallpaper.wallpaperComponent
+ removeNextWallpaperComponent() ? wallpaper.getComponent()
: wallpaper.nextWallpaperComponent;
if (componentName != null && !componentName.equals(mImageWallpaper)) {
wallpaper.mBindSource = BindSource.RESTORE_SETTINGS_LIVE_SUCCESS;
@@ -3907,7 +3906,7 @@
if (multiCrop()) pw.print(" mCropHints="); pw.println(wallpaper.mCropHints);
pw.print(" mName="); pw.println(wallpaper.name);
pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup);
- pw.print(" mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent);
+ pw.print(" mWallpaperComponent="); pw.println(wallpaper.getComponent());
pw.print(" mWallpaperDimAmount="); pw.println(wallpaper.mWallpaperDimAmount);
pw.print(" isColorExtracted="); pw.println(wallpaper.mIsColorExtractedFromDim);
pw.println(" mUidToDimAmount:");
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 3d5b273..6009b4a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6218,7 +6218,8 @@
public void onProcessRemoved(String name, int uid) {
synchronized (mGlobalLockWithoutBoost) {
final WindowProcessController proc = mProcessNames.remove(name, uid);
- if (proc != null && !mStartingProcessActivities.isEmpty()) {
+ if (proc != null && !proc.mHasEverAttached
+ && !mStartingProcessActivities.isEmpty()) {
// Use a copy in case finishIfPossible changes the list indirectly.
final ArrayList<ActivityRecord> activities =
new ArrayList<>(mStartingProcessActivities);
diff --git a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
index cc6904f..34b5f6a 100644
--- a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
+++ b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
@@ -103,7 +103,7 @@
final TaskDisplayArea displayArea = task.getDisplayArea();
final Rect screenBounds = displayArea.getBounds();
final Size idealSize = calculateIdealSize(screenBounds, DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
- if (!DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(activity.mWmService.mContext)) {
+ if (!DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()) {
return centerInScreen(idealSize, screenBounds);
}
if (activity.mAppCompatController.getAppCompatAspectRatioOverrides()
diff --git a/services/core/java/com/android/server/wm/DesktopModeHelper.java b/services/core/java/com/android/server/wm/DesktopModeHelper.java
index 61fbb96..b5ea0bd 100644
--- a/services/core/java/com/android/server/wm/DesktopModeHelper.java
+++ b/services/core/java/com/android/server/wm/DesktopModeHelper.java
@@ -35,8 +35,8 @@
"persist.wm.debug.desktop_mode_enforce_device_restrictions", true);
/** Whether desktop mode is enabled. */
- static boolean isDesktopModeEnabled(@NonNull Context context) {
- return DesktopModeFlags.DESKTOP_WINDOWING_MODE.isEnabled(context);
+ static boolean isDesktopModeEnabled() {
+ return DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE.isTrue();
}
/**
@@ -60,7 +60,7 @@
* Return {@code true} if desktop mode can be entered on the current device.
*/
static boolean canEnterDesktopMode(@NonNull Context context) {
- return isDesktopModeEnabled(context)
+ return isDesktopModeEnabled()
&& (!shouldEnforceDeviceRestrictions() || isDesktopModeSupported(context));
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 8f5612c..84072e2 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1841,6 +1841,7 @@
}
boolean attachApplication(WindowProcessController app) throws RemoteException {
+ app.mHasEverAttached = true;
final ArrayList<ActivityRecord> activities = mService.mStartingProcessActivities;
RemoteException remoteException = null;
boolean hasActivityStarted = false;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a2fda0a..86bb75a 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -35,6 +35,8 @@
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
+import static android.content.pm.ActivityInfo.FORCE_NON_RESIZE_APP;
+import static android.content.pm.ActivityInfo.FORCE_RESIZE_APP;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
@@ -49,6 +51,7 @@
import static android.view.SurfaceControl.METADATA_TASK_ID;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED;
@@ -133,6 +136,7 @@
import android.app.PictureInPictureParams;
import android.app.TaskInfo;
import android.app.WindowConfiguration;
+import android.app.compat.CompatChanges;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -503,6 +507,12 @@
int mOffsetXForInsets;
int mOffsetYForInsets;
+ /**
+ * Whether the compatibility overrides that change the resizability of the app should be allowed
+ * for the specific app.
+ */
+ boolean mAllowForceResizeOverride = true;
+
private final AnimatingActivityRegistry mAnimatingActivityRegistry =
new AnimatingActivityRegistry();
@@ -666,6 +676,7 @@
intent = _intent;
mMinWidth = minWidth;
mMinHeight = minHeight;
+ updateAllowForceResizeOverride();
}
mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
mHandler = new ActivityTaskHandler(mTaskSupervisor.mLooper);
@@ -1028,6 +1039,7 @@
mTaskSupervisor.mRecentTasks.remove(this);
mTaskSupervisor.mRecentTasks.add(this);
}
+ updateAllowForceResizeOverride();
}
/** Sets the original minimal width and height. */
@@ -1823,6 +1835,17 @@
-1 /* don't check PID */, -1 /* don't check UID */, this);
}
+ private void updateAllowForceResizeOverride() {
+ try {
+ mAllowForceResizeOverride = mAtmService.mContext.getPackageManager().getProperty(
+ PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES,
+ getBasePackageName()).getBoolean();
+ } catch (PackageManager.NameNotFoundException e) {
+ // Package not found or property not defined, reset to default value.
+ mAllowForceResizeOverride = true;
+ }
+ }
+
/**
* Check that a given bounds matches the application requested orientation.
*
@@ -2812,7 +2835,18 @@
boolean isResizeable(boolean checkPictureInPictureSupport) {
final boolean forceResizable = mAtmService.mForceResizableActivities
&& getActivityType() == ACTIVITY_TYPE_STANDARD;
- return forceResizable || ActivityInfo.isResizeableMode(mResizeMode)
+ if (forceResizable) return true;
+
+ final UserHandle userHandle = UserHandle.getUserHandleForUid(mUserId);
+ final boolean forceResizableOverride = mAllowForceResizeOverride
+ && CompatChanges.isChangeEnabled(
+ FORCE_RESIZE_APP, getBasePackageName(), userHandle);
+ final boolean forceNonResizableOverride = mAllowForceResizeOverride
+ && CompatChanges.isChangeEnabled(
+ FORCE_NON_RESIZE_APP, getBasePackageName(), userHandle);
+
+ if (forceNonResizableOverride) return false;
+ return forceResizableOverride || ActivityInfo.isResizeableMode(mResizeMode)
|| (mSupportsPictureInPicture && checkPictureInPictureSupport);
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 655a6fb..0a47522 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -2925,6 +2925,9 @@
final TaskFragment taskFragment = target.asTaskFragment();
final boolean isEmbeddedTaskFragment = taskFragment != null
&& taskFragment.isEmbedded();
+ final IBinder taskFragmentToken =
+ taskFragment != null ? taskFragment.getFragmentToken() : null;
+ change.setTaskFragmentToken(taskFragmentToken);
final ActivityRecord activityRecord = target.asActivityRecord();
if (task != null) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 9d46529..0a9cb1c 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -35,6 +35,7 @@
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.window.TaskFragmentAnimationParams.DEFAULT_ANIMATION_BACKGROUND_COLOR;
+import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
@@ -115,7 +116,6 @@
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import com.android.server.wm.utils.AlwaysTruePredicate;
-import com.android.window.flags.Flags;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -457,7 +457,7 @@
source.setFrame(provider.getArbitraryRectangle())
.updateSideHint(getBounds())
.setBoundingRects(provider.getBoundingRects());
- if (Flags.enableCaptionCompatInsetForceConsumption()) {
+ if (ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isTrue()) {
source.setFlags(provider.getFlags());
}
mLocalInsetsSources.put(id, source);
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 30d6f0a..32fe303 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -204,6 +204,9 @@
// Set to true when process was launched with a wrapper attached
private volatile boolean mUsingWrapper;
+ /** Whether this process has ever completed ActivityThread#handleBindApplication. */
+ boolean mHasEverAttached;
+
/** Non-null if this process may have a window. */
@Nullable
Session mWindowSession;
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 8c4448e..5cd117b 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -357,6 +357,7 @@
FloatPoint getMouseCursorPosition(ui::LogicalDisplayId displayId);
void setStylusPointerIconEnabled(bool enabled);
void setInputMethodConnectionIsActive(bool isActive);
+ void setKeyRemapping(const std::map<int32_t, int32_t>& keyRemapping);
/* --- InputReaderPolicyInterface implementation --- */
@@ -504,6 +505,9 @@
// True if there is an active input method connection.
bool isInputMethodConnectionActive{false};
+
+ // Keycodes to be remapped.
+ std::map<int32_t /* fromKeyCode */, int32_t /* toKeyCode */> keyRemapping{};
} mLocked GUARDED_BY(mLock);
std::atomic<bool> mInteractive;
@@ -761,6 +765,8 @@
outConfig->stylusButtonMotionEventsEnabled = mLocked.stylusButtonMotionEventsEnabled;
outConfig->stylusPointerIconEnabled = mLocked.stylusPointerIconEnabled;
+
+ outConfig->keyRemapping = mLocked.keyRemapping;
} // release lock
}
@@ -1808,9 +1814,30 @@
ATRACE_CALL();
JNIEnv* env = jniEnv();
- for (int32_t iconId = static_cast<int32_t>(PointerIconStyle::TYPE_CONTEXT_MENU);
- iconId <= static_cast<int32_t>(PointerIconStyle::TYPE_HANDWRITING); ++iconId) {
- const PointerIconStyle pointerIconStyle = static_cast<PointerIconStyle>(iconId);
+ constexpr static std::array ADDITIONAL_STYLES{PointerIconStyle::TYPE_CONTEXT_MENU,
+ PointerIconStyle::TYPE_HAND,
+ PointerIconStyle::TYPE_HELP,
+ PointerIconStyle::TYPE_WAIT,
+ PointerIconStyle::TYPE_CELL,
+ PointerIconStyle::TYPE_CROSSHAIR,
+ PointerIconStyle::TYPE_TEXT,
+ PointerIconStyle::TYPE_VERTICAL_TEXT,
+ PointerIconStyle::TYPE_ALIAS,
+ PointerIconStyle::TYPE_COPY,
+ PointerIconStyle::TYPE_NO_DROP,
+ PointerIconStyle::TYPE_ALL_SCROLL,
+ PointerIconStyle::TYPE_HORIZONTAL_DOUBLE_ARROW,
+ PointerIconStyle::TYPE_VERTICAL_DOUBLE_ARROW,
+ PointerIconStyle::TYPE_TOP_RIGHT_DOUBLE_ARROW,
+ PointerIconStyle::TYPE_TOP_LEFT_DOUBLE_ARROW,
+ PointerIconStyle::TYPE_ZOOM_IN,
+ PointerIconStyle::TYPE_ZOOM_OUT,
+ PointerIconStyle::TYPE_GRAB,
+ PointerIconStyle::TYPE_GRABBING,
+ PointerIconStyle::TYPE_HANDWRITING,
+ PointerIconStyle::TYPE_SPOT_HOVER};
+
+ for (const auto pointerIconStyle : ADDITIONAL_STYLES) {
PointerIcon pointerIcon = loadPointerIcon(env, displayId, pointerIconStyle);
(*outResources)[pointerIconStyle] = toSpriteIcon(pointerIcon);
if (!pointerIcon.bitmapFrames.empty()) {
@@ -1889,6 +1916,16 @@
mInputManager->getDispatcher().setInputMethodConnectionIsActive(isActive);
}
+void NativeInputManager::setKeyRemapping(const std::map<int32_t, int32_t>& keyRemapping) {
+ { // acquire lock
+ std::scoped_lock _l(mLock);
+ mLocked.keyRemapping = keyRemapping;
+ } // release lock
+
+ mInputManager->getReader().requestRefreshConfiguration(
+ InputReaderConfiguration::Change::KEY_REMAPPING);
+}
+
// ----------------------------------------------------------------------------
static NativeInputManager* getNativeInputManager(JNIEnv* env, jobject clazz) {
@@ -1962,10 +1999,19 @@
return vec;
}
-static void nativeAddKeyRemapping(JNIEnv* env, jobject nativeImplObj, jint deviceId,
- jint fromKeyCode, jint toKeyCode) {
+static void nativeSetKeyRemapping(JNIEnv* env, jobject nativeImplObj, jintArray fromKeyCodesArr,
+ jintArray toKeyCodesArr) {
+ const std::vector<int32_t> fromKeycodes = getIntArray(env, fromKeyCodesArr);
+ const std::vector<int32_t> toKeycodes = getIntArray(env, toKeyCodesArr);
+ if (fromKeycodes.size() != toKeycodes.size()) {
+ jniThrowRuntimeException(env, "FromKeycodes and toKeycodes cannot match.");
+ }
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
- im->getInputManager()->getReader().addKeyRemapping(deviceId, fromKeyCode, toKeyCode);
+ std::map<int32_t, int32_t> keyRemapping;
+ for (int i = 0; i < fromKeycodes.size(); i++) {
+ keyRemapping.insert_or_assign(fromKeycodes[i], toKeycodes[i]);
+ }
+ im->setKeyRemapping(keyRemapping);
}
static jboolean nativeHasKeys(JNIEnv* env, jobject nativeImplObj, jint deviceId, jint sourceMask,
@@ -2470,7 +2516,7 @@
jTypeId = env->GetStaticIntField(gLightClassInfo.clazz,
gLightClassInfo.lightTypeKeyboardMicMute);
} else {
- ALOGW("Unknown light type %d", lightInfo.type);
+ ALOGW("Unknown light type %s", ftl::enum_string(lightInfo.type).c_str());
continue;
}
@@ -2704,12 +2750,13 @@
}
static void nativeSetKeyRepeatConfiguration(JNIEnv* env, jobject nativeImplObj, jint timeoutMs,
- jint delayMs) {
+ jint delayMs, jboolean keyRepeatEnabled) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
im->getInputManager()->getDispatcher().setKeyRepeatConfiguration(std::chrono::milliseconds(
timeoutMs),
std::chrono::milliseconds(
- delayMs));
+ delayMs),
+ keyRepeatEnabled);
}
static jobject createInputSensorInfo(JNIEnv* env, jstring name, jstring vendor, jint version,
@@ -2933,7 +2980,7 @@
{"getScanCodeState", "(III)I", (void*)nativeGetScanCodeState},
{"getKeyCodeState", "(III)I", (void*)nativeGetKeyCodeState},
{"getSwitchState", "(III)I", (void*)nativeGetSwitchState},
- {"addKeyRemapping", "(III)V", (void*)nativeAddKeyRemapping},
+ {"setKeyRemapping", "([I[I)V", (void*)nativeSetKeyRemapping},
{"hasKeys", "(II[I[Z)Z", (void*)nativeHasKeys},
{"getKeyCodeForKeyLocation", "(II)I", (void*)nativeGetKeyCodeForKeyLocation},
{"createInputChannel", "(Ljava/lang/String;)Landroid/view/InputChannel;",
@@ -3008,7 +3055,7 @@
{"setDisplayEligibilityForPointerCapture", "(IZ)V",
(void*)nativeSetDisplayEligibilityForPointerCapture},
{"setMotionClassifierEnabled", "(Z)V", (void*)nativeSetMotionClassifierEnabled},
- {"setKeyRepeatConfiguration", "(II)V", (void*)nativeSetKeyRepeatConfiguration},
+ {"setKeyRepeatConfiguration", "(IIZ)V", (void*)nativeSetKeyRepeatConfiguration},
{"getSensorList", "(I)[Landroid/hardware/input/InputSensorInfo;",
(void*)nativeGetSensorList},
{"getTouchpadHardwareProperties",
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ab459df..3b334ec 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -107,7 +107,7 @@
import com.android.internal.os.RuntimeInit;
import com.android.internal.policy.AttributeCache;
import com.android.internal.protolog.ProtoLog;
-import com.android.internal.protolog.ProtoLogConfigurationService;
+import com.android.internal.protolog.ProtoLogConfigurationServiceImpl;
import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.EmergencyAffordanceManager;
@@ -436,6 +436,10 @@
private static final String PROFILING_SERVICE_JAR_PATH =
"/apex/com.android.profiling/javalib/service-profiling.jar";
+ private static final String RANGING_APEX_SERVICE_JAR_PATH =
+ "/apex/com.android.uwb/javalib/service-ranging.jar";
+ private static final String RANGING_SERVICE_CLASS = "com.android.server.ranging.RangingService";
+
private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
@@ -1097,7 +1101,7 @@
if (android.tracing.Flags.clientSideProtoLogging()) {
t.traceBegin("StartProtoLogConfigurationService");
ServiceManager.addService(
- Context.PROTOLOG_CONFIGURATION_SERVICE, new ProtoLogConfigurationService());
+ Context.PROTOLOG_CONFIGURATION_SERVICE, new ProtoLogConfigurationServiceImpl());
t.traceEnd();
}
@@ -3015,6 +3019,17 @@
t.traceEnd();
}
+ if (com.android.ranging.flags.Flags.rangingStackEnabled()) {
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)
+ || context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI_RTT)) {
+ t.traceBegin("RangingService");
+ mSystemServiceManager.startServiceFromJar(RANGING_SERVICE_CLASS,
+ RANGING_APEX_SERVICE_JAR_PATH);
+ t.traceEnd();
+ }
+ }
+
t.traceBegin("StartBootPhaseDeviceSpecificServicesReady");
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
t.traceEnd();
diff --git a/services/tests/appfunctions/src/android/app/appfunctions/AppFunctionRuntimeMetadataTest.kt b/services/tests/appfunctions/src/android/app/appfunctions/AppFunctionRuntimeMetadataTest.kt
index dbbb2fe..da3e94f 100644
--- a/services/tests/appfunctions/src/android/app/appfunctions/AppFunctionRuntimeMetadataTest.kt
+++ b/services/tests/appfunctions/src/android/app/appfunctions/AppFunctionRuntimeMetadataTest.kt
@@ -112,4 +112,28 @@
assertThat(runtimeMetadata.appFunctionStaticMetadataQualifiedId)
.isEqualTo("android\$apps-db/app_functions#com.pkg/funcId")
}
+
+ @Test
+ fun setEnabled_true() {
+ val runtimeMetadata =
+ AppFunctionRuntimeMetadata.Builder("com.pkg", "funcId").setEnabled(true).build()
+
+ assertThat(runtimeMetadata.enabled).isTrue()
+ }
+
+ @Test
+ fun setEnabled_false() {
+ val runtimeMetadata =
+ AppFunctionRuntimeMetadata.Builder("com.pkg", "funcId").setEnabled(false).build()
+
+ assertThat(runtimeMetadata.enabled).isFalse()
+ }
+
+ @Test
+ fun setEnabled_null() {
+ val runtimeMetadata =
+ AppFunctionRuntimeMetadata.Builder("com.pkg", "funcId").setEnabled(null).build()
+
+ assertThat(runtimeMetadata.enabled).isNull()
+ }
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeClamperTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeClamperTest.java
deleted file mode 100644
index 306b4f8..0000000
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeClamperTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.display.brightness.clamper;
-
-import static com.android.server.display.brightness.clamper.BrightnessWearBedtimeModeClamper.BEDTIME_MODE_OFF;
-import static com.android.server.display.brightness.clamper.BrightnessWearBedtimeModeClamper.BEDTIME_MODE_ON;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.verify;
-
-import android.content.ContentResolver;
-import android.database.ContentObserver;
-import android.provider.Settings;
-import android.testing.TestableContext;
-
-import androidx.annotation.NonNull;
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import com.android.internal.display.BrightnessSynchronizer;
-import com.android.server.testutils.TestHandler;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-public class BrightnessWearBedtimeModeClamperTest {
-
- private static final float BRIGHTNESS_CAP = 0.3f;
-
- @Mock
- private BrightnessClamperController.ClamperChangeListener mMockClamperChangeListener;
-
- @Rule
- public final TestableContext mContext = new TestableContext(
- InstrumentationRegistry.getInstrumentation().getContext());
-
- private final TestHandler mTestHandler = new TestHandler(null);
- private final TestInjector mInjector = new TestInjector();
- private BrightnessWearBedtimeModeClamper mClamper;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mClamper = new BrightnessWearBedtimeModeClamper(mInjector, mTestHandler, mContext,
- mMockClamperChangeListener, () -> BRIGHTNESS_CAP);
- mTestHandler.flush();
- }
-
- @Test
- public void testBrightnessCap() {
- assertEquals(BRIGHTNESS_CAP, mClamper.getBrightnessCap(), BrightnessSynchronizer.EPSILON);
- }
-
- @Test
- public void testBedtimeModeOn() {
- setBedtimeModeEnabled(true);
- assertTrue(mClamper.isActive());
- verify(mMockClamperChangeListener).onChanged();
- }
-
- @Test
- public void testBedtimeModeOff() {
- setBedtimeModeEnabled(false);
- assertFalse(mClamper.isActive());
- verify(mMockClamperChangeListener).onChanged();
- }
-
- @Test
- public void testType() {
- assertEquals(BrightnessClamper.Type.WEAR_BEDTIME_MODE, mClamper.getType());
- }
-
- @Test
- public void testOnDisplayChanged() {
- float newBrightnessCap = 0.61f;
-
- mClamper.onDisplayChanged(() -> newBrightnessCap);
- mTestHandler.flush();
-
- assertEquals(newBrightnessCap, mClamper.getBrightnessCap(), BrightnessSynchronizer.EPSILON);
- verify(mMockClamperChangeListener).onChanged();
- }
-
- private void setBedtimeModeEnabled(boolean enabled) {
- Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.Wearable.BEDTIME_MODE,
- enabled ? BEDTIME_MODE_ON : BEDTIME_MODE_OFF);
- mInjector.notifyBedtimeModeChanged();
- mTestHandler.flush();
- }
-
- private static class TestInjector extends BrightnessWearBedtimeModeClamper.Injector {
-
- private ContentObserver mObserver;
-
- @Override
- void registerBedtimeModeObserver(@NonNull ContentResolver cr,
- @NonNull ContentObserver observer) {
- mObserver = observer;
- }
-
- private void notifyBedtimeModeChanged() {
- if (mObserver != null) {
- mObserver.dispatchChange(/* selfChange= */ false,
- Settings.Global.getUriFor(Settings.Global.Wearable.BEDTIME_MODE));
- }
- }
- }
-}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeModifierTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeModifierTest.java
new file mode 100644
index 0000000..8271a0f
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeModifierTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.clamper;
+
+import static com.android.server.display.brightness.clamper.BrightnessWearBedtimeModeModifier.BEDTIME_MODE_OFF;
+import static com.android.server.display.brightness.clamper.BrightnessWearBedtimeModeModifier.BEDTIME_MODE_ON;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.hardware.display.BrightnessInfo;
+import android.hardware.display.DisplayManagerInternal;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.testing.TestableContext;
+
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.display.BrightnessSynchronizer;
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.DisplayDeviceConfig;
+import com.android.server.display.brightness.BrightnessReason;
+import com.android.server.display.brightness.clamper.BrightnessClamperController.ModifiersAggregatedState;
+import com.android.server.testutils.TestHandler;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class BrightnessWearBedtimeModeModifierTest {
+ private static final int NO_MODIFIER = 0;
+ private static final float BRIGHTNESS_CAP = 0.3f;
+ private static final String DISPLAY_ID = "displayId";
+
+ @Mock
+ private BrightnessClamperController.ClamperChangeListener mMockClamperChangeListener;
+ @Mock
+ private DisplayManagerInternal.DisplayPowerRequest mMockRequest;
+ @Mock
+ private DisplayDeviceConfig mMockDisplayDeviceConfig;
+ @Mock
+ private IBinder mMockBinder;
+
+ @Rule
+ public final TestableContext mContext = new TestableContext(
+ InstrumentationRegistry.getInstrumentation().getContext());
+
+ private final TestHandler mTestHandler = new TestHandler(null);
+ private final TestInjector mInjector = new TestInjector();
+ private BrightnessWearBedtimeModeModifier mModifier;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mModifier = new BrightnessWearBedtimeModeModifier(mInjector, mTestHandler, mContext,
+ mMockClamperChangeListener, () -> BRIGHTNESS_CAP);
+ mTestHandler.flush();
+ }
+
+ @Test
+ public void testBedtimeModeOff() {
+ setBedtimeModeEnabled(false);
+ assertModifierState(
+ 0.5f, true,
+ PowerManager.BRIGHTNESS_MAX, 0.5f,
+ false, true);
+ verify(mMockClamperChangeListener).onChanged();
+ }
+
+ @Test
+ public void testBedtimeModeOn() {
+ setBedtimeModeEnabled(true);
+ assertModifierState(
+ 0.5f, true,
+ BRIGHTNESS_CAP, BRIGHTNESS_CAP,
+ true, false);
+ verify(mMockClamperChangeListener).onChanged();
+ }
+
+ @Test
+ public void testOnDisplayChanged() {
+ setBedtimeModeEnabled(true);
+ clearInvocations(mMockClamperChangeListener);
+ float newBrightnessCap = 0.61f;
+ onDisplayChange(newBrightnessCap);
+ mTestHandler.flush();
+
+ assertModifierState(
+ 0.5f, true,
+ newBrightnessCap, 0.5f,
+ true, false);
+ verify(mMockClamperChangeListener).onChanged();
+ }
+
+ private void setBedtimeModeEnabled(boolean enabled) {
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.Wearable.BEDTIME_MODE,
+ enabled ? BEDTIME_MODE_ON : BEDTIME_MODE_OFF);
+ mInjector.notifyBedtimeModeChanged();
+ mTestHandler.flush();
+ }
+
+ private void onDisplayChange(float brightnessCap) {
+ when(mMockDisplayDeviceConfig.getBrightnessCapForWearBedtimeMode())
+ .thenReturn(brightnessCap);
+ mModifier.onDisplayChanged(ClamperTestUtilsKt.createDisplayDeviceData(
+ mMockDisplayDeviceConfig, mMockBinder, DISPLAY_ID, DisplayDeviceConfig.DEFAULT_ID));
+ }
+
+ private void assertModifierState(
+ float currentBrightness,
+ boolean currentSlowChange,
+ float maxBrightness, float brightness,
+ boolean isActive,
+ boolean isSlowChange) {
+ ModifiersAggregatedState modifierState = new ModifiersAggregatedState();
+ DisplayBrightnessState.Builder stateBuilder = DisplayBrightnessState.builder();
+ stateBuilder.setBrightness(currentBrightness);
+ stateBuilder.setIsSlowChange(currentSlowChange);
+
+ int maxBrightnessReason = isActive ? BrightnessInfo.BRIGHTNESS_MAX_REASON_WEAR_BEDTIME_MODE
+ : BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
+ int modifier = isActive ? BrightnessReason.MODIFIER_THROTTLED : NO_MODIFIER;
+
+ mModifier.applyStateChange(modifierState);
+ assertThat(modifierState.mMaxBrightness).isEqualTo(maxBrightness);
+ assertThat(modifierState.mMaxBrightnessReason).isEqualTo(maxBrightnessReason);
+
+ mModifier.apply(mMockRequest, stateBuilder);
+
+ assertThat(stateBuilder.getMaxBrightness())
+ .isWithin(BrightnessSynchronizer.EPSILON).of(maxBrightness);
+ assertThat(stateBuilder.getBrightness())
+ .isWithin(BrightnessSynchronizer.EPSILON).of(brightness);
+ assertThat(stateBuilder.getBrightnessMaxReason()).isEqualTo(maxBrightnessReason);
+ assertThat(stateBuilder.getBrightnessReason().getModifier()).isEqualTo(modifier);
+ assertThat(stateBuilder.isSlowChange()).isEqualTo(isSlowChange);
+ }
+
+
+ private static class TestInjector extends BrightnessWearBedtimeModeModifier.Injector {
+
+ private ContentObserver mObserver;
+
+ @Override
+ void registerBedtimeModeObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer) {
+ mObserver = observer;
+ }
+
+ private void notifyBedtimeModeChanged() {
+ if (mObserver != null) {
+ mObserver.dispatchChange(/* selfChange= */ false,
+ Settings.Global.getUriFor(Settings.Global.Wearable.BEDTIME_MODE));
+ }
+ }
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
index 8b65337..32135f1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
@@ -22,9 +22,10 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
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.doCallRealMethod;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
@@ -36,6 +37,7 @@
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
import android.os.Process;
+import android.os.RemoteException;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
@@ -137,9 +139,17 @@
mSensitiveContentProtectionManagerService.mNotificationListener =
spy(mSensitiveContentProtectionManagerService.mNotificationListener);
- doCallRealMethod()
- .when(mSensitiveContentProtectionManagerService.mNotificationListener)
- .onListenerConnected();
+
+ // Unexpected NLS interactions when registered cause test flakes. For purposes of this test,
+ // the test will control any NLS calls.
+ try {
+ doNothing().when(mSensitiveContentProtectionManagerService.mNotificationListener)
+ .registerAsSystemService(any(), any(), anyInt());
+ doNothing().when(mSensitiveContentProtectionManagerService.mNotificationListener)
+ .unregisterAsSystemService();
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
// Setup RankingMap and two possilbe rankings
when(mSensitiveRanking.hasSensitiveContent()).thenReturn(true);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java
index 3dd2f24a..1cad255 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java
@@ -509,8 +509,12 @@
mAppStartInfoTracker.handleProcessBroadcastStart(3, app, buildIntent(COMPONENT),
false /* isAlarm */);
+ // Add a brief delay between timestamps to make sure the clock, which is in milliseconds has
+ // actually incremented.
+ sleep(1);
mAppStartInfoTracker.handleProcessBroadcastStart(2, app, buildIntent(COMPONENT),
false /* isAlarm */);
+ sleep(1);
mAppStartInfoTracker.handleProcessBroadcastStart(1, app, buildIntent(COMPONENT),
false /* isAlarm */);
@@ -557,9 +561,10 @@
// Now load from disk.
mAppStartInfoTracker.loadExistingProcessStartInfo();
- // Confirm clock has been set and that its current time is greater than the previous one.
+ // Confirm clock has been set and that its current time is greater than or equal to the
+ // previous one, thereby ensuring it was loaded from disk.
assertNotNull(mAppStartInfoTracker.mMonotonicClock);
- assertTrue(mAppStartInfoTracker.mMonotonicClock.monotonicTime() > originalMonotonicTime);
+ assertTrue(mAppStartInfoTracker.mMonotonicClock.monotonicTime() >= originalMonotonicTime);
}
private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index f6ad07d..2107406 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -229,8 +229,10 @@
doCallRealMethod().when(mService).enqueueOomAdjTargetLocked(any(ProcessRecord.class));
doCallRealMethod().when(mService).updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_ACTIVITY);
setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object());
- doReturn(new ActivityManagerService.ProcessChangeItem()).when(pr)
- .enqueueProcessChangeItemLocked(anyInt(), anyInt());
+ doNothing().when(pr).enqueueProcessChangeItemLocked(anyInt(), anyInt(), anyInt(),
+ anyInt());
+ doNothing().when(pr).enqueueProcessChangeItemLocked(anyInt(), anyInt(), anyInt(),
+ anyBoolean());
mService.mOomAdjuster = mService.mConstants.ENABLE_NEW_OOMADJ
? new OomAdjusterModernImpl(mService, mService.mProcessList,
new ActiveUids(mService, false), mInjector)
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundUserSoundNotifierTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundUserSoundNotifierTest.java
index 3062d51..9ba2724 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundUserSoundNotifierTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundUserSoundNotifierTest.java
@@ -172,6 +172,7 @@
mBackgroundUserSoundNotifier.muteAlarmSounds(mSpiedContext);
verify(apc1.getPlayerProxy()).stop();
+ verify(mockAudioPolicy).sendFocusLossAndUpdate(afi);
verify(apc2.getPlayerProxy(), never()).stop();
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
index 15ae463..9983fb4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
@@ -32,6 +32,8 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
@@ -50,6 +52,7 @@
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.Flags;
import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.content.ComponentName;
@@ -64,7 +67,10 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.service.wallpaper.IWallpaperConnection;
import android.service.wallpaper.IWallpaperEngine;
import android.service.wallpaper.WallpaperService;
@@ -91,8 +97,10 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -100,6 +108,7 @@
import org.mockito.quality.Strictness;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -125,6 +134,7 @@
@ClassRule
public static final TestableContext sContext = new TestableContext(
InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+
private static ComponentName sImageWallpaperComponentName;
private static ComponentName sDefaultWallpaperComponent;
@@ -133,8 +143,11 @@
@Mock
private DisplayManager mDisplayManager;
+ private final TemporaryFolder mFolder = new TemporaryFolder();
+ private final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Rule
- public final TemporaryFolder mFolder = new TemporaryFolder();
+ public RuleChain rules = RuleChain.outerRule(mSetFlagsRule).around(mFolder);
+
private final SparseArray<File> mTempDirs = new SparseArray<>();
private WallpaperManagerService mService;
private static IWallpaperConnection.Stub sWallpaperService;
@@ -290,7 +303,7 @@
final WallpaperData fallbackData = mService.mFallbackWallpaper;
assertEquals("Fallback wallpaper component should be ImageWallpaper.",
- sImageWallpaperComponentName, fallbackData.wallpaperComponent);
+ sImageWallpaperComponentName, fallbackData.getComponent());
verifyLastWallpaperData(USER_SYSTEM, sDefaultWallpaperComponent);
verifyDisplayData();
@@ -325,6 +338,7 @@
* is issued to the wallpaper.
*/
@Test
+ @Ignore("b/368345733")
public void testSetCurrentComponent() throws Exception {
final int testUserId = USER_SYSTEM;
mService.switchUser(testUserId, null);
@@ -411,26 +425,84 @@
}
@Test
- public void testXmlSerializationRoundtrip() {
- WallpaperData systemWallpaperData = mService.getCurrentWallpaperData(FLAG_SYSTEM, 0);
+ @EnableFlags(Flags.FLAG_REMOVE_NEXT_WALLPAPER_COMPONENT)
+ public void testSaveLoadSettings() {
+ WallpaperData expectedData = mService.getCurrentWallpaperData(FLAG_SYSTEM, 0);
+ expectedData.setComponent(sDefaultWallpaperComponent);
+ expectedData.primaryColors = new WallpaperColors(Color.valueOf(Color.RED),
+ Color.valueOf(Color.BLUE), null);
+ expectedData.mWallpaperDimAmount = 0.5f;
+ expectedData.mUidToDimAmount.put(0, 0.5f);
+ expectedData.mUidToDimAmount.put(1, 0.4f);
+
+ ByteArrayOutputStream ostream = new ByteArrayOutputStream();
try {
TypedXmlSerializer serializer = Xml.newBinarySerializer();
- serializer.setOutput(new ByteArrayOutputStream(), StandardCharsets.UTF_8.name());
- serializer.startDocument(StandardCharsets.UTF_8.name(), true);
- mService.mWallpaperDataParser.writeWallpaperAttributes(
- serializer, "wp", systemWallpaperData);
+ serializer.setOutput(ostream, StandardCharsets.UTF_8.name());
+ mService.mWallpaperDataParser.saveSettingsToSerializer(serializer, expectedData, null);
+ ostream.close();
+ } catch (IOException e) {
+ fail("exception occurred while writing system wallpaper attributes");
+ }
+
+ WallpaperData actualData = new WallpaperData(0, FLAG_SYSTEM);
+ try {
+ ByteArrayInputStream istream = new ByteArrayInputStream(ostream.toByteArray());
+ TypedXmlPullParser parser = Xml.newBinaryPullParser();
+ parser.setInput(istream, StandardCharsets.UTF_8.name());
+ mService.mWallpaperDataParser.loadSettingsFromSerializer(parser,
+ actualData, /* userId= */0, /* loadSystem= */ true, /* loadLock= */
+ false, /* keepDimensionHints= */ true,
+ new WallpaperDisplayHelper.DisplayData(0));
+ } catch (IOException | XmlPullParserException e) {
+ fail("exception occurred while parsing wallpaper");
+ }
+
+ assertThat(actualData.getComponent()).isEqualTo(expectedData.getComponent());
+ assertThat(actualData.primaryColors).isEqualTo(expectedData.primaryColors);
+ assertThat(actualData.mWallpaperDimAmount).isEqualTo(expectedData.mWallpaperDimAmount);
+ assertThat(actualData.mUidToDimAmount).isNotNull();
+ assertThat(actualData.mUidToDimAmount.size()).isEqualTo(
+ expectedData.mUidToDimAmount.size());
+ for (int i = 0; i < actualData.mUidToDimAmount.size(); i++) {
+ int key = actualData.mUidToDimAmount.keyAt(0);
+ assertThat(actualData.mUidToDimAmount.get(key)).isEqualTo(
+ expectedData.mUidToDimAmount.get(key));
+ }
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_REMOVE_NEXT_WALLPAPER_COMPONENT)
+ public void testSaveLoadSettings_legacyNextComponent() {
+ WallpaperData systemWallpaperData = mService.getCurrentWallpaperData(FLAG_SYSTEM, 0);
+ systemWallpaperData.setComponent(sDefaultWallpaperComponent);
+ ByteArrayOutputStream ostream = new ByteArrayOutputStream();
+ try {
+ TypedXmlSerializer serializer = Xml.newBinarySerializer();
+ serializer.setOutput(ostream, StandardCharsets.UTF_8.name());
+ mService.mWallpaperDataParser.saveSettingsToSerializer(serializer, systemWallpaperData,
+ null);
+ ostream.close();
} catch (IOException e) {
fail("exception occurred while writing system wallpaper attributes");
}
WallpaperData shouldMatchSystem = new WallpaperData(0, FLAG_SYSTEM);
try {
+ ByteArrayInputStream istream = new ByteArrayInputStream(ostream.toByteArray());
TypedXmlPullParser parser = Xml.newBinaryPullParser();
- mService.mWallpaperDataParser.parseWallpaperAttributes(parser, shouldMatchSystem, true);
- } catch (XmlPullParserException e) {
+ parser.setInput(istream, StandardCharsets.UTF_8.name());
+ mService.mWallpaperDataParser.loadSettingsFromSerializer(parser,
+ shouldMatchSystem, /* userId= */0, /* loadSystem= */ true, /* loadLock= */
+ false, /* keepDimensionHints= */ true,
+ new WallpaperDisplayHelper.DisplayData(0));
+ } catch (IOException | XmlPullParserException e) {
fail("exception occurred while parsing wallpaper");
}
- assertEquals(systemWallpaperData.primaryColors, shouldMatchSystem.primaryColors);
+
+ assertThat(shouldMatchSystem.nextWallpaperComponent).isEqualTo(
+ systemWallpaperData.getComponent());
+ assertThat(shouldMatchSystem.primaryColors).isEqualTo(systemWallpaperData.primaryColors);
}
@Test
@@ -580,7 +652,7 @@
final WallpaperData lastData = mService.mLastWallpaper;
assertNotNull("Last wallpaper must not be null", lastData);
assertEquals("Last wallpaper component must be equals.", expectedComponent,
- lastData.wallpaperComponent);
+ lastData.getComponent());
assertEquals("The user id in last wallpaper should be the last switched user",
lastUserId, lastData.userId);
assertNotNull("Must exist user data connection on last wallpaper data",
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index a25621a..390eb93 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -61,7 +61,6 @@
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doNothing;
@@ -95,7 +94,6 @@
import android.os.Message;
import android.os.PowerManagerInternal;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.IStorageManager;
@@ -214,10 +212,7 @@
doNothing().when(mInjector).activityManagerOnUserStopped(anyInt());
doNothing().when(mInjector).clearBroadcastQueueForUser(anyInt());
doNothing().when(mInjector).taskSupervisorRemoveUser(anyInt());
- doAnswer(invocation -> {
- ((Runnable) invocation.getArgument(0)).run();
- return null;
- }).when(mInjector).showKeyguard(any());
+ doNothing().when(mInjector).lockDeviceNowAndWaitForKeyguardShown();
mockIsUsersOnSecondaryDisplaysEnabled(false);
// All UserController params are set to default.
@@ -432,6 +427,7 @@
mUserController.registerUserSwitchObserver(observer, "mock");
// Start user -- this will update state of mUserController
mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND);
+ verify(observer, times(1)).onBeforeUserSwitching(eq(TEST_USER_ID));
Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
assertNotNull(reportMsg);
UserState userState = (UserState) reportMsg.obj;
@@ -440,7 +436,6 @@
// Call dispatchUserSwitch and verify that observer was called only once
mInjector.mHandler.clearAllRecordedMessages();
mUserController.dispatchUserSwitch(userState, oldUserId, newUserId);
- verify(observer, times(1)).onBeforeUserSwitching(eq(TEST_USER_ID));
verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
Set<Integer> expectedCodes = Collections.singleton(CONTINUE_USER_SWITCH_MSG);
Set<Integer> actualCodes = mInjector.mHandler.getMessageCodes();
@@ -463,6 +458,7 @@
mUserController.registerUserSwitchObserver(observer, "mock");
// Start user -- this will update state of mUserController
mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND);
+ verify(observer, times(1)).onBeforeUserSwitching(eq(TEST_USER_ID));
Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
assertNotNull(reportMsg);
UserState userState = (UserState) reportMsg.obj;
@@ -471,7 +467,6 @@
// Call dispatchUserSwitch and verify that observer was called only once
mInjector.mHandler.clearAllRecordedMessages();
mUserController.dispatchUserSwitch(userState, oldUserId, newUserId);
- verify(observer, times(1)).onBeforeUserSwitching(eq(TEST_USER_ID));
verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
// Verify that CONTINUE_USER_SWITCH_MSG is not sent (triggers timeout)
Set<Integer> actualCodes = mInjector.mHandler.getMessageCodes();
@@ -554,6 +549,7 @@
expectedCodes.add(REPORT_USER_SWITCH_COMPLETE_MSG);
if (backgroundUserStopping) {
expectedCodes.add(CLEAR_USER_JOURNEY_SESSION_MSG);
+ expectedCodes.add(0); // this is for directly posting in stopping.
}
if (expectScheduleBackgroundUserStopping) {
expectedCodes.add(SCHEDULED_STOP_BACKGROUND_USER_MSG);
@@ -1579,13 +1575,21 @@
// mock the device to be secure in order to expect the keyguard to be shown
when(mInjector.mKeyguardManagerMock.isDeviceSecure(anyInt())).thenReturn(true);
- // call real showKeyguard method for this test
- doCallRealMethod().when(mInjector).showKeyguard(any());
+ // call real lockDeviceNowAndWaitForKeyguardShown method for this test
+ doCallRealMethod().when(mInjector).lockDeviceNowAndWaitForKeyguardShown();
- mUserController.completeUserSwitch(TEST_USER_ID1, TEST_USER_ID2);
+ // call startUser on a thread because we're expecting it to be blocked
+ Thread threadStartUser = new Thread(()-> {
+ mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND);
+ });
+ threadStartUser.start();
- // make sure the switch is stalled by checking the UserSwitchingDialog is not dismissed yet
- verify(mInjector, never()).dismissUserSwitchingDialog(any());
+ // make sure the switch is stalled...
+ Thread.sleep(2000);
+ // by checking REPORT_USER_SWITCH_MSG is not sent yet
+ assertNull(mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG));
+ // and the thread is still alive
+ assertTrue(threadStartUser.isAlive());
// mock send the keyguard shown event
ArgumentCaptor<ActivityTaskManagerInternal.ScreenObserver> captor = ArgumentCaptor.forClass(
@@ -1593,42 +1597,12 @@
verify(mInjector.mActivityTaskManagerInternal).registerScreenObserver(captor.capture());
captor.getValue().onKeyguardStateChanged(true);
- // verify the switch now moves on by checking the UserSwitchingDialog is dismissed
- verify(mInjector, atLeastOnce()).dismissUserSwitchingDialog(any());
-
- // verify that SHOW_KEYGUARD_TIMEOUT is ignored and does not crash the system
- try {
- mInjector.mHandler.processPostDelayedCallbacksWithin(
- UserController.SHOW_KEYGUARD_TIMEOUT_MS);
- } catch (RuntimeException e) {
- throw new AssertionError(
- "SHOW_KEYGUARD_TIMEOUT is not ignored and crashed the system", e);
- }
- }
-
- @Test
- public void testRuntimeExceptionIsThrownIfTheKeyguardIsNotShown() throws Exception {
- // enable user switch ui, because keyguard is only shown then
- mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true,
- /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false,
- /* backgroundUserScheduledStopTimeSecs= */ -1);
-
- // mock the device to be secure in order to expect the keyguard to be shown
- when(mInjector.mKeyguardManagerMock.isDeviceSecure(anyInt())).thenReturn(true);
-
- // suppress showKeyguard method for this test
- doNothing().when(mInjector).showKeyguard(any());
-
- mUserController.completeUserSwitch(TEST_USER_ID1, TEST_USER_ID2);
-
- // verify that the system has crashed
- assertThrows("Should have thrown RuntimeException", RuntimeException.class, () -> {
- mInjector.mHandler.processPostDelayedCallbacksWithin(
- UserController.SHOW_KEYGUARD_TIMEOUT_MS);
- });
-
- // make sure the UserSwitchingDialog is not dismissed
- verify(mInjector, never()).dismissUserSwitchingDialog(any());
+ // verify the switch now moves on...
+ Thread.sleep(1000);
+ // by checking REPORT_USER_SWITCH_MSG is sent
+ assertNotNull(mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG));
+ // and the thread is finished
+ assertFalse(threadStartUser.isAlive());
}
private void setUpAndStartUserInBackground(int userId) throws Exception {
@@ -1989,9 +1963,7 @@
Set<Integer> getMessageCodes() {
Set<Integer> result = new LinkedHashSet<>();
for (Message msg : mMessages) {
- if (msg.what != 0) { // ignore mHandle.post and mHandler.postDelayed messages
- result.add(msg.what);
- }
+ result.add(msg.what);
}
return result;
}
@@ -2015,28 +1987,14 @@
@Override
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
- final Runnable cb = msg.getCallback();
- if (cb != null && uptimeMillis <= SystemClock.uptimeMillis()) {
- // run mHandler.post calls immediately
- cb.run();
- return true;
- }
Message copy = new Message();
copy.copyFrom(msg);
- copy.setCallback(cb);
mMessages.add(copy);
- return super.sendMessageAtTime(msg, uptimeMillis);
- }
-
- public void processPostDelayedCallbacksWithin(long millis) {
- final long whenMax = SystemClock.uptimeMillis() + millis;
- for (Message msg : mMessages) {
- final Runnable cb = msg.getCallback();
- if (cb != null && msg.getWhen() <= whenMax) {
- msg.setCallback(null);
- cb.run();
- }
+ if (msg.getCallback() != null) {
+ msg.getCallback().run();
+ msg.setCallback(null);
}
+ return super.sendMessageAtTime(msg, uptimeMillis);
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/audio/MediaFocusControlTest.java b/services/tests/servicestests/src/com/android/server/audio/MediaFocusControlTest.java
new file mode 100644
index 0000000..34878c8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/audio/MediaFocusControlTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 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.server.audio;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.AudioFocusInfo;
+import android.media.AudioManager;
+import android.os.Binder;
+import android.os.IBinder;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class MediaFocusControlTest {
+ private static final String TAG = "MediaFocusControlTest";
+
+ private Context mContext;
+ private MediaFocusControl mMediaFocusControl;
+ private final IBinder mICallBack = new Binder();
+
+
+ private static class NoopPlayerFocusEnforcer implements PlayerFocusEnforcer {
+ public boolean duckPlayers(@NonNull FocusRequester winner, @NonNull FocusRequester loser,
+ boolean forceDuck) {
+ return true;
+ }
+
+ public void restoreVShapedPlayers(@NonNull FocusRequester winner) {
+ }
+
+ public void mutePlayersForCall(int[] usagesToMute) {
+ }
+
+ public void unmutePlayersForCall() {
+ }
+
+ public boolean fadeOutPlayers(@NonNull FocusRequester winner,
+ @NonNull FocusRequester loser) {
+ return true;
+ }
+
+ public void forgetUid(int uid) {
+ }
+
+ public long getFadeOutDurationMillis(@NonNull AudioAttributes aa) {
+ return 100;
+ }
+
+ public long getFadeInDelayForOffendersMillis(@NonNull AudioAttributes aa) {
+ return 100;
+ }
+
+ public boolean shouldEnforceFade() {
+ return false;
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mMediaFocusControl = new MediaFocusControl(mContext, new NoopPlayerFocusEnforcer());
+ }
+
+ private static final AudioAttributes MEDIA_ATTRIBUTES = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_MEDIA).build();
+ private static final AudioAttributes ALARM_ATTRIBUTES = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_ALARM).build();
+ private static final int MEDIA_UID = 10300;
+ private static final int ALARM_UID = 10301;
+
+ /**
+ * Test {@link MediaFocusControl#sendFocusLossAndUpdate(AudioFocusInfo)}
+ */
+ @Test
+ public void testSendFocusLossAndUpdate() throws Exception {
+ // simulate a media app requesting focus, followed by an alarm
+ mMediaFocusControl.requestAudioFocus(MEDIA_ATTRIBUTES, AudioManager.AUDIOFOCUS_GAIN,
+ mICallBack, null /*focusDispatcher*/, "clientMedia", "packMedia",
+ AudioManager.AUDIOFOCUS_FLAG_TEST /*flags*/, 35 /*sdk*/, false/*forceDuck*/,
+ MEDIA_UID, true /*permissionOverridesCheck*/);
+ final AudioFocusInfo alarm = new AudioFocusInfo(ALARM_ATTRIBUTES, ALARM_UID,
+ "clientAlarm", "packAlarm",
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 0/*lossReceived*/,
+ AudioManager.AUDIOFOCUS_FLAG_TEST /*flags*/, 35 /*sdk*/);
+ mMediaFocusControl.requestAudioFocus(alarm.getAttributes(), alarm.getGainRequest(),
+ mICallBack, null /*focusDispatcher*/, alarm.getClientId(), alarm.getPackageName(),
+ alarm.getFlags(), alarm.getSdkTarget(), false/*forceDuck*/,
+ alarm.getClientUid(), true /*permissionOverridesCheck*/);
+ // verify stack is in expected state
+ List<AudioFocusInfo> stack = mMediaFocusControl.getFocusStack();
+ Assert.assertEquals("focus stack should have 2 entries", 2, stack.size());
+ Assert.assertEquals("focus loser should have received LOSS_TRANSIENT_CAN_DUCK",
+ AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK, stack.get(0).getLossReceived());
+
+ // make alarm app lose focus and check stack
+ mMediaFocusControl.sendFocusLossAndUpdate(alarm);
+ stack = mMediaFocusControl.getFocusStack();
+ Assert.assertEquals("focus stack should have 1 entry after sendFocusLossAndUpdate",
+ 1, stack.size());
+ Assert.assertEquals("new top of stack should be media app",
+ MEDIA_UID, stack.get(0).getClientUid());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index 689b241..abc9ce3 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -50,11 +50,12 @@
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
+import android.annotation.SuppressLint;
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions.LaunchCookie;
+import android.app.AppOpsManager;
import android.app.KeyguardManager;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.ApplicationInfoFlags;
@@ -72,6 +73,7 @@
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.testing.TestableContext;
import android.view.ContentRecordingSession;
import android.view.ContentRecordingSession.RecordContent;
@@ -99,13 +101,14 @@
/**
* Tests for the {@link MediaProjectionManagerService} class.
- *
+ * <p>
* Build/Install/Run:
* atest FrameworksServicesTests:MediaProjectionManagerServiceTest
*/
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
+@SuppressLint({"UseCheckPermission", "VisibleForTests", "MissingPermission"})
public class MediaProjectionManagerServiceTest {
private static final int UID = 10;
private static final String PACKAGE_NAME = "test.package";
@@ -151,7 +154,10 @@
}
};
- private Context mContext;
+ @Rule
+ public final TestableContext mContext = spy(
+ new TestableContext(InstrumentationRegistry.getInstrumentation().getContext()));
+
private MediaProjectionManagerService mService;
private OffsettableClock mClock;
private ContentRecordingSession mWaitingDisplaySession =
@@ -169,6 +175,8 @@
@Mock
private KeyguardManager mKeyguardManager;
@Mock
+ AppOpsManager mAppOpsManager;
+ @Mock
private IMediaProjectionWatcherCallback mWatcherCallback;
@Mock
private MediaProjectionMetricsLogger mMediaProjectionMetricsLogger;
@@ -185,10 +193,9 @@
LocalServices.removeServiceForTest(WindowManagerInternal.class);
LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
- mContext = spy(new ContextWrapper(
- InstrumentationRegistry.getInstrumentation().getTargetContext()));
- doReturn(mPackageManager).when(mContext).getPackageManager();
- doReturn(mKeyguardManager).when(mContext).getSystemService(eq(Context.KEYGUARD_SERVICE));
+ mContext.addMockSystemService(AppOpsManager.class, mAppOpsManager);
+ mContext.addMockSystemService(KeyguardManager.class, mKeyguardManager);
+ mContext.setMockPackageManager(mPackageManager);
mClock = new OffsettableClock.Stopped();
mWaitingDisplaySession.setWaitingForConsent(true);
@@ -291,6 +298,27 @@
assertThat(mService.getActiveProjectionInfo()).isNotNull();
}
+ @SuppressLint("MissingPermission")
+ @EnableFlags(android.companion.virtualdevice.flags
+ .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
+ @Test
+ public void testCreateProjection_keyguardLocked_AppOpMediaProjection()
+ throws NameNotFoundException {
+ MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
+ doReturn(true).when(mAppOpsManager).isOperationActive(eq(AppOpsManager.OP_PROJECT_MEDIA),
+ eq(projection.uid), eq(projection.packageName));
+ doReturn(true).when(mKeyguardManager).isKeyguardLocked();
+
+ doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+ RECORD_SENSITIVE_CONTENT, projection.packageName);
+
+ projection.start(mIMediaProjectionCallback);
+ projection.notifyVirtualDisplayCreated(10);
+
+ // The projection was started because it was allowed to capture the keyguard.
+ assertThat(mService.getActiveProjectionInfo()).isNotNull();
+ }
+
@Test
public void testCreateProjection_attemptReuse_noPriorProjectionGrant()
throws NameNotFoundException {
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 96ddf80..b8f9767 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -2815,7 +2815,8 @@
}
@Test
- @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
+ @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
+ android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
public void testOnlyForceGroupIfNeeded_newNotification_notAutogrouped() {
NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
when(mGroupHelper.onNotificationPosted(any(), anyBoolean())).thenReturn(false);
@@ -2834,7 +2835,8 @@
}
@Test
- @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
+ @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
+ android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST})
public void testOnlyForceGroupIfNeeded_newNotification_wasAutogrouped() {
NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
when(mGroupHelper.onNotificationPosted(any(), anyBoolean())).thenReturn(true);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/VibratorHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/VibratorHelperTest.java
index 4d2396c..65b4ac1 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/VibratorHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/VibratorHelperTest.java
@@ -104,6 +104,12 @@
}
@Test
+ public void createVibrationEffectFromSoundUri_opaqueUri() {
+ Uri uri = Uri.parse("a:b#c");
+ assertNull(mVibratorHelper.createVibrationEffectFromSoundUri(uri));
+ }
+
+ @Test
public void createVibrationEffectFromSoundUri_uriWithoutRequiredQueryParameter() {
Uri uri = Settings.System.DEFAULT_NOTIFICATION_URI;
assertNull(mVibratorHelper.createVibrationEffectFromSoundUri(uri));
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 9b87947..1206928 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -6992,6 +6992,22 @@
assertThat(zenRule.condition).isNotNull();
}
+ @Test
+ @EnableFlags(FLAG_MODES_API)
+ public void addAutomaticZenRule_withoutPolicy_getsItsOwnInstanceOfDefaultPolicy() {
+ // Add a rule without policy -> uses default config
+ AutomaticZenRule azr = new AutomaticZenRule.Builder("Rule", Uri.parse("cond"))
+ .setPackage(mPkg)
+ .build();
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mPkg, azr, ORIGIN_APP, "adding",
+ CUSTOM_PKG_UID);
+
+ ZenRule zenRule = checkNotNull(mZenModeHelper.mConfig.automaticRules.get(ruleId));
+
+ assertThat(zenRule.zenPolicy).isEqualTo(mZenModeHelper.getDefaultZenPolicy());
+ assertThat(zenRule.zenPolicy).isNotSameInstanceAs(mZenModeHelper.getDefaultZenPolicy());
+ }
+
private static void addZenRule(ZenModeConfig config, String id, String ownerPkg, int zenMode,
@Nullable ZenPolicy zenPolicy) {
ZenRule rule = new ZenRule();
diff --git a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
index 7ea5010..ff8b6d3 100644
--- a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
@@ -141,7 +141,8 @@
}
@Override
- void onKeyUp(long eventTime, int multiPressCount, int displayId) {
+ void onKeyUp(long eventTime, int multiPressCount, int displayId, int deviceId,
+ int metaState) {
mKeyUpQueue.add(new KeyUpData(KEYCODE_POWER, multiPressCount));
}
});
@@ -177,7 +178,8 @@
}
@Override
- void onKeyUp(long eventTime, int multiPressCount, int displayId) {
+ void onKeyUp(long eventTime, int multiPressCount, int displayId, int deviceId,
+ int metaState) {
mKeyUpQueue.add(new KeyUpData(KEYCODE_BACK, multiPressCount));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 957b5e0..ae0c6e5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -331,6 +331,7 @@
final WindowProcessController proc = mSystemServicesTestRule.addProcess(
activity.packageName, activity.processName,
6789 /* pid */, activity.info.applicationInfo.uid);
+ assertFalse(proc.mHasEverAttached);
try {
mRootWindowContainer.attachApplication(proc);
verify(mSupervisor).realStartActivityLocked(eq(topActivity), eq(proc),
@@ -338,6 +339,15 @@
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
+
+ // Verify that onProcessRemoved won't clear the launching activities if an attached process
+ // is died. Because in real case, it should be handled from WindowProcessController's
+ // and ActivityRecord's handleAppDied to decide whether to remove the activities.
+ assertTrue(proc.mHasEverAttached);
+ assertTrue(mAtm.mStartingProcessActivities.isEmpty());
+ mAtm.mStartingProcessActivities.add(activity);
+ mAtm.mInternal.onProcessRemoved(proc.mName, proc.mUid);
+ assertFalse(mAtm.mStartingProcessActivities.isEmpty());
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 7ff2e50..4b03483 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -29,6 +29,8 @@
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
@@ -75,6 +77,7 @@
import android.app.ActivityOptions;
import android.app.TaskInfo;
import android.app.WindowConfiguration;
+import android.compat.testing.PlatformCompatChangeRule;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -97,9 +100,13 @@
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
+import libcore.junit.util.compat.CoreCompatChangeRule;
+
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.xmlpull.v1.XmlPullParser;
@@ -122,6 +129,9 @@
@RunWith(WindowTestRunner.class)
public class TaskTests extends WindowTestsBase {
+ @Rule
+ public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
private static final String TASK_TAG = "task";
private Rect mParentBounds;
@@ -404,6 +414,85 @@
}
@Test
+ @CoreCompatChangeRule.EnableCompatChanges({ActivityInfo.FORCE_RESIZE_APP})
+ public void testIsResizeable_nonResizeable_forceResize_overridesEnabled_Resizeable() {
+ final Task task = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true)
+ .setComponent(
+ ComponentName.createRelative(mContext, SizeCompatTests.class.getName()))
+ .build();
+ task.setResizeMode(RESIZE_MODE_UNRESIZEABLE);
+ // Override should take effect and task should be resizeable.
+ assertTrue(task.getTaskInfo().isResizeable);
+ }
+
+ @Test
+ @CoreCompatChangeRule.EnableCompatChanges({ActivityInfo.FORCE_RESIZE_APP})
+ public void testIsResizeable_nonResizeable_forceResize_overridesDisabled_nonResizeable() {
+ final Task task = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true)
+ .setComponent(
+ ComponentName.createRelative(mContext, SizeCompatTests.class.getName()))
+ .build();
+ task.setResizeMode(RESIZE_MODE_UNRESIZEABLE);
+
+ // Disallow resize overrides.
+ task.mAllowForceResizeOverride = false;
+
+ // Override should not take effect and task should be un-resizeable.
+ assertFalse(task.getTaskInfo().isResizeable);
+ }
+
+ @Test
+ @CoreCompatChangeRule.EnableCompatChanges({ActivityInfo.FORCE_NON_RESIZE_APP})
+ public void testIsResizeable_resizeable_forceNonResize_overridesEnabled_nonResizeable() {
+ final Task task = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true)
+ .setComponent(
+ ComponentName.createRelative(mContext, SizeCompatTests.class.getName()))
+ .build();
+ task.setResizeMode(RESIZE_MODE_RESIZEABLE);
+
+ // Override should take effect and task should be un-resizeable.
+ assertFalse(task.getTaskInfo().isResizeable);
+ }
+
+ @Test
+ @CoreCompatChangeRule.EnableCompatChanges({ActivityInfo.FORCE_NON_RESIZE_APP})
+ public void testIsResizeable_resizeable_forceNonResize_overridesDisabled_Resizeable() {
+ final Task task = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true)
+ .setComponent(
+ ComponentName.createRelative(mContext, SizeCompatTests.class.getName()))
+ .build();
+ task.setResizeMode(RESIZE_MODE_RESIZEABLE);
+
+ // Disallow resize overrides.
+ task.mAllowForceResizeOverride = false;
+
+ // Override should not take effect and task should be resizeable.
+ assertTrue(task.getTaskInfo().isResizeable);
+ }
+
+ @Test
+ @CoreCompatChangeRule.EnableCompatChanges({ActivityInfo.FORCE_NON_RESIZE_APP})
+ public void testIsResizeable_systemWideForceResize_compatForceNonResize__Resizeable() {
+ final Task task = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true)
+ .setComponent(
+ ComponentName.createRelative(mContext, SizeCompatTests.class.getName()))
+ .build();
+ task.setResizeMode(RESIZE_MODE_RESIZEABLE);
+
+ // Set system-wide force resizeable override.
+ task.mAtmService.mForceResizableActivities = true;
+
+ // System wide override should tak priority over app compat override so the task should
+ // remain resizeable.
+ assertTrue(task.getTaskInfo().isResizeable);
+ }
+
+ @Test
public void testResolveNonResizableTaskWindowingMode() {
// Test with no support non-resizable in multi window regardless the screen size.
mAtm.mSupportsNonResizableMultiWindow = -1;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java
index 4104999..12b7445 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.tools.traces.Utils.busyWaitForDataSourceRegistration;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyZeroInteractions;
@@ -28,7 +30,6 @@
import static java.io.File.createTempFile;
import static java.nio.file.Files.createTempDirectory;
-import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.Presubmit;
import android.tools.ScenarioBuilder;
import android.tools.traces.io.ResultWriter;
@@ -36,9 +37,6 @@
import android.view.Choreographer;
import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import com.google.protobuf.InvalidProtocolBufferException;
import org.junit.After;
import org.junit.Before;
@@ -46,12 +44,9 @@
import org.junit.Test;
import org.mockito.Mockito;
-import perfetto.protos.PerfettoConfig.TracingServiceState;
import perfetto.protos.PerfettoConfig.WindowManagerConfig.LogFrequency;
-import java.io.FileInputStream;
import java.io.IOException;
-import java.util.Optional;
/**
* Test class for {@link WindowTracingPerfetto}.
@@ -74,7 +69,7 @@
sChoreographer = Mockito.mock(Choreographer.class);
sWindowTracing = new WindowTracingPerfetto(sWmMock, sChoreographer,
new WindowManagerGlobalLock(), TEST_DATA_SOURCE_NAME);
- waitDataSourceIsAvailable();
+ busyWaitForDataSourceRegistration(TEST_DATA_SOURCE_NAME);
}
@Before
@@ -156,67 +151,4 @@
mTraceMonitor.stop(writer);
}
-
- private static void waitDataSourceIsAvailable() {
- final int timeoutMs = 10000;
- final int busyWaitIntervalMs = 100;
-
- int elapsedMs = 0;
-
- while (!isDataSourceAvailable()) {
- try {
- Thread.sleep(busyWaitIntervalMs);
- elapsedMs += busyWaitIntervalMs;
- if (elapsedMs >= timeoutMs) {
- throw new RuntimeException("Data source didn't become available."
- + " Waited for: " + timeoutMs + " ms");
- }
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
- }
-
- private static boolean isDataSourceAvailable() {
- byte[] proto = executeShellCommand("perfetto --query-raw");
-
- try {
- TracingServiceState state = TracingServiceState.parseFrom(proto);
-
- Optional<Integer> producerId = Optional.empty();
-
- for (TracingServiceState.Producer producer : state.getProducersList()) {
- if (producer.getPid() == android.os.Process.myPid()) {
- producerId = Optional.of(producer.getId());
- break;
- }
- }
-
- if (producerId.isEmpty()) {
- return false;
- }
-
- for (TracingServiceState.DataSource ds : state.getDataSourcesList()) {
- if (ds.getDsDescriptor().getName().equals(TEST_DATA_SOURCE_NAME)
- && ds.getProducerId() == producerId.get()) {
- return true;
- }
- }
- } catch (InvalidProtocolBufferException e) {
- throw new RuntimeException(e);
- }
-
- return false;
- }
-
- private static byte[] executeShellCommand(String command) {
- try {
- ParcelFileDescriptor fd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
- .executeShellCommand(command);
- FileInputStream is = new ParcelFileDescriptor.AutoCloseInputStream(fd);
- return is.readAllBytes();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
}
diff --git a/telephony/java/android/telephony/BarringInfo.java b/telephony/java/android/telephony/BarringInfo.java
index e20e4d2..e42b41f 100644
--- a/telephony/java/android/telephony/BarringInfo.java
+++ b/telephony/java/android/telephony/BarringInfo.java
@@ -159,7 +159,7 @@
/**
* @return the conditional barring factor as a percentage 0-100, which is the probability of
- * a random device being barred for the service type.
+ * a random device being allowed for a conditionally barred service.
*/
public int getConditionalBarringFactor() {
return mConditionalBarringFactor;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 41223db..2ef0573 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -5038,7 +5038,7 @@
* {@code true} - Enable NI SUPL message injection.
*/
@FlaggedApi(android.location.flags.Flags
- .FLAG_ENABLE_NI_SUPL_MESSAGE_INJECTION_BY_CARRIER_CONFIG)
+ .FLAG_ENABLE_NI_SUPL_MESSAGE_INJECTION_BY_CARRIER_CONFIG_BUGFIX)
public static final String KEY_ENABLE_NI_SUPL_MESSAGE_INJECTION_BOOL =
KEY_PREFIX + "enable_ni_supl_message_injection_bool";
@@ -5059,7 +5059,7 @@
defaults.putInt(KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
SUPL_EMERGENCY_MODE_TYPE_CP_ONLY);
defaults.putStringArray(KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, null);
- if (android.location.flags.Flags.enableNiSuplMessageInjectionByCarrierConfig()) {
+ if (android.location.flags.Flags.enableNiSuplMessageInjectionByCarrierConfigBugfix()) {
defaults.putBoolean(KEY_ENABLE_NI_SUPL_MESSAGE_INJECTION_BOOL, false);
}
return defaults;
diff --git a/telephony/java/android/telephony/satellite/ISatelliteModemStateCallback.aidl b/telephony/java/android/telephony/satellite/ISatelliteModemStateCallback.aidl
index 66a20ae..50e3a0e 100644
--- a/telephony/java/android/telephony/satellite/ISatelliteModemStateCallback.aidl
+++ b/telephony/java/android/telephony/satellite/ISatelliteModemStateCallback.aidl
@@ -34,4 +34,12 @@
* @param isEmergency True means satellite enabled for emergency mode, false otherwise.
*/
void onEmergencyModeChanged(in boolean isEmergency);
+
+ /**
+ * Indicates that the satellite registration failed with following failure code
+ *
+ * @param causeCode the primary failure cause code of the procedure.
+ * For LTE (EMM), cause codes are TS 24.301 Sec 9.9.3.9
+ */
+ void onRegistrationFailure(in int causeCode);
}
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 90dae3b..4eefaac 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
+import android.annotation.Hide;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1579,6 +1580,13 @@
executor.execute(() -> Binder.withCleanCallingIdentity(() ->
callback.onEmergencyModeChanged(isEmergency)));
}
+
+ @Hide
+ @Override
+ public void onRegistrationFailure(int causeCode) {
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onRegistrationFailure(causeCode)));
+ }
};
sSatelliteModemStateCallbackMap.put(callback, internalCallback);
return telephony.registerForSatelliteModemStateChanged(internalCallback);
diff --git a/telephony/java/android/telephony/satellite/SatelliteModemStateCallback.java b/telephony/java/android/telephony/satellite/SatelliteModemStateCallback.java
index 423a785..13af469 100644
--- a/telephony/java/android/telephony/satellite/SatelliteModemStateCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteModemStateCallback.java
@@ -45,4 +45,13 @@
*/
@FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
default void onEmergencyModeChanged(boolean isEmergency) {};
+
+ /**
+ * Indicates that the satellite registration failed with following failure code
+ *
+ * @param causeCode the primary failure cause code of the procedure.
+ * For LTE (EMM), cause codes are TS 24.301 Sec 9.9.3.9
+ * @hide
+ */
+ default void onRegistrationFailure(int causeCode) {};
}
diff --git a/tests/FlickerTests/ActivityEmbedding/OWNERS b/tests/FlickerTests/ActivityEmbedding/OWNERS
new file mode 100644
index 0000000..981b316
--- /dev/null
+++ b/tests/FlickerTests/ActivityEmbedding/OWNERS
@@ -0,0 +1 @@
+# Bug component: 1168918
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
index 3f6a0bf..c77413b 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
@@ -20,6 +20,7 @@
import android.graphics.Insets
import android.graphics.Rect
import android.graphics.Region
+import android.os.SystemClock
import android.platform.uiautomator_helpers.DeviceHelpers
import android.tools.device.apphelpers.IStandardAppHelper
import android.tools.helpers.SYSTEMUI_PACKAGE
@@ -27,11 +28,14 @@
import android.tools.traces.wm.WindowingMode
import android.view.WindowInsets
import android.view.WindowManager
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.uiautomator.By
import androidx.test.uiautomator.BySelector
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiObject2
import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.helpers.MotionEventHelper.InputMethod.TOUCH
+import com.android.window.flags.Flags
import java.time.Duration
/**
@@ -69,13 +73,22 @@
fun enterDesktopWithDrag(
wmHelper: WindowManagerStateHelper,
device: UiDevice,
+ motionEventHelper: MotionEventHelper = MotionEventHelper(getInstrumentation(), TOUCH)
) {
innerHelper.launchViaIntent(wmHelper)
- dragToDesktop(wmHelper, device)
+ dragToDesktop(
+ wmHelper = wmHelper,
+ device = device,
+ motionEventHelper = motionEventHelper
+ )
waitForAppToMoveToDesktop(wmHelper)
}
- private fun dragToDesktop(wmHelper: WindowManagerStateHelper, device: UiDevice) {
+ private fun dragToDesktop(
+ wmHelper: WindowManagerStateHelper,
+ device: UiDevice,
+ motionEventHelper: MotionEventHelper
+ ) {
val windowRect = wmHelper.getWindowRegion(innerHelper).bounds
val startX = windowRect.centerX()
@@ -88,7 +101,17 @@
val endY = displayRect.centerY() / 2
// drag the window to move to desktop
- device.drag(startX, startY, startX, endY, 100)
+ if (motionEventHelper.inputMethod == TOUCH
+ && Flags.enableHoldToDragAppHandle()) {
+ // Touch requires hold-to-drag.
+ val downTime = SystemClock.uptimeMillis()
+ motionEventHelper.actionDown(startX, startY, time = downTime)
+ SystemClock.sleep(100L) // hold for 100ns before starting the move.
+ motionEventHelper.actionMove(startX, startY, startX, endY, 100, downTime = downTime)
+ motionEventHelper.actionUp(startX, endY, downTime = downTime)
+ } else {
+ device.drag(startX, startY, startX, endY, 100)
+ }
}
private fun getMaximizeButtonForTheApp(caption: UiObject2?): UiObject2 {
@@ -220,9 +243,10 @@
val endY = startY + verticalChange
val endX = startX + horizontalChange
- motionEvent.actionDown(startX, startY)
- motionEvent.actionMove(startX, startY, endX, endY, /* steps= */100)
- motionEvent.actionUp(endX, endY)
+ val downTime = SystemClock.uptimeMillis()
+ motionEvent.actionDown(startX, startY, time = downTime)
+ motionEvent.actionMove(startX, startY, endX, endY, /* steps= */100, downTime = downTime)
+ motionEvent.actionUp(endX, endY, downTime = downTime)
wmHelper
.StateSyncBuilder()
.withAppTransitionIdle()
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MotionEventHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MotionEventHelper.kt
index 0835398..86a0b0f 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MotionEventHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MotionEventHelper.kt
@@ -21,6 +21,7 @@
import android.view.ContentInfo.Source
import android.view.InputDevice.SOURCE_MOUSE
import android.view.InputDevice.SOURCE_STYLUS
+import android.view.InputDevice.SOURCE_TOUCHSCREEN
import android.view.MotionEvent
import android.view.MotionEvent.ACTION_DOWN
import android.view.MotionEvent.ACTION_MOVE
@@ -36,23 +37,24 @@
*/
class MotionEventHelper(
private val instr: Instrumentation,
- private val inputMethod: InputMethod
+ val inputMethod: InputMethod
) {
enum class InputMethod(@ToolType val toolType: Int, @Source val source: Int) {
STYLUS(TOOL_TYPE_STYLUS, SOURCE_STYLUS),
MOUSE(TOOL_TYPE_MOUSE, SOURCE_MOUSE),
- TOUCHPAD(TOOL_TYPE_FINGER, SOURCE_MOUSE)
+ TOUCHPAD(TOOL_TYPE_FINGER, SOURCE_MOUSE),
+ TOUCH(TOOL_TYPE_FINGER, SOURCE_TOUCHSCREEN)
}
- fun actionDown(x: Int, y: Int) {
- injectMotionEvent(ACTION_DOWN, x, y)
+ fun actionDown(x: Int, y: Int, time: Long = SystemClock.uptimeMillis()) {
+ injectMotionEvent(ACTION_DOWN, x, y, downTime = time, eventTime = time)
}
- fun actionUp(x: Int, y: Int) {
- injectMotionEvent(ACTION_UP, x, y)
+ fun actionUp(x: Int, y: Int, downTime: Long) {
+ injectMotionEvent(ACTION_UP, x, y, downTime = downTime)
}
- fun actionMove(startX: Int, startY: Int, endX: Int, endY: Int, steps: Int) {
+ fun actionMove(startX: Int, startY: Int, endX: Int, endY: Int, steps: Int, downTime: Long) {
val incrementX = (endX - startX).toFloat() / (steps - 1)
val incrementY = (endY - startY).toFloat() / (steps - 1)
@@ -61,14 +63,19 @@
val x = startX + incrementX * i
val y = startY + incrementY * i
- val moveEvent = getMotionEvent(time, time, ACTION_MOVE, x, y)
+ val moveEvent = getMotionEvent(downTime, time, ACTION_MOVE, x, y)
injectMotionEvent(moveEvent)
}
}
- private fun injectMotionEvent(action: Int, x: Int, y: Int): MotionEvent {
- val eventTime = SystemClock.uptimeMillis()
- val event = getMotionEvent(eventTime, eventTime, action, x.toFloat(), y.toFloat())
+ private fun injectMotionEvent(
+ action: Int,
+ x: Int,
+ y: Int,
+ downTime: Long = SystemClock.uptimeMillis(),
+ eventTime: Long = SystemClock.uptimeMillis()
+ ): MotionEvent {
+ val event = getMotionEvent(downTime, eventTime, action, x.toFloat(), y.toFloat())
injectMotionEvent(event)
return event
}
diff --git a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
index c2e71f8..351ec463 100644
--- a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
+++ b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
@@ -21,6 +21,8 @@
import android.content.Context
import android.content.ContextWrapper
import android.content.PermissionChecker
+import android.content.pm.PackageManager
+import android.content.pm.PackageManagerInternal
import android.hardware.display.DisplayManager
import android.hardware.display.DisplayViewport
import android.hardware.display.VirtualDisplay
@@ -29,10 +31,13 @@
import android.os.InputEventInjectionSync
import android.os.SystemClock
import android.os.test.TestLooper
+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
import android.view.InputDevice
+import android.view.KeyCharacterMap
import android.view.KeyEvent
import android.view.SurfaceHolder
import android.view.SurfaceView
@@ -94,6 +99,10 @@
ExtendedMockitoRule.Builder(this).mockStatic(LocalServices::class.java)
.mockStatic(PermissionChecker::class.java).build()!!
+ @JvmField
+ @Rule
+ val setFlagsRule = SetFlagsRule()
+
@get:Rule
val fakeSettingsProviderRule = FakeSettingsProvider.rule()!!
@@ -107,8 +116,14 @@
private lateinit var windowManagerInternal: WindowManagerInternal
@Mock
+ private lateinit var packageManagerInternal: PackageManagerInternal
+
+ @Mock
private lateinit var uEventManager: UEventManager
+ @Mock
+ private lateinit var kbdController: InputManagerService.KeyboardBacklightControllerInterface
+
private lateinit var service: InputManagerService
private lateinit var localService: InputManagerInternal
private lateinit var context: Context
@@ -135,15 +150,29 @@
override fun registerLocalService(service: InputManagerInternal?) {
localService = service!!
}
+
+ override fun getKeyboardBacklightController(
+ nativeService: NativeInputManagerService?,
+ dataStore: PersistentDataStore?
+ ): InputManagerService.KeyboardBacklightControllerInterface {
+ return kbdController
+ }
})
inputManagerGlobalSession = InputManagerGlobal.createTestSession(service)
val inputManager = InputManager(context)
whenever(context.getSystemService(InputManager::class.java)).thenReturn(inputManager)
whenever(context.getSystemService(Context.INPUT_SERVICE)).thenReturn(inputManager)
+ whenever(context.checkCallingOrSelfPermission(Manifest.permission.MANAGE_KEY_GESTURES))
+ .thenReturn(
+ PackageManager.PERMISSION_GRANTED
+ )
ExtendedMockito.doReturn(windowManagerInternal).`when` {
LocalServices.getService(eq(WindowManagerInternal::class.java))
}
+ ExtendedMockito.doReturn(packageManagerInternal).`when` {
+ LocalServices.getService(eq(PackageManagerInternal::class.java))
+ }
assertTrue("Local service must be registered", this::localService.isInitialized)
service.setWindowManagerCallbacks(wmCallbacks)
@@ -183,9 +212,10 @@
verify(native).setMotionClassifierEnabled(anyBoolean())
verify(native).setMaximumObscuringOpacityForTouch(anyFloat())
verify(native).setStylusPointerIconEnabled(anyBoolean())
- // Called twice at boot, since there are individual callbacks to update the
- // key repeat timeout and the key repeat delay.
- verify(native, times(2)).setKeyRepeatConfiguration(anyInt(), anyInt())
+ // Called thrice at boot, since there are individual callbacks to update the
+ // key repeat timeout, the key repeat delay and whether key repeat enabled.
+ verify(native, times(3)).setKeyRepeatConfiguration(anyInt(), anyInt(),
+ anyBoolean())
}
@Test
@@ -442,6 +472,37 @@
verify(mockOnKeyListener, never()).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, upEvent)
}
+ @Test
+ @EnableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
+ fun handleKeyGestures_keyboardBacklight() {
+ service.systemRunning()
+
+ val backlightDownEvent = createKeyEvent(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN)
+ service.interceptKeyBeforeDispatching(null, backlightDownEvent, /* policyFlags = */0)
+ verify(kbdController).decrementKeyboardBacklight(anyInt())
+
+ val backlightUpEvent = createKeyEvent(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP)
+ service.interceptKeyBeforeDispatching(null, backlightUpEvent, /* policyFlags = */0)
+ verify(kbdController).incrementKeyboardBacklight(anyInt())
+ }
+
+ @Test
+ @EnableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
+ fun handleKeyGestures_toggleCapsLock() {
+ service.systemRunning()
+
+ val metaDownEvent = createKeyEvent(KeyEvent.KEYCODE_META_LEFT)
+ service.interceptKeyBeforeDispatching(null, metaDownEvent, /* policyFlags = */0)
+ val altDownEvent =
+ createKeyEvent(KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.META_META_ON, KeyEvent.ACTION_DOWN)
+ service.interceptKeyBeforeDispatching(null, altDownEvent, /* policyFlags = */0)
+ val altUpEvent =
+ createKeyEvent(KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.META_META_ON, KeyEvent.ACTION_UP)
+ service.interceptKeyBeforeDispatching(null, altUpEvent, /* policyFlags = */0)
+
+ verify(native).toggleCapsLock(anyInt())
+ }
+
fun overrideSendActionKeyEventsToFocusedWindow(
hasPermission: Boolean,
hasPrivateFlag: Boolean
@@ -476,6 +537,25 @@
)
whenever(windowManagerInternal.getKeyInterceptionInfoFromToken(any())).thenReturn(info)
}
+
+ private fun createKeyEvent(
+ keycode: Int,
+ modifierState: Int = 0,
+ action: Int = KeyEvent.ACTION_DOWN
+ ): KeyEvent {
+ return KeyEvent(
+ /* downTime = */0,
+ /* eventTime = */0,
+ action,
+ keycode,
+ /* repeat = */0,
+ modifierState,
+ KeyCharacterMap.VIRTUAL_KEYBOARD,
+ /* scancode = */0,
+ /* flags = */0,
+ InputDevice.SOURCE_KEYBOARD
+ )
+ }
}
private fun <T> whenever(methodCall: T): OngoingStubbing<T> = `when`(methodCall)
diff --git a/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java
index 681b7f2..9459070 100644
--- a/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java
+++ b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java
@@ -16,6 +16,7 @@
package com.android.server.input.debug;
+import static android.view.InputDevice.SOURCE_MOUSE;
import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
import static org.junit.Assert.assertEquals;
@@ -29,7 +30,9 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
+import android.hardware.input.InputManager;
import android.testing.TestableContext;
+import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
@@ -60,13 +63,15 @@
*/
@RunWith(AndroidJUnit4.class)
public class TouchpadDebugViewTest {
- private static final int TOUCHPAD_DEVICE_ID = 6;
+ private static final int TOUCHPAD_DEVICE_ID = 60;
private TouchpadDebugView mTouchpadDebugView;
private WindowManager.LayoutParams mWindowLayoutParams;
@Mock
WindowManager mWindowManager;
+ @Mock
+ InputManager mInputManager;
Rect mWindowBounds;
WindowMetrics mWindowMetrics;
@@ -79,12 +84,21 @@
mTestableContext = new TestableContext(context);
mTestableContext.addMockSystemService(WindowManager.class, mWindowManager);
+ mTestableContext.addMockSystemService(InputManager.class, mInputManager);
mWindowBounds = new Rect(0, 0, 2560, 1600);
mWindowMetrics = new WindowMetrics(mWindowBounds, new WindowInsets(mWindowBounds), 1.0f);
when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics);
+ InputDevice inputDevice = new InputDevice.Builder()
+ .setId(TOUCHPAD_DEVICE_ID)
+ .setSources(InputDevice.SOURCE_TOUCHPAD | SOURCE_MOUSE)
+ .setName("Test Device " + TOUCHPAD_DEVICE_ID)
+ .build();
+
+ when(mInputManager.getInputDevice(TOUCHPAD_DEVICE_ID)).thenReturn(inputDevice);
+
mTouchpadDebugView = new TouchpadDebugView(mTestableContext, TOUCHPAD_DEVICE_ID,
new TouchpadHardwareProperties.Builder(0f, 0f, 500f,
500f, 45f, 47f, -4f, 5f, (short) 10, true,
@@ -307,26 +321,26 @@
new TouchpadHardwareState(0, 1 /* buttonsDown */, 0, 0,
new TouchpadFingerState[0]), TOUCHPAD_DEVICE_ID);
- assertEquals(((ColorDrawable) child.getBackground()).getColor(), Color.BLUE);
+ assertEquals(((ColorDrawable) child.getBackground()).getColor(), Color.rgb(118, 151, 99));
mTouchpadDebugView.updateHardwareState(
new TouchpadHardwareState(0, 0 /* buttonsDown */, 0, 0,
new TouchpadFingerState[0]), TOUCHPAD_DEVICE_ID);
- assertEquals(((ColorDrawable) child.getBackground()).getColor(), Color.RED);
+ assertEquals(((ColorDrawable) child.getBackground()).getColor(), Color.rgb(84, 85, 169));
mTouchpadDebugView.updateHardwareState(
new TouchpadHardwareState(0, 1 /* buttonsDown */, 0, 0,
new TouchpadFingerState[0]), TOUCHPAD_DEVICE_ID);
- assertEquals(((ColorDrawable) child.getBackground()).getColor(), Color.BLUE);
+ assertEquals(((ColorDrawable) child.getBackground()).getColor(), Color.rgb(118, 151, 99));
// Color should not change because hardware state of a different touchpad
mTouchpadDebugView.updateHardwareState(
new TouchpadHardwareState(0, 0 /* buttonsDown */, 0, 0,
new TouchpadFingerState[0]), TOUCHPAD_DEVICE_ID + 1);
- assertEquals(((ColorDrawable) child.getBackground()).getColor(), Color.BLUE);
+ assertEquals(((ColorDrawable) child.getBackground()).getColor(), Color.rgb(118, 151, 99));
}
@Test
@@ -341,4 +355,43 @@
mTouchpadDebugView.updateGestureInfo(gestureType, TOUCHPAD_DEVICE_ID);
assertEquals(child.getText().toString(), TouchpadDebugView.getGestureText(gestureType));
}
-}
+
+ @Test
+ public void testTwoFingerDrag() {
+ float offsetX = ViewConfiguration.get(mTestableContext).getScaledTouchSlop() + 10;
+ float offsetY = ViewConfiguration.get(mTestableContext).getScaledTouchSlop() + 10;
+
+ // Simulate ACTION_DOWN event (gesture starts).
+ MotionEvent actionDown = new MotionEventBuilder(MotionEvent.ACTION_DOWN, SOURCE_MOUSE)
+ .pointer(new PointerBuilder(0, MotionEvent.TOOL_TYPE_FINGER)
+ .x(40f)
+ .y(40f)
+ )
+ .classification(MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE)
+ .build();
+ mTouchpadDebugView.dispatchTouchEvent(actionDown);
+
+ // Simulate ACTION_MOVE event (dragging with two fingers, processed as one pointer).
+ MotionEvent actionMove = new MotionEventBuilder(MotionEvent.ACTION_MOVE, SOURCE_MOUSE)
+ .pointer(new PointerBuilder(0, MotionEvent.TOOL_TYPE_FINGER)
+ .x(40f + offsetX)
+ .y(40f + offsetY)
+ )
+ .classification(MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE)
+ .build();
+ mTouchpadDebugView.dispatchTouchEvent(actionMove);
+
+ // Simulate ACTION_UP event (gesture ends).
+ MotionEvent actionUp = new MotionEventBuilder(MotionEvent.ACTION_UP, SOURCE_MOUSE)
+ .pointer(new PointerBuilder(0, MotionEvent.TOOL_TYPE_FINGER)
+ .x(40f + offsetX)
+ .y(40f + offsetY)
+ )
+ .classification(MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE)
+ .build();
+ mTouchpadDebugView.dispatchTouchEvent(actionUp);
+
+ // Verify that no updateViewLayout is called (as expected for a two-finger drag gesture).
+ verify(mWindowManager, times(0)).updateViewLayout(any(), any());
+ }
+}
\ No newline at end of file
diff --git a/tests/Tracing/Android.bp b/tests/Tracing/Android.bp
index 5a7f12f..90998e6 100644
--- a/tests/Tracing/Android.bp
+++ b/tests/Tracing/Android.bp
@@ -15,7 +15,7 @@
},
// Include some source files directly to be able to access package members
srcs: ["src/**/*.java"],
- libs: ["android.test.runner"],
+ libs: ["android.test.runner.stubs.system"],
static_libs: [
"junit",
"androidx.test.rules",
diff --git a/core/tests/coretests/src/android/tracing/perfetto/DataSourceTest.java b/tests/Tracing/src/android/tracing/perfetto/DataSourceTest.java
similarity index 100%
rename from core/tests/coretests/src/android/tracing/perfetto/DataSourceTest.java
rename to tests/Tracing/src/android/tracing/perfetto/DataSourceTest.java
diff --git a/core/tests/coretests/src/android/tracing/perfetto/TestDataSource.java b/tests/Tracing/src/android/tracing/perfetto/TestDataSource.java
similarity index 100%
rename from core/tests/coretests/src/android/tracing/perfetto/TestDataSource.java
rename to tests/Tracing/src/android/tracing/perfetto/TestDataSource.java
diff --git a/tests/Tracing/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java b/tests/Tracing/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java
index e841d9e..6f3deab 100644
--- a/tests/Tracing/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java
@@ -16,6 +16,8 @@
package com.android.internal.protolog;
+import static android.tools.traces.Utils.busyWaitForDataSourceRegistration;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
@@ -42,7 +44,7 @@
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.internal.protolog.ProtoLogConfigurationService.ViewerConfigFileTracer;
+import com.android.internal.protolog.ProtoLogConfigurationServiceImpl.ViewerConfigFileTracer;
import com.android.internal.protolog.common.IProtoLogGroup;
import com.android.internal.protolog.common.LogDataType;
import com.android.internal.protolog.common.LogLevel;
@@ -166,7 +168,8 @@
return new ProtoInputStream(sViewerConfigBuilder.build().toByteArray());
});
};
- sProtoLogConfigurationService = new ProtoLogConfigurationService(dataSourceBuilder, tracer);
+ sProtoLogConfigurationService =
+ new ProtoLogConfigurationServiceImpl(dataSourceBuilder, tracer);
if (android.tracing.Flags.clientSideProtoLogging()) {
sProtoLog = new PerfettoProtoLogImpl(
@@ -177,6 +180,8 @@
viewerConfigInputStreamProvider, sReader, () -> sCacheUpdater.run(),
TestProtoLogGroup.values(), dataSourceBuilder, sProtoLogConfigurationService);
}
+
+ busyWaitForDataSourceRegistration(TEST_PROTOLOG_DATASOURCE_NAME);
}
@Before
diff --git a/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java
index e1bdd77..a3d03a8 100644
--- a/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java
@@ -150,11 +150,11 @@
@Test
public void canRegisterClientWithGroupsOnly() throws RemoteException {
- final ProtoLogConfigurationService service = new ProtoLogConfigurationService();
+ final ProtoLogConfigurationService service = new ProtoLogConfigurationServiceImpl();
- final ProtoLogConfigurationService.RegisterClientArgs args =
- new ProtoLogConfigurationService.RegisterClientArgs()
- .setGroups(new ProtoLogConfigurationService.RegisterClientArgs
+ final ProtoLogConfigurationServiceImpl.RegisterClientArgs args =
+ new ProtoLogConfigurationServiceImpl.RegisterClientArgs()
+ .setGroups(new ProtoLogConfigurationServiceImpl.RegisterClientArgs
.GroupConfig(TEST_GROUP, true));
service.registerClient(mMockClient, args);
@@ -165,11 +165,11 @@
@Test
public void willDumpViewerConfigOnlyOnceOnTraceStop()
throws RemoteException, InvalidProtocolBufferException {
- final ProtoLogConfigurationService service = new ProtoLogConfigurationService();
+ final ProtoLogConfigurationService service = new ProtoLogConfigurationServiceImpl();
- final ProtoLogConfigurationService.RegisterClientArgs args =
- new ProtoLogConfigurationService.RegisterClientArgs()
- .setGroups(new ProtoLogConfigurationService.RegisterClientArgs
+ final ProtoLogConfigurationServiceImpl.RegisterClientArgs args =
+ new ProtoLogConfigurationServiceImpl.RegisterClientArgs()
+ .setGroups(new ProtoLogConfigurationServiceImpl.RegisterClientArgs
.GroupConfig(TEST_GROUP, true))
.setViewerConfigFile(mViewerConfigFile.getAbsolutePath());
service.registerClient(mMockClient, args);
@@ -200,13 +200,13 @@
@Test
public void willDumpViewerConfigOnLastClientDisconnected()
throws RemoteException, FileNotFoundException {
- final ProtoLogConfigurationService.ViewerConfigFileTracer tracer =
- Mockito.mock(ProtoLogConfigurationService.ViewerConfigFileTracer.class);
- final ProtoLogConfigurationService service = new ProtoLogConfigurationService(tracer);
+ final ProtoLogConfigurationServiceImpl.ViewerConfigFileTracer tracer =
+ Mockito.mock(ProtoLogConfigurationServiceImpl.ViewerConfigFileTracer.class);
+ final ProtoLogConfigurationService service = new ProtoLogConfigurationServiceImpl(tracer);
- final ProtoLogConfigurationService.RegisterClientArgs args =
- new ProtoLogConfigurationService.RegisterClientArgs()
- .setGroups(new ProtoLogConfigurationService.RegisterClientArgs
+ final ProtoLogConfigurationServiceImpl.RegisterClientArgs args =
+ new ProtoLogConfigurationServiceImpl.RegisterClientArgs()
+ .setGroups(new ProtoLogConfigurationServiceImpl.RegisterClientArgs
.GroupConfig(TEST_GROUP, true))
.setViewerConfigFile(mViewerConfigFile.getAbsolutePath());
service.registerClient(mMockClient, args);
@@ -225,10 +225,10 @@
@Test
public void sendEnableLoggingToLogcatToClient() throws RemoteException {
- final var service = new ProtoLogConfigurationService();
+ final var service = new ProtoLogConfigurationServiceImpl();
- final var args = new ProtoLogConfigurationService.RegisterClientArgs()
- .setGroups(new ProtoLogConfigurationService.RegisterClientArgs
+ final var args = new ProtoLogConfigurationServiceImpl.RegisterClientArgs()
+ .setGroups(new ProtoLogConfigurationServiceImpl.RegisterClientArgs
.GroupConfig(TEST_GROUP, false));
service.registerClient(mMockClient, args);
@@ -242,11 +242,11 @@
@Test
public void sendDisableLoggingToLogcatToClient() throws RemoteException {
- final ProtoLogConfigurationService service = new ProtoLogConfigurationService();
+ final ProtoLogConfigurationService service = new ProtoLogConfigurationServiceImpl();
- final ProtoLogConfigurationService.RegisterClientArgs args =
- new ProtoLogConfigurationService.RegisterClientArgs()
- .setGroups(new ProtoLogConfigurationService.RegisterClientArgs
+ final ProtoLogConfigurationServiceImpl.RegisterClientArgs args =
+ new ProtoLogConfigurationServiceImpl.RegisterClientArgs()
+ .setGroups(new ProtoLogConfigurationServiceImpl.RegisterClientArgs
.GroupConfig(TEST_GROUP, true));
service.registerClient(mMockClient, args);
@@ -260,11 +260,11 @@
@Test
public void doNotSendLoggingToLogcatToClientWithoutRegisteredGroup() throws RemoteException {
- final ProtoLogConfigurationService service = new ProtoLogConfigurationService();
+ final ProtoLogConfigurationService service = new ProtoLogConfigurationServiceImpl();
- final ProtoLogConfigurationService.RegisterClientArgs args =
- new ProtoLogConfigurationService.RegisterClientArgs()
- .setGroups(new ProtoLogConfigurationService.RegisterClientArgs
+ final ProtoLogConfigurationServiceImpl.RegisterClientArgs args =
+ new ProtoLogConfigurationServiceImpl.RegisterClientArgs()
+ .setGroups(new ProtoLogConfigurationServiceImpl.RegisterClientArgs
.GroupConfig(TEST_GROUP, false));
service.registerClient(mMockClient, args);
@@ -277,15 +277,15 @@
@Test
public void handlesToggleToLogcatBeforeClientIsRegistered() throws RemoteException {
- final ProtoLogConfigurationService service = new ProtoLogConfigurationService();
+ final ProtoLogConfigurationService service = new ProtoLogConfigurationServiceImpl();
Truth.assertThat(service.getGroups()).asList().doesNotContain(TEST_GROUP);
service.enableProtoLogToLogcat(TEST_GROUP);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue();
- final ProtoLogConfigurationService.RegisterClientArgs args =
- new ProtoLogConfigurationService.RegisterClientArgs()
- .setGroups(new ProtoLogConfigurationService.RegisterClientArgs
+ final ProtoLogConfigurationServiceImpl.RegisterClientArgs args =
+ new ProtoLogConfigurationServiceImpl.RegisterClientArgs()
+ .setGroups(new ProtoLogConfigurationServiceImpl.RegisterClientArgs
.GroupConfig(TEST_GROUP, false));
service.registerClient(mMockClient, args);
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestIgnore.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestIgnore.java
new file mode 100644
index 0000000..501fd65
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestIgnore.java
@@ -0,0 +1,34 @@
+/*
+ * 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 android.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * @hide
+ */
+@Target({METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestIgnore {
+}
diff --git a/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt b/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
index eba8e62..001943c 100644
--- a/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
+++ b/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
@@ -24,6 +24,9 @@
--remove-annotation
android.hosttest.annotation.HostSideTestRemove
+--ignore-annotation
+ android.hosttest.annotation.HostSideTestIgnore
+
--substitute-annotation
android.hosttest.annotation.HostSideTestSubstitute
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
index 34aaaa9..165bb57 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -166,6 +166,7 @@
options.keepClassAnnotations,
options.throwAnnotations,
options.removeAnnotations,
+ options.ignoreAnnotations,
options.substituteAnnotations,
options.redirectAnnotations,
options.redirectionClassAnnotations,
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
index 057a52c..b083d89 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
@@ -84,6 +84,7 @@
var keepAnnotations: MutableSet<String> = mutableSetOf(),
var throwAnnotations: MutableSet<String> = mutableSetOf(),
var removeAnnotations: MutableSet<String> = mutableSetOf(),
+ var ignoreAnnotations: MutableSet<String> = mutableSetOf(),
var keepClassAnnotations: MutableSet<String> = mutableSetOf(),
var redirectAnnotations: MutableSet<String> = mutableSetOf(),
@@ -184,6 +185,9 @@
"--remove-annotation" ->
ret.removeAnnotations.addUniqueAnnotationArg()
+ "--ignore-annotation" ->
+ ret.ignoreAnnotations.addUniqueAnnotationArg()
+
"--substitute-annotation" ->
ret.substituteAnnotations.addUniqueAnnotationArg()
@@ -277,6 +281,7 @@
keepAnnotations=$keepAnnotations,
throwAnnotations=$throwAnnotations,
removeAnnotations=$removeAnnotations,
+ ignoreAnnotations=$ignoreAnnotations,
keepClassAnnotations=$keepClassAnnotations,
substituteAnnotations=$substituteAnnotations,
nativeSubstituteAnnotations=$redirectionClassAnnotations,
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
index a6b8cdb..36adf06 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
@@ -48,6 +48,7 @@
keepClassAnnotations_: Set<String>,
throwAnnotations_: Set<String>,
removeAnnotations_: Set<String>,
+ ignoreAnnotations_: Set<String>,
substituteAnnotations_: Set<String>,
redirectAnnotations_: Set<String>,
redirectionClassAnnotations_: Set<String>,
@@ -60,6 +61,7 @@
private val keepClassAnnotations = convertToInternalNames(keepClassAnnotations_)
private val throwAnnotations = convertToInternalNames(throwAnnotations_)
private val removeAnnotations = convertToInternalNames(removeAnnotations_)
+ private val ignoreAnnotations = convertToInternalNames(ignoreAnnotations_)
private val redirectAnnotations = convertToInternalNames(redirectAnnotations_)
private val substituteAnnotations = convertToInternalNames(substituteAnnotations_)
private val redirectionClassAnnotations =
@@ -73,6 +75,7 @@
keepClassAnnotations +
throwAnnotations +
removeAnnotations +
+ ignoreAnnotations +
redirectAnnotations +
substituteAnnotations
@@ -107,6 +110,7 @@
in substituteAnnotations -> FilterPolicy.Substitute.withReason(REASON_ANNOTATION)
in throwAnnotations -> FilterPolicy.Throw.withReason(REASON_ANNOTATION)
in removeAnnotations -> FilterPolicy.Remove.withReason(REASON_ANNOTATION)
+ in ignoreAnnotations -> FilterPolicy.Ignore.withReason(REASON_ANNOTATION)
in redirectAnnotations -> FilterPolicy.Redirect.withReason(REASON_ANNOTATION)
else -> null
}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt
index 7440b94..d6aa7617 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt
@@ -27,16 +27,22 @@
class ClassFilter private constructor(
private val defaultResult: Boolean,
) {
+ private enum class MatchType {
+ Full,
+ Prefix,
+ Suffix,
+ }
+
private class FilterElement(
val allowed: Boolean,
val internalName: String,
- val isPrefix: Boolean,
+ val matchType: MatchType,
) {
fun matches(classInternalName: String): Boolean {
- return if (isPrefix) {
- classInternalName.startsWith(internalName)
- } else {
- classInternalName == internalName
+ return when (matchType) {
+ MatchType.Full -> classInternalName == internalName
+ MatchType.Prefix -> classInternalName.startsWith(internalName)
+ MatchType.Suffix -> classInternalName.endsWith(internalName)
}
}
}
@@ -114,15 +120,29 @@
// Special case -- matches any class names.
if (line == "*") {
- ret.elements.add(FilterElement(allow, "", true))
+ ret.elements.add(FilterElement(allow, "", MatchType.Prefix))
return@forEach
}
- // Handle wildcard -- e.g. "package.name.*"
+ // Handle prefix match -- e.g. "package.name.*"
if (line.endsWith(".*")) {
ret.elements.add(
FilterElement(
- allow, line.substring(0, line.length - 2).toJvmClassName(), true
+ allow,
+ line.substring(0, line.length - 2).toJvmClassName() + "/",
+ MatchType.Prefix
+ )
+ )
+ return@forEach
+ }
+
+ // Handle suffix match -- e.g. "*.Flags"
+ if (line.startsWith("*.")) {
+ ret.elements.add(
+ FilterElement(
+ allow,
+ "/" + line.substring(2, line.length).toJvmClassName(),
+ MatchType.Suffix
)
)
return@forEach
@@ -136,10 +156,10 @@
lineNo
)
}
- ret.elements.add(FilterElement(allow, line.toJvmClassName(), false))
+ ret.elements.add(FilterElement(allow, line.toJvmClassName(), MatchType.Suffix))
}
return ret
}
}
-}
\ No newline at end of file
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
index 82586bb..103e152 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -21,6 +21,26 @@
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
+## Class: android/hosttest/annotation/HostSideTestIgnore.class
+ Compiled from "HostSideTestIgnore.java"
+public interface android.hosttest.annotation.HostSideTestIgnore extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 61
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestIgnore
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestIgnore.java"
+RuntimeVisibleAnnotations:
+ x: #x(#x=[e#x.#x,e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
## Class: android/hosttest/annotation/HostSideTestKeep.class
Compiled from "HostSideTestKeep.java"
public interface android.hosttest.annotation.HostSideTestKeep extends java.lang.annotation.Annotation
@@ -382,7 +402,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
super_class: #x // java/lang/Object
- interfaces: 0, fields: 2, methods: 8, attributes: 2
+ interfaces: 0, fields: 2, methods: 9, attributes: 2
public int keep;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -522,6 +542,24 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestThrow
+
+ public int toBeIgnored();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String not supported on host side
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestIgnore
}
SourceFile: "TinyFrameworkAnnotations.java"
RuntimeInvisibleAnnotations:
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-dump.txt
index 31bbcc5..eeec554 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-dump.txt
@@ -432,7 +432,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 6, attributes: 3
+ interfaces: 0, fields: 1, methods: 7, attributes: 3
public int keep;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -554,6 +554,22 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestThrow
+
+ public int toBeIgnored();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestIgnore
}
SourceFile: "TinyFrameworkAnnotations.java"
RuntimeVisibleAnnotations:
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
index 41f459a..0f8af92 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
@@ -593,7 +593,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 6, attributes: 3
+ interfaces: 0, fields: 1, methods: 7, attributes: 3
public int keep;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -743,6 +743,27 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestThrow
+
+ public int toBeIgnored();
+ descriptor: ()I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String toBeIgnored
+ x: ldc #x // String ()I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iconst_0
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestIgnore
}
SourceFile: "TinyFrameworkAnnotations.java"
RuntimeVisibleAnnotations:
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.java
index ed0fa26..3415deb 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.java
@@ -16,6 +16,7 @@
package com.android.hoststubgen.test.tinyframework;
import android.hosttest.annotation.HostSideTestClassLoadHook;
+import android.hosttest.annotation.HostSideTestIgnore;
import android.hosttest.annotation.HostSideTestKeep;
import android.hosttest.annotation.HostSideTestRemove;
import android.hosttest.annotation.HostSideTestSubstitute;
@@ -71,4 +72,9 @@
public String unsupportedMethod() {
return "This value shouldn't be seen on the host side.";
}
+
+ @HostSideTestIgnore
+ public int toBeIgnored() {
+ throw new RuntimeException("not supported on host side");
+ }
}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotationsTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotationsTest.java
index 34c98e9..1816b38 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotationsTest.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotationsTest.java
@@ -102,4 +102,11 @@
assertThat(new TinyFrameworkNestedClasses.StaticNestedClass.Double$NestedClass().value)
.isEqualTo(8);
}
+
+ @Test
+ public void testIgnoreAnnotation() {
+ // The actual method will throw, but because of @Ignore, it'll return 0.
+ assertThat(new TinyFrameworkAnnotations().toBeIgnored())
+ .isEqualTo(0);
+ }
}
diff --git a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt
index 85b6e80..d4e75d4 100644
--- a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt
+++ b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt
@@ -69,6 +69,8 @@
assertThat(f.matches("d/e/f")).isEqualTo(false)
assertThat(f.matches("d/e/f/g")).isEqualTo(true)
assertThat(f.matches("x")).isEqualTo(true)
+
+ assertThat(f.matches("ab/x")).isEqualTo(true)
}
@Test
@@ -96,4 +98,18 @@
assertThat(e.message).contains("line 1")
}
}
+
+ @Test
+ fun testSuffix() {
+ val f = ClassFilter.buildFromString("""
+ *.Abc # allow
+ !* # Disallow by default
+ """.trimIndent(), true, "X")
+ assertThat(f.matches("a/b/c")).isEqualTo(false)
+ assertThat(f.matches("a/Abc")).isEqualTo(true)
+ assertThat(f.matches("a/b/c/Abc")).isEqualTo(true)
+ assertThat(f.matches("a/b/c/Abc\$Nested")).isEqualTo(true)
+
+ assertThat(f.matches("a/XyzAbc")).isEqualTo(false)
+ }
}
\ No newline at end of file
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
index 290e7be..9467434 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
@@ -22,6 +22,7 @@
import com.google.android.lint.aidl.EnforcePermissionDetector
import com.google.android.lint.aidl.PermissionAnnotationDetector
import com.google.android.lint.aidl.SimpleManualPermissionEnforcementDetector
+import com.google.android.lint.aidl.SimpleRequiresNoPermissionDetector
import com.google.auto.service.AutoService
@AutoService(IssueRegistry::class)
@@ -34,6 +35,7 @@
EnforcePermissionDetector.ISSUE_MISUSING_ENFORCE_PERMISSION,
PermissionAnnotationDetector.ISSUE_MISSING_PERMISSION_ANNOTATION,
SimpleManualPermissionEnforcementDetector.ISSUE_SIMPLE_MANUAL_PERMISSION_ENFORCEMENT,
+ SimpleRequiresNoPermissionDetector.ISSUE_SIMPLE_REQUIRES_NO_PERMISSION,
)
override val api: Int
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfaces.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfaces.kt
index 675a59e6..caa018d 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfaces.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfaces.kt
@@ -256,7 +256,7 @@
"android.devicelock.IGetDeviceIdCallback",
"android.devicelock.IGetKioskAppsCallback",
"android.devicelock.IIsDeviceLockedCallback",
- "android.devicelock.IVoidResultCallback",
+ "android.devicelock.ILockUnlockDeviceCallback",
"android.federatedcompute.aidl.IExampleStoreCallback",
"android.federatedcompute.aidl.IExampleStoreIterator",
"android.federatedcompute.aidl.IExampleStoreIteratorCallback",
@@ -364,8 +364,6 @@
"android.health.connect.aidl.IGetPriorityResponseCallback",
"android.health.connect.aidl.IHealthConnectService",
"android.health.connect.aidl.IInsertRecordsResponseCallback",
- "android.health.connect.aidl.IMedicalDataSourceResponseCallback",
- "android.health.connect.aidl.IMedicalResourcesResponseCallback",
"android.health.connect.aidl.IMigrationCallback",
"android.health.connect.aidl.IReadMedicalResourcesResponseCallback",
"android.health.connect.aidl.IReadRecordsResponseCallback",
@@ -462,6 +460,7 @@
"android.net.ipmemorystore.IOnBlobRetrievedListener",
"android.net.ipmemorystore.IOnL2KeyResponseListener",
"android.net.ipmemorystore.IOnNetworkAttributesRetrievedListener",
+ "android.net.ipmemorystore.IOnNetworkEventCountRetrievedListener",
"android.net.ipmemorystore.IOnSameL3NetworkResponseListener",
"android.net.ipmemorystore.IOnStatusAndCountListener",
"android.net.ipmemorystore.IOnStatusListener",
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/PermissionAnnotationDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/PermissionAnnotationDetector.kt
index d44c271..8d6e320 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/PermissionAnnotationDetector.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/PermissionAnnotationDetector.kt
@@ -57,7 +57,10 @@
ISSUE_MISSING_PERMISSION_ANNOTATION,
node,
context.getLocation(node),
- "The method ${node.name} is not permission-annotated."
+ """
+ ${node.name} should be annotated with either @EnforcePermission, \
+ @RequiresNoPermission or @PermissionManuallyEnforced.
+ """.trimMargin()
)
}
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetector.kt
new file mode 100644
index 0000000..1a13c02
--- /dev/null
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetector.kt
@@ -0,0 +1,118 @@
+/*
+ * 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.google.android.lint.aidl
+
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import org.jetbrains.uast.UastCallKind
+import org.jetbrains.uast.UBlockExpression
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UMethod
+import org.jetbrains.uast.visitor.AbstractUastVisitor
+
+/**
+ * Ensures all AIDL implementations hosted by system_server which don't call other methods are
+ * annotated with @RequiresNoPermission. AIDL Interfaces part of `exemptAidlInterfaces` are skipped
+ * during this search to ensure the detector targets only new AIDL Interfaces.
+ */
+class SimpleRequiresNoPermissionDetector : AidlImplementationDetector() {
+ override fun visitAidlMethod(
+ context: JavaContext,
+ node: UMethod,
+ interfaceName: String,
+ body: UBlockExpression
+ ) {
+ if (!isSystemServicePath(context)) return
+ if (context.evaluator.isAbstract(node)) return
+
+ val fullyQualifiedInterfaceName =
+ getContainingAidlInterfaceQualified(context, node) ?: return
+ if (exemptAidlInterfaces.contains(fullyQualifiedInterfaceName)) return
+
+ if (node.hasAnnotation(ANNOTATION_REQUIRES_NO_PERMISSION)) return
+
+ if (!isCallingMethod(node)) {
+ context.report(
+ ISSUE_SIMPLE_REQUIRES_NO_PERMISSION,
+ node,
+ context.getLocation(node),
+ """
+ Method ${node.name} doesn't perform any permission checks, meaning it should \
+ be annotated with @RequiresNoPermission.
+ """.trimMargin()
+ )
+ }
+ }
+
+ private fun isCallingMethod(node: UMethod): Boolean {
+ val uCallExpressionVisitor = UCallExpressionVisitor()
+ node.accept(uCallExpressionVisitor)
+
+ return uCallExpressionVisitor.isCallingMethod
+ }
+
+ /**
+ * Visits the body of a `UMethod` and determines if it encounters a `UCallExpression` which is
+ * a `UastCallKind.METHOD_CALL`. `isCallingMethod` will hold the result of the search procedure.
+ */
+ private class UCallExpressionVisitor : AbstractUastVisitor() {
+ var isCallingMethod = false
+
+ override fun visitElement(node: UElement): Boolean {
+ // Stop the search early when a method call has been found.
+ return isCallingMethod
+ }
+
+ override fun visitCallExpression(node: UCallExpression): Boolean {
+ if (node.kind != UastCallKind.METHOD_CALL) return false
+
+ isCallingMethod = true
+ return true
+ }
+ }
+
+ companion object {
+
+ private val EXPLANATION = """
+ Method implementations of AIDL Interfaces hosted by the `system_server` which do not
+ call any other methods should be annotated with @RequiresNoPermission. That is because
+ not calling any other methods implies that the method does not perform any permission
+ checking.
+
+ Please migrate to an @RequiresNoPermission annotation.
+ """.trimIndent()
+
+ @JvmField
+ val ISSUE_SIMPLE_REQUIRES_NO_PERMISSION = Issue.create(
+ id = "SimpleRequiresNoPermission",
+ briefDescription = "System Service APIs not calling other methods should use @RNP",
+ explanation = EXPLANATION,
+ category = Category.SECURITY,
+ priority = 5,
+ severity = Severity.ERROR,
+ implementation = Implementation(
+ SimpleRequiresNoPermissionDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ ),
+ )
+ }
+}
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt
index 92d0829..f985d02 100644
--- a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt
@@ -17,7 +17,6 @@
package com.google.android.lint.aidl
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
-import com.android.tools.lint.checks.infrastructure.TestFile
import com.android.tools.lint.checks.infrastructure.TestLintTask
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
@@ -64,7 +63,7 @@
"""
package com.android.server;
public class Bar extends IBar.Stub {
- public void testMethod() { }
+ public void testMethod(int parameter1, int parameter2) { }
}
"""
)
@@ -74,9 +73,9 @@
.run()
.expect(
"""
- src/frameworks/base/services/java/com/android/server/Bar.java:3: Error: The method testMethod is not permission-annotated. [MissingPermissionAnnotation]
- public void testMethod() { }
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ src/frameworks/base/services/java/com/android/server/Bar.java:3: Error: testMethod should be annotated with either @EnforcePermission, @RequiresNoPermission or @PermissionManuallyEnforced. [MissingPermissionAnnotation]
+ public void testMethod(int parameter1, int parameter2) { }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 errors, 0 warnings
"""
)
@@ -90,7 +89,7 @@
"""
package com.android.server;
public class Bar extends IBar.Stub {
- public void testMethod() { }
+ public void testMethod(int parameter1, int parameter2) { }
}
"""
)
@@ -132,7 +131,7 @@
"""
package com.android.server;
public abstract class Bar extends IBar.Stub {
- public abstract void testMethod();
+ public abstract void testMethod(int parameter1, int parameter2);
}
"""
)
@@ -177,50 +176,6 @@
.expectClean()
}
- /* Stubs */
-
- // A service with permission annotation on the method.
- private val interfaceIFoo: TestFile = java(
- """
- public interface IFoo extends android.os.IInterface {
- public static abstract class Stub extends android.os.Binder implements IFoo {
- }
- @Override
- @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
- public void testMethod();
- @Override
- @android.annotation.RequiresNoPermission
- public void testMethodNoPermission();
- @Override
- @android.annotation.PermissionManuallyEnforced
- public void testMethodManual();
- }
- """
- ).indented()
-
- // A service with no permission annotation.
- private val interfaceIBar: TestFile = java(
- """
- public interface IBar extends android.os.IInterface {
- public static abstract class Stub extends android.os.Binder implements IBar {
- }
- public void testMethod();
- }
- """
- ).indented()
-
- // A service whose AIDL Interface is exempted.
- private val interfaceIExempted: TestFile = java(
- """
- package android.accessibilityservice;
- public interface IBrailleDisplayConnection extends android.os.IInterface {
- public static abstract class Stub extends android.os.Binder implements IBrailleDisplayConnection {
- }
- public void testMethod();
- }
- """
- ).indented()
-
private val stubs = arrayOf(interfaceIFoo, interfaceIBar, interfaceIExempted)
private fun createVisitedPath(filename: String) =
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetectorTest.kt
new file mode 100644
index 0000000..a33b48c
--- /dev/null
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetectorTest.kt
@@ -0,0 +1,244 @@
+/*
+ * 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.google.android.lint.aidl
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+
+class SimpleRequiresNoPermissionDetectorTest : LintDetectorTest() {
+ override fun getDetector(): Detector = SimpleRequiresNoPermissionDetector()
+ override fun getIssues(): List<Issue> = listOf(
+ SimpleRequiresNoPermissionDetector
+ .ISSUE_SIMPLE_REQUIRES_NO_PERMISSION
+ )
+
+ override fun lint(): TestLintTask = super.lint().allowMissingSdk()
+
+ fun testRequiresNoPermissionUsedCorrectly_shouldNotWarn() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Foo.java"),
+ """
+ package com.android.server;
+ public class Foo extends IFoo.Stub {
+ private int memberInt;
+
+ @Override
+ @android.annotation.RequiresNoPermission
+ public void testMethodNoPermission(int parameter1, int parameter2) {
+ if (parameter1 < parameter2) {
+ memberInt = parameter1;
+ } else {
+ memberInt = parameter2;
+ }
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expectClean()
+ }
+
+ fun testMissingRequiresNoPermission_shouldWarn() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Bar.java"),
+ """
+ package com.android.server;
+ public class Bar extends IBar.Stub {
+ private int memberInt;
+
+ @Override
+ public void testMethod(int parameter1, int parameter2) {
+ if (parameter1 < parameter2) {
+ memberInt = parameter1;
+ } else {
+ memberInt = parameter2;
+ }
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expect(
+ """
+ src/frameworks/base/services/java/com/android/server/Bar.java:5: Error: Method testMethod doesn't perform any permission checks, meaning it should be annotated with @RequiresNoPermission. [SimpleRequiresNoPermission]
+ @Override
+ ^
+ 1 errors, 0 warnings
+ """
+ )
+ }
+
+ fun testMethodOnlyPerformsConstructorCall_shouldWarn() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Bar.java"),
+ """
+ package com.android.server;
+ public class Bar extends IBar.Stub {
+ private IntPair memberIntPair;
+
+ @Override
+ public void testMethod(int parameter1, int parameter2) {
+ memberIntPair = new IntPair(parameter1, parameter2);
+ }
+
+ private static class IntPair {
+ public int first;
+ public int second;
+
+ public IntPair(int first, int second) {
+ this.first = first;
+ this.second = second;
+ }
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expect(
+ """
+ src/frameworks/base/services/java/com/android/server/Bar.java:5: Error: Method testMethod doesn't perform any permission checks, meaning it should be annotated with @RequiresNoPermission. [SimpleRequiresNoPermission]
+ @Override
+ ^
+ 1 errors, 0 warnings
+ """
+ )
+ }
+
+ fun testMissingRequiresNoPermissionInIgnoredDirectory_shouldNotWarn() {
+ lint()
+ .files(
+ java(
+ ignoredPath,
+ """
+ package com.android.server;
+ public class Bar extends IBar.Stub {
+ @Override
+ public void testMethod(int parameter1, int parameter2) {}
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expectClean()
+ }
+
+ fun testMissingRequiresNoPermissionAbstractMethod_shouldNotWarn() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Bar.java"),
+ """
+ package com.android.server;
+ public abstract class Bar extends IBar.Stub {
+ private int memberInt;
+
+ @Override
+ public abstract void testMethodNoPermission(int parameter1, int parameter2);
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expectClean()
+ }
+
+ // If this test fails, consider the following steps:
+ // 1. Pick the first entry (interface) from `exemptAidlInterfaces`.
+ // 2. Change `interfaceIExempted` to use that interface.
+ // 3. Change this test's class to extend the interface's Stub.
+ fun testMissingRequiresNoPermissionAidlInterfaceExempted_shouldNotWarn() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Bar.java"),
+ """
+ package com.android.server;
+ public class Bar extends android.accessibilityservice.IBrailleDisplayConnection.Stub {
+ public void testMethod(int parameter1, int parameter2) {}
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expectClean()
+ }
+
+ fun testMethodMakesAnotherMethodCall_shouldNotWarn() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Bar.java"),
+ """
+ package com.android.server;
+ public class Bar extends IBar.Stub {
+ private int memberInt;
+
+ @Override
+ public void testMethod(int parameter1, int parameter2) {
+ if (!hasPermission()) return;
+
+ if (parameter1 < parameter2) {
+ memberInt = parameter1;
+ } else {
+ memberInt = parameter2;
+ }
+ }
+
+ private bool hasPermission() {
+ // Perform a permission check.
+ return true;
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expectClean()
+ }
+
+ private val stubs = arrayOf(interfaceIFoo, interfaceIBar, interfaceIExempted)
+
+ private fun createVisitedPath(filename: String) =
+ "src/frameworks/base/services/java/com/android/server/$filename"
+
+ private val ignoredPath = "src/test/pkg/TestClass.java"
+}
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt
index 2ec8fdd..18a8f18 100644
--- a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt
@@ -85,4 +85,46 @@
}
}
""".trimIndent()
-)
\ No newline at end of file
+)
+
+// A service with permission annotation on the method.
+val interfaceIFoo: TestFile = java(
+ """
+ public interface IFoo extends android.os.IInterface {
+ public static abstract class Stub extends android.os.Binder implements IFoo {
+ }
+ @Override
+ @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void testMethod();
+ @Override
+ @android.annotation.RequiresNoPermission
+ public void testMethodNoPermission(int parameter1, int parameter2);
+ @Override
+ @android.annotation.PermissionManuallyEnforced
+ public void testMethodManual();
+ }
+ """
+).indented()
+
+// A service with no permission annotation.
+val interfaceIBar: TestFile = java(
+ """
+ public interface IBar extends android.os.IInterface {
+ public static abstract class Stub extends android.os.Binder implements IBar {
+ }
+ public void testMethod(int parameter1, int parameter2);
+ }
+ """
+).indented()
+
+// A service whose AIDL Interface is exempted.
+val interfaceIExempted: TestFile = java(
+ """
+ package android.accessibilityservice;
+ public interface IBrailleDisplayConnection extends android.os.IInterface {
+ public static abstract class Stub extends android.os.Binder implements IBrailleDisplayConnection {
+ }
+ public void testMethod();
+ }
+ """
+).indented()
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
index f68ae2c..fc4a909 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
@@ -173,6 +173,10 @@
}
}
}
+
+ Executor getExecutor() {
+ return mExecutor;
+ }
}
private ISharedConnectivityService mService;
@@ -188,7 +192,7 @@
private final String mServicePackageName;
private final String mIntentAction;
private ServiceConnection mServiceConnection;
- private UserManager mUserManager;
+ private final UserManager mUserManager;
/**
* Creates a new instance of {@link SharedConnectivityManager}.
@@ -316,15 +320,19 @@
private void registerCallbackInternal(SharedConnectivityClientCallback callback,
SharedConnectivityCallbackProxy proxy) {
- try {
- mService.registerCallback(proxy);
- synchronized (mProxyDataLock) {
- mProxyMap.put(callback, proxy);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Exception in registerCallback", e);
- callback.onRegisterCallbackFailed(e);
- }
+ proxy.getExecutor().execute(
+ () -> {
+ try {
+ mService.registerCallback(proxy);
+ synchronized (mProxyDataLock) {
+ mProxyMap.put(callback, proxy);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception in registerCallback", e);
+ callback.onRegisterCallbackFailed(e);
+ }
+ }
+ );
}
/**