diff options
772 files changed, 16386 insertions, 6540 deletions
diff --git a/ACTIVITY_MANAGER_OWNERS b/ACTIVITY_MANAGER_OWNERS new file mode 100644 index 000000000000..47782d1406c4 --- /dev/null +++ b/ACTIVITY_MANAGER_OWNERS @@ -0,0 +1,4 @@ +mwachens@google.com +sudheersai@google.com +varunshah@google.com +yamasani@google.com diff --git a/AconfigFlags.bp b/AconfigFlags.bp index dd919cacc534..a0f38d9a7bd9 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -680,6 +680,11 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } +cc_aconfig_library { + name: "com.android.media.flags.editing-aconfig-cc", + aconfig_declarations: "com.android.media.flags.editing-aconfig", +} + // MediaProjection aconfig_declarations { name: "com.android.media.flags.projection-aconfig", diff --git a/Android.bp b/Android.bp index 5b9f2cbf2d0d..8c0158549d2d 100644 --- a/Android.bp +++ b/Android.bp @@ -99,6 +99,7 @@ filegroup { ":android.hardware.biometrics.common-V4-java-source", ":android.hardware.biometrics.fingerprint-V5-java-source", ":android.hardware.biometrics.fingerprint.virtualhal-java-source", + ":android.hardware.biometrics.face.virtualhal-java-source", ":android.hardware.biometrics.face-V4-java-source", ":android.hardware.gnss-V2-java-source", ":android.hardware.graphics.common-V3-java-source", diff --git a/BATTERY_STATS_OWNERS b/BATTERY_STATS_OWNERS index 7728975fcec1..575bded5ad64 100644 --- a/BATTERY_STATS_OWNERS +++ b/BATTERY_STATS_OWNERS @@ -1,4 +1,3 @@ # OWNERS of BatteryStats related files -bookatz@google.com dplotnikov@google.com mwachens@google.com diff --git a/OOM_ADJUSTER_OWNERS b/OOM_ADJUSTER_OWNERS new file mode 100644 index 000000000000..7727f9f014c0 --- /dev/null +++ b/OOM_ADJUSTER_OWNERS @@ -0,0 +1,3 @@ +mwachens@google.com +dplotnikov@google.com +tyk@google.com diff --git a/PERFORMANCE_OWNERS b/PERFORMANCE_OWNERS index 02b0a1ec75e7..d5d752f7ff23 100644 --- a/PERFORMANCE_OWNERS +++ b/PERFORMANCE_OWNERS @@ -7,3 +7,4 @@ shayba@google.com jdduke@google.com shombert@google.com kevinjeon@google.com +yforta@google.com diff --git a/apex/jobscheduler/ALARM_OWNERS b/apex/jobscheduler/ALARM_OWNERS new file mode 100644 index 000000000000..5c3bff7b42f4 --- /dev/null +++ b/apex/jobscheduler/ALARM_OWNERS @@ -0,0 +1,2 @@ +suprabh@google.com +tetianameronyk@google.com
\ 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 000000000000..62db91db98f8 --- /dev/null +++ b/apex/jobscheduler/DEVICE_IDLE_OWNERS @@ -0,0 +1,2 @@ +suprabh@google.com +guanxin@google.com
\ No newline at end of file diff --git a/apex/jobscheduler/JOB_OWNERS b/apex/jobscheduler/JOB_OWNERS new file mode 100644 index 000000000000..05bf25c50d60 --- /dev/null +++ b/apex/jobscheduler/JOB_OWNERS @@ -0,0 +1,3 @@ +suprabh@google.com +varunshah@google.com +guanxin@google.com
\ No newline at end of file diff --git a/apex/jobscheduler/OWNERS b/apex/jobscheduler/OWNERS index 22b648975e5f..ffa58022c4f7 100644 --- a/apex/jobscheduler/OWNERS +++ b/apex/jobscheduler/OWNERS @@ -1,8 +1,25 @@ -ctate@android.com -ctate@google.com -dplotnikov@google.com -jji@google.com -omakoto@google.com -suprabh@google.com -varunshah@google.com -yamasani@google.com +# 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 + +suprabh@google.com #{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 0b1e559dda15..000000000000 --- a/apex/jobscheduler/framework/java/android/app/job/OWNERS +++ /dev/null @@ -1,6 +0,0 @@ -# Bug component: 330738 - -yamasani@google.com -omakoto@google.com -ctate@android.com -ctate@google.com diff --git a/core/api/current.txt b/core/api/current.txt index 542543d11318..2c6e1cb44c7f 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -5333,6 +5333,7 @@ package android.app { method @NonNull public String getProcessName(); method public int getRealUid(); method public int getReason(); + method @FlaggedApi("android.app.app_start_info_component") public int getStartComponent(); method public int getStartType(); method public int getStartupState(); method @NonNull public java.util.Map<java.lang.Integer,java.lang.Long> getStartupTimestamps(); @@ -5347,6 +5348,11 @@ package android.app { field public static final int STARTUP_STATE_ERROR = 1; // 0x1 field public static final int STARTUP_STATE_FIRST_FRAME_DRAWN = 2; // 0x2 field public static final int STARTUP_STATE_STARTED = 0; // 0x0 + field @FlaggedApi("android.app.app_start_info_component") public static final int START_COMPONENT_ACTIVITY = 1; // 0x1 + field @FlaggedApi("android.app.app_start_info_component") public static final int START_COMPONENT_BROADCAST = 2; // 0x2 + field @FlaggedApi("android.app.app_start_info_component") public static final int START_COMPONENT_CONTENT_PROVIDER = 3; // 0x3 + field @FlaggedApi("android.app.app_start_info_component") public static final int START_COMPONENT_OTHER = 5; // 0x5 + field @FlaggedApi("android.app.app_start_info_component") public static final int START_COMPONENT_SERVICE = 4; // 0x4 field public static final int START_REASON_ALARM = 0; // 0x0 field public static final int START_REASON_BACKUP = 1; // 0x1 field public static final int START_REASON_BOOT_COMPLETE = 2; // 0x2 @@ -6495,6 +6501,7 @@ package android.app { field public static final int FLAG_NO_CLEAR = 32; // 0x20 field public static final int FLAG_ONGOING_EVENT = 2; // 0x2 field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8 + field @FlaggedApi("android.app.api_rich_ongoing") public static final int FLAG_PROMOTED_ONGOING = 262144; // 0x40000 field @Deprecated public static final int FLAG_SHOW_LIGHTS = 1; // 0x1 field public static final int FOREGROUND_SERVICE_DEFAULT = 0; // 0x0 field public static final int FOREGROUND_SERVICE_DEFERRED = 2; // 0x2 @@ -19396,7 +19403,7 @@ package android.hardware.camera2 { 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 +19928,7 @@ package android.hardware.camera2 { 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 +19954,7 @@ package android.hardware.camera2 { 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 +20114,10 @@ package android.hardware.camera2.params { 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 { @@ -36934,14 +36941,16 @@ package android.provider { @FlaggedApi("android.provider.new_default_account_api_enabled") public static final class ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState { ctor public ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState(int, @Nullable android.accounts.Account); - method @Nullable public android.accounts.Account getCloudAccount(); + method @Nullable public android.accounts.Account getAccount(); method public int getState(); method @NonNull public static android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState ofCloud(@NonNull android.accounts.Account); method @NonNull public static android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState ofLocal(); method @NonNull public static android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState ofNotSet(); + method @NonNull public static android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState ofSim(@NonNull android.accounts.Account); field public static final int DEFAULT_ACCOUNT_STATE_CLOUD = 3; // 0x3 field public static final int DEFAULT_ACCOUNT_STATE_LOCAL = 2; // 0x2 field public static final int DEFAULT_ACCOUNT_STATE_NOT_SET = 1; // 0x1 + field public static final int DEFAULT_ACCOUNT_STATE_SIM = 4; // 0x4 } public static final class ContactsContract.RawContacts.DisplayPhoto { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index b2a49e11c8df..cc0354c32de2 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -4950,94 +4950,94 @@ package android.hardware.camera2 { 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); - } - - @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); - } - - @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 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); + } + + 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); + } + + 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/java/android/app/ApplicationStartInfo.java b/core/java/android/app/ApplicationStartInfo.java index 1e9a79bca65a..fad289c1beb8 100644 --- a/core/java/android/app/ApplicationStartInfo.java +++ b/core/java/android/app/ApplicationStartInfo.java @@ -102,10 +102,10 @@ public final class ApplicationStartInfo implements Parcelable { /** Process started due to boot complete. */ public static final int START_REASON_BOOT_COMPLETE = 2; - /** Process started due to broadcast received. */ + /** Process started due to broadcast received for any reason not explicitly listed. */ public static final int START_REASON_BROADCAST = 3; - /** Process started due to access of ContentProvider */ + /** Process started due to access of ContentProvider for any reason not explicitly listed. */ public static final int START_REASON_CONTENT_PROVIDER = 4; /** * Process started to run scheduled job. */ @@ -123,7 +123,7 @@ public final class ApplicationStartInfo implements Parcelable { /** Process started due to push message. */ public static final int START_REASON_PUSH = 9; - /** Process service started. */ + /** Process started due to Service started for any reason not explicitly listed.. */ public static final int START_REASON_SERVICE = 10; /** Process started due to Activity started for any reason not explicitly listed. */ @@ -209,6 +209,26 @@ public final class ApplicationStartInfo implements Parcelable { /** Clock monotonic timestamp of surfaceflinger composition complete. */ public static final int START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE = 7; + /** Process was started for an activity component. */ + @FlaggedApi(Flags.FLAG_APP_START_INFO_COMPONENT) + public static final int START_COMPONENT_ACTIVITY = 1; + + /** Process was started for a broadcast component. */ + @FlaggedApi(Flags.FLAG_APP_START_INFO_COMPONENT) + public static final int START_COMPONENT_BROADCAST = 2; + + /** Process was started for a content provider component. */ + @FlaggedApi(Flags.FLAG_APP_START_INFO_COMPONENT) + public static final int START_COMPONENT_CONTENT_PROVIDER = 3; + + /** Process was started for a service component. */ + @FlaggedApi(Flags.FLAG_APP_START_INFO_COMPONENT) + public static final int START_COMPONENT_SERVICE = 4; + + /** Process was started not for one of the four standard components. */ + @FlaggedApi(Flags.FLAG_APP_START_INFO_COMPONENT) + public static final int START_COMPONENT_OTHER = 5; + /** * @see #getMonoticCreationTimeMs */ @@ -280,6 +300,11 @@ public final class ApplicationStartInfo implements Parcelable { private boolean mWasForceStopped; /** + * @see #getStartComponent() + */ + private @StartComponent int mStartComponent; + + /** * @hide * */ @IntDef( @@ -344,6 +369,21 @@ public final class ApplicationStartInfo implements Parcelable { public @interface LaunchMode {} /** + * @hide * + */ + @IntDef( + prefix = {"START_COMPONENT_"}, + value = { + START_COMPONENT_ACTIVITY, + START_COMPONENT_BROADCAST, + START_COMPONENT_CONTENT_PROVIDER, + START_COMPONENT_SERVICE, + START_COMPONENT_OTHER, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface StartComponent {} + + /** * @see #getStartupState * @hide */ @@ -480,6 +520,14 @@ public final class ApplicationStartInfo implements Parcelable { } /** + * @see #getStartComponent() + * @hide + */ + public void setStartComponent(@StartComponent int startComponent) { + mStartComponent = startComponent; + } + + /** * Current state of startup. * * Can be used to determine whether the object will have additional fields added as it may be @@ -567,6 +615,11 @@ public final class ApplicationStartInfo implements Parcelable { /** * The reason code of what triggered the process's start. * + * Start reason provides granular reasoning on why the app is being started. Start reason should + * not be used for distinguishing between the component the app is being started for as some + * reasons may overlap with multiple components, see {@link #getStartComponent} for this + * functionality instead. + * * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p> */ public @StartReason int getReason() { @@ -654,6 +707,22 @@ public final class ApplicationStartInfo implements Parcelable { return mWasForceStopped; } + /** + * The component type that was being started which triggered the start. + * + * Start component should be used to accurately distinguish between the 4 component types: + * activity, service, broadcast, and content provider. This can be useful for optimizing + * startup flow by enabling the caller to only load the necessary dependencies for a specific + * component type. For more granular information on why the app is being started, see + * {@link #getReason}. + * + * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p> + */ + @FlaggedApi(Flags.FLAG_APP_START_INFO_COMPONENT) + public @StartComponent int getStartComponent() { + return mStartComponent; + } + @Override public int describeContents() { return 0; @@ -680,6 +749,8 @@ public final class ApplicationStartInfo implements Parcelable { dest.writeParcelable(mStartIntent, flags); dest.writeInt(mLaunchMode); dest.writeBoolean(mWasForceStopped); + dest.writeLong(mMonoticCreationTimeMs); + dest.writeInt(mStartComponent); } /** @hide */ @@ -703,6 +774,7 @@ public final class ApplicationStartInfo implements Parcelable { mLaunchMode = other.mLaunchMode; mWasForceStopped = other.mWasForceStopped; mMonoticCreationTimeMs = other.mMonoticCreationTimeMs; + mStartComponent = other.mStartComponent; } private ApplicationStartInfo(@NonNull Parcel in) { @@ -726,6 +798,7 @@ public final class ApplicationStartInfo implements Parcelable { mLaunchMode = in.readInt(); mWasForceStopped = in.readBoolean(); mMonoticCreationTimeMs = in.readLong(); + mStartComponent = in.readInt(); } private static String intern(@Nullable String source) { @@ -805,6 +878,7 @@ public final class ApplicationStartInfo implements Parcelable { proto.write(ApplicationStartInfoProto.LAUNCH_MODE, mLaunchMode); proto.write(ApplicationStartInfoProto.WAS_FORCE_STOPPED, mWasForceStopped); proto.write(ApplicationStartInfoProto.MONOTONIC_CREATION_TIME_MS, mMonoticCreationTimeMs); + proto.write(ApplicationStartInfoProto.START_COMPONENT, mStartComponent); proto.end(token); } @@ -892,6 +966,9 @@ public final class ApplicationStartInfo implements Parcelable { mMonoticCreationTimeMs = proto.readLong( ApplicationStartInfoProto.MONOTONIC_CREATION_TIME_MS); break; + case (int) ApplicationStartInfoProto.START_COMPONENT: + mStartComponent = proto.readInt(ApplicationStartInfoProto.START_COMPONENT); + break; } } proto.end(token); @@ -918,8 +995,11 @@ public final class ApplicationStartInfo implements Parcelable { .append(" reason=").append(reasonToString(mReason)) .append(" startType=").append(startTypeToString(mStartType)) .append(" launchMode=").append(mLaunchMode) - .append(" wasForceStopped=").append(mWasForceStopped) - .append('\n'); + .append(" wasForceStopped=").append(mWasForceStopped); + if (Flags.appStartInfoComponent()) { + sb.append(" startComponent=").append(startComponentToString(mStartComponent)); + } + sb.append('\n'); if (mStartIntent != null) { sb.append(" intent=").append(mStartIntent.toString()) .append('\n'); @@ -963,6 +1043,18 @@ public final class ApplicationStartInfo implements Parcelable { }; } + @FlaggedApi(Flags.FLAG_APP_START_INFO_COMPONENT) + private static String startComponentToString(@StartComponent int startComponent) { + return switch (startComponent) { + case START_COMPONENT_ACTIVITY -> "ACTIVITY"; + case START_COMPONENT_BROADCAST -> "SERVICE"; + case START_COMPONENT_CONTENT_PROVIDER -> "CONTENT PROVIDER"; + case START_COMPONENT_SERVICE -> "SERVICE"; + case START_COMPONENT_OTHER -> "OTHER"; + default -> ""; + }; + } + /** @hide */ @Override public boolean equals(@Nullable Object other) { @@ -971,18 +1063,19 @@ public final class ApplicationStartInfo implements Parcelable { } final ApplicationStartInfo o = (ApplicationStartInfo) other; return mPid == o.mPid && mRealUid == o.mRealUid && mPackageUid == o.mPackageUid - && mDefiningUid == o.mDefiningUid && mReason == o.mReason - && mStartupState == o.mStartupState && mStartType == o.mStartType - && mLaunchMode == o.mLaunchMode && TextUtils.equals(mProcessName, o.mProcessName) - && timestampsEquals(o) && mWasForceStopped == o.mWasForceStopped - && mMonoticCreationTimeMs == o.mMonoticCreationTimeMs; + && mDefiningUid == o.mDefiningUid && mReason == o.mReason + && mStartupState == o.mStartupState && mStartType == o.mStartType + && mLaunchMode == o.mLaunchMode && TextUtils.equals(mProcessName, o.mProcessName) + && timestampsEquals(o) && mWasForceStopped == o.mWasForceStopped + && mMonoticCreationTimeMs == o.mMonoticCreationTimeMs + && mStartComponent == o.mStartComponent; } @Override public int hashCode() { return Objects.hash(mPid, mRealUid, mPackageUid, mDefiningUid, mReason, mStartupState, mStartType, mLaunchMode, mProcessName, mStartupTimestampsNs, - mMonoticCreationTimeMs); + mMonoticCreationTimeMs, mStartComponent); } private boolean timestampsEquals(@NonNull ApplicationStartInfo other) { diff --git a/core/java/android/app/BroadcastStickyCache.java b/core/java/android/app/BroadcastStickyCache.java new file mode 100644 index 000000000000..d6f061be3b00 --- /dev/null +++ b/core/java/android/app/BroadcastStickyCache.java @@ -0,0 +1,229 @@ +/* + * 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.app; + +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Intent; +import android.content.IntentFilter; +import android.hardware.usb.UsbManager; +import android.media.AudioManager; +import android.net.ConnectivityManager; +import android.net.TetheringManager; +import android.net.nsd.NsdManager; +import android.net.wifi.WifiManager; +import android.net.wifi.p2p.WifiP2pManager; +import android.os.SystemProperties; +import android.os.UpdateLock; +import android.telephony.TelephonyManager; +import android.util.ArrayMap; +import android.view.WindowManagerPolicyConstants; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; + +import java.util.ArrayList; + +/** @hide */ +public class BroadcastStickyCache { + + private static final String[] CACHED_BROADCAST_ACTIONS = { + AudioManager.ACTION_HDMI_AUDIO_PLUG, + AudioManager.ACTION_HEADSET_PLUG, + AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED, + AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED, + AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, + AudioManager.RINGER_MODE_CHANGED_ACTION, + ConnectivityManager.CONNECTIVITY_ACTION, + Intent.ACTION_BATTERY_CHANGED, + Intent.ACTION_DEVICE_STORAGE_FULL, + Intent.ACTION_DEVICE_STORAGE_LOW, + Intent.ACTION_SIM_STATE_CHANGED, + NsdManager.ACTION_NSD_STATE_CHANGED, + TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED, + TetheringManager.ACTION_TETHER_STATE_CHANGED, + UpdateLock.UPDATE_LOCK_CHANGED, + UsbManager.ACTION_USB_STATE, + WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED, + WifiManager.NETWORK_STATE_CHANGED_ACTION, + WifiManager.SUPPLICANT_STATE_CHANGED_ACTION, + WifiManager.WIFI_STATE_CHANGED_ACTION, + WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION, + WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED, + "android.net.conn.INET_CONDITION_ACTION" // ConnectivityManager.INET_CONDITION_ACTION + }; + + @GuardedBy("sCachedStickyBroadcasts") + private static final ArrayList<CachedStickyBroadcast> sCachedStickyBroadcasts = + new ArrayList<>(); + + @GuardedBy("sCachedPropertyHandles") + private static final ArrayMap<String, SystemProperties.Handle> sCachedPropertyHandles = + new ArrayMap<>(); + + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public static boolean useCache(@Nullable IntentFilter filter) { + if (!shouldCache(filter)) { + return false; + } + synchronized (sCachedStickyBroadcasts) { + final CachedStickyBroadcast cachedStickyBroadcast = getValueUncheckedLocked(filter); + if (cachedStickyBroadcast == null) { + return false; + } + final long version = cachedStickyBroadcast.propertyHandle.getLong(-1 /* def */); + return version > 0 && cachedStickyBroadcast.version == version; + } + } + + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public static void add(@Nullable IntentFilter filter, @Nullable Intent intent) { + if (!shouldCache(filter)) { + return; + } + synchronized (sCachedStickyBroadcasts) { + CachedStickyBroadcast cachedStickyBroadcast = getValueUncheckedLocked(filter); + if (cachedStickyBroadcast == null) { + final String key = getKey(filter.getAction(0)); + final SystemProperties.Handle handle = SystemProperties.find(key); + final long version = handle == null ? -1 : handle.getLong(-1 /* def */); + if (version == -1) { + return; + } + cachedStickyBroadcast = new CachedStickyBroadcast(filter, handle); + sCachedStickyBroadcasts.add(cachedStickyBroadcast); + cachedStickyBroadcast.intent = intent; + cachedStickyBroadcast.version = version; + } else { + cachedStickyBroadcast.intent = intent; + cachedStickyBroadcast.version = cachedStickyBroadcast.propertyHandle + .getLong(-1 /* def */); + } + } + } + + private static boolean shouldCache(@Nullable IntentFilter filter) { + if (!Flags.useStickyBcastCache()) { + return false; + } + if (filter == null || filter.safeCountActions() != 1) { + return false; + } + if (!ArrayUtils.contains(CACHED_BROADCAST_ACTIONS, filter.getAction(0))) { + return false; + } + return true; + } + + @VisibleForTesting + @NonNull + public static String getKey(@NonNull String action) { + return "cache_key.system_server.sticky_bcast." + action; + } + + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + @Nullable + public static Intent getIntentUnchecked(@NonNull IntentFilter filter) { + synchronized (sCachedStickyBroadcasts) { + final CachedStickyBroadcast cachedStickyBroadcast = getValueUncheckedLocked(filter); + return cachedStickyBroadcast.intent; + } + } + + @GuardedBy("sCachedStickyBroadcasts") + @Nullable + private static CachedStickyBroadcast getValueUncheckedLocked(@NonNull IntentFilter filter) { + for (int i = sCachedStickyBroadcasts.size() - 1; i >= 0; --i) { + final CachedStickyBroadcast cachedStickyBroadcast = sCachedStickyBroadcasts.get(i); + if (IntentFilter.filterEquals(filter, cachedStickyBroadcast.filter)) { + return cachedStickyBroadcast; + } + } + return null; + } + + public static void incrementVersion(@NonNull String action) { + if (!shouldIncrementVersion(action)) { + return; + } + final String key = getKey(action); + synchronized (sCachedPropertyHandles) { + SystemProperties.Handle handle = sCachedPropertyHandles.get(key); + final long version; + if (handle == null) { + handle = SystemProperties.find(key); + if (handle != null) { + sCachedPropertyHandles.put(key, handle); + } + } + version = handle == null ? 0 : handle.getLong(0 /* def */); + SystemProperties.set(key, String.valueOf(version + 1)); + if (handle == null) { + sCachedPropertyHandles.put(key, SystemProperties.find(key)); + } + } + } + + public static void incrementVersionIfExists(@NonNull String action) { + if (!shouldIncrementVersion(action)) { + return; + } + final String key = getKey(action); + synchronized (sCachedPropertyHandles) { + final SystemProperties.Handle handle = sCachedPropertyHandles.get(key); + if (handle == null) { + return; + } + final long version = handle.getLong(0 /* def */); + SystemProperties.set(key, String.valueOf(version + 1)); + } + } + + private static boolean shouldIncrementVersion(@NonNull String action) { + if (!Flags.useStickyBcastCache()) { + return false; + } + if (!ArrayUtils.contains(CACHED_BROADCAST_ACTIONS, action)) { + return false; + } + return true; + } + + @VisibleForTesting + public static void clearForTest() { + synchronized (sCachedStickyBroadcasts) { + sCachedStickyBroadcasts.clear(); + } + synchronized (sCachedPropertyHandles) { + sCachedPropertyHandles.clear(); + } + } + + private static final class CachedStickyBroadcast { + @NonNull public final IntentFilter filter; + @Nullable public Intent intent; + @IntRange(from = 0) public long version; + @NonNull public final SystemProperties.Handle propertyHandle; + + CachedStickyBroadcast(@NonNull IntentFilter filter, + @NonNull SystemProperties.Handle propertyHandle) { + this.filter = filter; + this.propertyHandle = propertyHandle; + } + } +} diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 90fba2962a23..ecef0db46bb2 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1921,10 +1921,19 @@ class ContextImpl extends Context { } } try { - final Intent intent = ActivityManager.getService().registerReceiverWithFeature( - mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(), - AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission, userId, - flags); + final Intent intent; + if (receiver == null && BroadcastStickyCache.useCache(filter)) { + intent = BroadcastStickyCache.getIntentUnchecked(filter); + } else { + intent = ActivityManager.getService().registerReceiverWithFeature( + mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(), + AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission, + userId, + flags); + if (receiver == null) { + BroadcastStickyCache.add(filter, intent); + } + } if (intent != null) { intent.setExtrasClassLoader(getClassLoader()); // TODO: determine at registration time if caller is diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index e2bee64cbb7b..b9fe356690e0 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -258,4 +258,6 @@ interface INotificationManager @EnforcePermission(allOf={"INTERACT_ACROSS_USERS", "ACCESS_NOTIFICATIONS"}) void unregisterCallNotificationEventListener(String packageName, in UserHandle userHandle, in ICallNotificationEventCallback listener); + void setCanBePromoted(String pkg, int uid, boolean promote); + boolean canBePromoted(String pkg, int uid); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 81d2c890ee31..392a1f113c23 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -772,6 +772,17 @@ public class Notification implements Parcelable @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_SILENT_FLAG) public static final int FLAG_SILENT = 1 << 17; //0x00020000 + /** + * Bit to be bitwise-ored into the {@link #flags} field that should be + * set by the system if this notification is a promoted ongoing notification, either via a + * user setting or allowlist. + * + * Applications cannot set this flag directly, but the posting app and + * {@link android.service.notification.NotificationListenerService} can read it. + */ + @FlaggedApi(Flags.FLAG_API_RICH_ONGOING) + public static final int FLAG_PROMOTED_ONGOING = 0x00040000; + private static final List<Class<? extends Style>> PLATFORM_STYLE_CLASSES = Arrays.asList( BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class, DecoratedCustomViewStyle.class, DecoratedMediaCustomViewStyle.class, @@ -3110,6 +3121,53 @@ public class Notification implements Parcelable } /** + * @hide + */ + @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING) + public boolean containsCustomViews() { + return contentView != null + || bigContentView != null + || headsUpContentView != null + || (publicVersion != null + && (publicVersion.contentView != null + || publicVersion.bigContentView != null + || publicVersion.headsUpContentView != null)); + } + + /** + * @hide + */ + @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING) + public boolean hasTitle() { + return extras != null + && (!TextUtils.isEmpty(extras.getCharSequence(EXTRA_TITLE)) + || !TextUtils.isEmpty(extras.getCharSequence(EXTRA_TITLE_BIG))); + } + + /** + * @hide + */ + @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING) + public boolean hasPromotableStyle() { + //TODO(b/367739672): Add progress style + return extras == null || !extras.containsKey(Notification.EXTRA_TEMPLATE) + || isStyle(Notification.BigPictureStyle.class) + || isStyle(Notification.BigTextStyle.class) + || isStyle(Notification.CallStyle.class); + } + + /** + * @hide + */ + @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING) + public boolean hasPromotableCharacteristics() { + return isColorized() + && hasTitle() + && !containsCustomViews() + && hasPromotableStyle(); + } + + /** * Whether this notification was posted by a headless system app. * * If we don't have enough information to figure this out, this will return false. Therefore, @@ -7636,7 +7694,6 @@ public class Notification implements Parcelable if (mLargeIcon != null || largeIcon != null) { Resources resources = context.getResources(); - Class<? extends Style> style = getNotificationStyle(); int maxSize = resources.getDimensionPixelSize(isLowRam ? R.dimen.notification_right_icon_size_low_ram : R.dimen.notification_right_icon_size); @@ -8782,6 +8839,16 @@ public class Notification implements Parcelable } /** + * @hide + */ + public boolean displayCustomViewInline() { + // This is a lie; True is returned for conversations to make sure that the custom + // view is not used instead of the template, but it will not actually be included. + return Flags.notificationNoCustomViewConversations() + && mConversationType != CONVERSATION_TYPE_LEGACY; + } + + /** * @return the text that should be displayed in the statusBar when heads upped. * If {@code null} is returned, the default implementation will be used. * diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS index cd7e40cf174d..d363e19bcc19 100644 --- a/core/java/android/app/OWNERS +++ b/core/java/android/app/OWNERS @@ -38,6 +38,7 @@ per-file GameState* = file:/GAME_MANAGER_OWNERS per-file IGameManager* = file:/GAME_MANAGER_OWNERS per-file IGameMode* = file:/GAME_MANAGER_OWNERS per-file BackgroundStartPrivileges.java = file:/BAL_OWNERS +per-file activity_manager.aconfig = file:/ACTIVITY_MANAGER_OWNERS # ActivityThread per-file ActivityThread.java = file:/services/core/java/com/android/server/am/OWNERS diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING index 5ed1f4e35533..637187e01160 100644 --- a/core/java/android/app/TEST_MAPPING +++ b/core/java/android/app/TEST_MAPPING @@ -177,6 +177,10 @@ { "file_patterns": ["(/|^)AppOpsManager.java"], "name": "CtsAppOpsTestCases" + }, + { + "file_patterns": ["(/|^)BroadcastStickyCache.java"], + "name": "BroadcastUnitTests" } ] } diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig index 38bd576d607a..1f31ab5d1849 100644 --- a/core/java/android/app/activity_manager.aconfig +++ b/core/java/android/app/activity_manager.aconfig @@ -147,3 +147,21 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + namespace: "backstage_power" + name: "use_sticky_bcast_cache" + description: "Use cache for sticky broadcast intents" + is_fixed_read_only: true + bug: "356148006" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + namespace: "system_performance" + name: "app_start_info_component" + description: "Control ApplicationStartInfo component field and API" + bug: "362537357" +} diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig index 9b06adf4e894..108b5f40863c 100644 --- a/core/java/android/app/notification.aconfig +++ b/core/java/android/app/notification.aconfig @@ -105,6 +105,13 @@ flag { } flag { + name: "notification_no_custom_view_conversations" + namespace: "systemui" + description: "Ensures that conversations are not allowed to use Custom Views." + bug: "368817201" +} + +flag { name: "keyguard_private_notifications" namespace: "systemui" description: "Fixes the behavior of KeyguardManager#setPrivateNotificationsAllowed()" @@ -244,4 +251,4 @@ flag { 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/Intent.java b/core/java/android/content/Intent.java index 031380dc1962..044178c4f6aa 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -20,6 +20,7 @@ import static android.app.sdksandbox.SdkSandboxManager.ACTION_START_SANDBOXED_AC import static android.content.ContentProvider.maybeAddUserId; import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE; import static android.security.Flags.FLAG_FRP_ENFORCEMENT; +import static android.security.Flags.preventIntentRedirect; import android.Manifest; import android.accessibilityservice.AccessibilityService; @@ -7687,9 +7688,17 @@ public class Intent implements Parcelable, Cloneable { /** @hide */ public static final int LOCAL_FLAG_FROM_SYSTEM = 1 << 5; + /** + * This flag indicates the creator token of this intent has been verified. + * + * @hide + */ + public static final int LOCAL_FLAG_CREATOR_TOKEN_VERIFIED = 1 << 6; + /** @hide */ @IntDef(flag = true, prefix = { "EXTENDED_FLAG_" }, value = { EXTENDED_FLAG_FILTER_MISMATCH, + EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN, }) @Retention(RetentionPolicy.SOURCE) public @interface ExtendedFlags {} @@ -7703,6 +7712,13 @@ public class Intent implements Parcelable, Cloneable { @TestApi public static final int EXTENDED_FLAG_FILTER_MISMATCH = 1 << 0; + /** + * This flag indicates the creator token of this intent is either missing or invalid. + * + * @hide + */ + public static final int EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN = 1 << 1; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // toUri() and parseUri() options. @@ -7870,6 +7886,7 @@ public class Intent implements Parcelable, Cloneable { this.mPackage = o.mPackage; this.mComponent = o.mComponent; this.mOriginalIntent = o.mOriginalIntent; + this.mCreatorTokenInfo = o.mCreatorTokenInfo; if (o.mCategories != null) { this.mCategories = new ArraySet<>(o.mCategories); @@ -12176,6 +12193,60 @@ public class Intent implements Parcelable, Cloneable { return (mExtras != null) ? mExtras.describeContents() : 0; } + private static class CreatorTokenInfo { + // Stores a creator token for an intent embedded as an extra intent in a top level intent, + private IBinder mCreatorToken; + // Stores all extra keys whose values are intents for a top level intent. + private ArraySet<String> mExtraIntentKeys; + } + + private @Nullable CreatorTokenInfo mCreatorTokenInfo; + + /** @hide */ + public void removeCreatorTokenInfo() { + mCreatorTokenInfo = null; + } + + /** @hide */ + public @Nullable IBinder getCreatorToken() { + return mCreatorTokenInfo == null ? null : mCreatorTokenInfo.mCreatorToken; + } + + /** @hide */ + public Set<String> getExtraIntentKeys() { + return mCreatorTokenInfo == null ? null : mCreatorTokenInfo.mExtraIntentKeys; + } + + /** @hide */ + public void setCreatorToken(@NonNull IBinder creatorToken) { + if (mCreatorTokenInfo == null) { + mCreatorTokenInfo = new CreatorTokenInfo(); + } + mCreatorTokenInfo.mCreatorToken = creatorToken; + } + + /** + * Collects keys in the extra bundle whose value are intents. + * @hide + */ + public void collectExtraIntentKeys() { + if (!preventIntentRedirect()) return; + + if (mExtras != null && !mExtras.isParcelled() && !mExtras.isEmpty()) { + for (String key : mExtras.keySet()) { + if (mExtras.get(key) instanceof Intent) { + if (mCreatorTokenInfo == null) { + mCreatorTokenInfo = new CreatorTokenInfo(); + } + if (mCreatorTokenInfo.mExtraIntentKeys == null) { + mCreatorTokenInfo.mExtraIntentKeys = new ArraySet<>(); + } + mCreatorTokenInfo.mExtraIntentKeys.add(key); + } + } + } + } + public void writeToParcel(Parcel out, int flags) { out.writeString8(mAction); Uri.writeToParcel(out, mData); @@ -12225,6 +12296,16 @@ public class Intent implements Parcelable, Cloneable { } else { out.writeInt(0); } + + if (preventIntentRedirect()) { + if (mCreatorTokenInfo == null) { + out.writeInt(0); + } else { + out.writeInt(1); + out.writeStrongBinder(mCreatorTokenInfo.mCreatorToken); + out.writeArraySet(mCreatorTokenInfo.mExtraIntentKeys); + } + } } public static final @android.annotation.NonNull Parcelable.Creator<Intent> CREATOR @@ -12282,6 +12363,14 @@ public class Intent implements Parcelable, Cloneable { if (in.readInt() != 0) { mOriginalIntent = new Intent(in); } + + if (preventIntentRedirect()) { + if (in.readInt() != 0) { + mCreatorTokenInfo = new CreatorTokenInfo(); + mCreatorTokenInfo.mCreatorToken = in.readStrongBinder(); + mCreatorTokenInfo.mExtraIntentKeys = (ArraySet<String>) in.readArraySet(null); + } + } } /** diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig index 34f3b61a8a88..fd1a89692da2 100644 --- a/core/java/android/content/pm/multiuser.aconfig +++ b/core/java/android/content/pm/multiuser.aconfig @@ -221,6 +221,17 @@ flag { } flag { + name: "cache_user_properties_correctly_read_only" + namespace: "multiuser" + description: "UserProperties cache needs to take into account who the callingUid is." + bug: "369198539" + metadata { + purpose: PURPOSE_BUGFIX + } + is_fixed_read_only: true +} + +flag { name: "cache_user_serial_number" namespace: "multiuser" description: "Optimise user serial number retrieval" diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java index 9b87df9ad3a4..3cf508a6db00 100644 --- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java @@ -259,10 +259,8 @@ public final class CameraExtensionCharacteristics { 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 @@ public final class CameraExtensionCharacteristics { 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 @@ public final class CameraExtensionCharacteristics { 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 @@ public final class CameraExtensionCharacteristics { 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); - - 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); - } + // Check if user enabled fallback impl + ContentResolver resolver = ctx.getContentResolver(); + int userEnabled = Settings.Secure.getInt(resolver, + Settings.Secure.CAMERA_EXTENSIONS_FALLBACK, 1); - if (!vendorImpl) { - unregisterClient(ctx, token, extension); - ret = registerClientHelper(ctx, token, extension, true /*useFallback*/); - } + 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*/); } return ret; diff --git a/core/java/android/hardware/camera2/CameraExtensionSession.java b/core/java/android/hardware/camera2/CameraExtensionSession.java index 2d9433e31ab2..20f89a55dd3b 100644 --- a/core/java/android/hardware/camera2/CameraExtensionSession.java +++ b/core/java/android/hardware/camera2/CameraExtensionSession.java @@ -156,7 +156,6 @@ public abstract class CameraExtensionSession implements AutoCloseable { * @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/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 75d617c89522..a18a634918f9 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -5293,7 +5293,6 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { @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 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * @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 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * @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 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { */ @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 8fa09a802aa4..df66f590148f 100644 --- a/core/java/android/hardware/camera2/extension/AdvancedExtender.java +++ b/core/java/android/hardware/camera2/extension/AdvancedExtender.java @@ -53,7 +53,6 @@ import java.util.Map; * @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 @@ public abstract class AdvancedExtender { * * @param cameraManager the system camera manager */ - @FlaggedApi(Flags.FLAG_CONCERT_MODE) public AdvancedExtender(@NonNull CameraManager cameraManager) { mCameraManager = cameraManager; try { @@ -101,7 +99,6 @@ public abstract class AdvancedExtender { * @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 @@ public abstract class AdvancedExtender { * 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 @@ public abstract class AdvancedExtender { * 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 @@ public abstract class AdvancedExtender { * 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 @@ public abstract class AdvancedExtender { * 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 @@ public abstract class AdvancedExtender { * 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 @@ public abstract class AdvancedExtender { * @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 @@ public abstract class AdvancedExtender { * @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 @@ public abstract class AdvancedExtender { * {@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 @@ public abstract class AdvancedExtender { 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 01698d54150c..9cc4f16fa627 100644 --- a/core/java/android/hardware/camera2/extension/CameraExtensionService.java +++ b/core/java/android/hardware/camera2/extension/CameraExtensionService.java @@ -42,7 +42,6 @@ interface CameraUsageTracker { * @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 @@ public abstract class CameraExtensionService extends Service { } }; - @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 @@ public abstract class CameraExtensionService extends Service { * 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 @@ public abstract class CameraExtensionService extends Service { * * @param token Binder token */ - @FlaggedApi(Flags.FLAG_CONCERT_MODE) public abstract void onUnregisterClient(@NonNull IBinder token); /** @@ -204,7 +199,6 @@ public abstract class CameraExtensionService extends Service { * 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 32139b8e314b..e8b20e37f40c 100644 --- a/core/java/android/hardware/camera2/extension/CameraOutputSurface.java +++ b/core/java/android/hardware/camera2/extension/CameraOutputSurface.java @@ -42,11 +42,9 @@ import com.android.internal.camera.flags.Flags; * @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 @@ public final class CameraOutputSurface { * @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 @@ public final class CameraOutputSurface { /** * Return the current output {@link Surface} */ - @FlaggedApi(Flags.FLAG_CONCERT_MODE) @NonNull public Surface getSurface() { return mOutputSurface.surface; @@ -84,7 +80,6 @@ public final class CameraOutputSurface { /** * 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 @@ public final class CameraOutputSurface { /** * 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 495abc8100ae..e578f6ef9064 100644 --- a/core/java/android/hardware/camera2/extension/CharacteristicsMap.java +++ b/core/java/android/hardware/camera2/extension/CharacteristicsMap.java @@ -36,7 +36,6 @@ import java.util.Set; * @hide */ @SystemApi -@FlaggedApi(Flags.FLAG_CONCERT_MODE) public class CharacteristicsMap { private final HashMap<String, CameraCharacteristics> mCharMap; @@ -46,7 +45,6 @@ public class CharacteristicsMap { * @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 @@ public class CharacteristicsMap { * * @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 @@ public class CharacteristicsMap { * @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 32de1ce8f0d6..43dfaa58554f 100644 --- a/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java +++ b/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java @@ -43,7 +43,6 @@ import java.util.List; * @hide */ @SystemApi -@FlaggedApi(Flags.FLAG_CONCERT_MODE) public class ExtensionConfiguration { private final int mSessionType; private final int mSessionTemplateId; @@ -65,7 +64,6 @@ public class ExtensionConfiguration { * @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 @@ public class ExtensionConfiguration { 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 8a47430e7eb4..ff0d8d7b53a5 100644 --- a/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java +++ b/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java @@ -35,7 +35,6 @@ import java.util.List; * @hide */ @SystemApi -@FlaggedApi(Flags.FLAG_CONCERT_MODE) public class ExtensionOutputConfiguration { private final List<CameraOutputSurface> mSurfaces; private final String mPhysicalCameraId; @@ -57,7 +56,6 @@ public class ExtensionOutputConfiguration { * @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 0ad27c212d67..936d57baadd3 100644 --- a/core/java/android/hardware/camera2/extension/RequestProcessor.java +++ b/core/java/android/hardware/camera2/extension/RequestProcessor.java @@ -45,19 +45,16 @@ import java.util.concurrent.Executor; * @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 @@ public final class RequestProcessor { * @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 @@ public final class RequestProcessor { * 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 @@ public final class RequestProcessor { * 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 @@ public final class RequestProcessor { * @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 @@ public final class RequestProcessor { * @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 @@ public final class RequestProcessor { * or {@link CaptureFailure#getFrameNumber}) in * the capture sequence. */ - @FlaggedApi(Flags.FLAG_CONCERT_MODE) void onCaptureSequenceCompleted(int sequenceId, long frameNumber); /** @@ -221,17 +212,14 @@ public final class RequestProcessor { * @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 @@ public final class RequestProcessor { * 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 @@ public final class RequestProcessor { /** * Gets all the parameters. */ - @FlaggedApi(Flags.FLAG_CONCERT_MODE) @NonNull public List<Pair<CaptureRequest.Key, Object>> getParameters() { return mParameters; @@ -265,7 +251,6 @@ public final class RequestProcessor { * * @see CameraDevice.RequestTemplate */ - @FlaggedApi(Flags.FLAG_CONCERT_MODE) Integer getTemplateId() { return mTemplateId; } @@ -322,7 +307,6 @@ public final class RequestProcessor { * @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 @@ public final class RequestProcessor { * @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 @@ public final class RequestProcessor { * @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 @@ public final class RequestProcessor { /** * Abort all ongoing capture requests. */ - @FlaggedApi(Flags.FLAG_CONCERT_MODE) public void abortCaptures() { try { mRequestProcessor.abortCaptures(); @@ -425,7 +406,6 @@ public final class RequestProcessor { /** * 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 eead4ef15ae8..cf9f30d89762 100644 --- a/core/java/android/hardware/camera2/extension/SessionProcessor.java +++ b/core/java/android/hardware/camera2/extension/SessionProcessor.java @@ -76,7 +76,6 @@ import java.util.concurrent.Executor; * @hide */ @SystemApi -@FlaggedApi(Flags.FLAG_CONCERT_MODE) public abstract class SessionProcessor { private static final String TAG = "SessionProcessor"; private CameraUsageTracker mCameraUsageTracker; @@ -84,7 +83,6 @@ public abstract class SessionProcessor { /** * Initialize a session process instance */ - @FlaggedApi(Flags.FLAG_CONCERT_MODE) public SessionProcessor() {} void setCameraUsageTracker(CameraUsageTracker tracker) { @@ -97,7 +95,6 @@ public abstract class SessionProcessor { * @hide */ @SystemApi - @FlaggedApi(Flags.FLAG_CONCERT_MODE) public interface CaptureCallback { /** * This method is called when the camera device has started @@ -116,7 +113,6 @@ public abstract class SessionProcessor { * first frame in a multi-frame capture, * in nanoseconds. */ - @FlaggedApi(Flags.FLAG_CONCERT_MODE) void onCaptureStarted(int captureSequenceId, long timestamp); /** @@ -126,7 +122,6 @@ public abstract class SessionProcessor { * * @param captureSequenceId id of the current capture sequence */ - @FlaggedApi(Flags.FLAG_CONCERT_MODE) void onCaptureProcessStarted(int captureSequenceId); /** @@ -139,7 +134,6 @@ public abstract class SessionProcessor { * @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 @@ public abstract class SessionProcessor { * * @param captureSequenceId id of the current capture sequence */ - @FlaggedApi(Flags.FLAG_CONCERT_MODE) void onCaptureSequenceCompleted(int captureSequenceId); /** @@ -162,7 +155,6 @@ public abstract class SessionProcessor { * * @param captureSequenceId id of the current capture sequence */ - @FlaggedApi(Flags.FLAG_CONCERT_MODE) void onCaptureSequenceAborted(int captureSequenceId); /** @@ -192,7 +184,6 @@ public abstract class SessionProcessor { * 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 @@ public abstract class SessionProcessor { * 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 @@ public abstract class SessionProcessor { * @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 @@ public abstract class SessionProcessor { * * */ - @FlaggedApi(Flags.FLAG_CONCERT_MODE) public abstract void onCaptureSessionStart(@NonNull RequestProcessor requestProcessor, @NonNull String statsKey); @@ -279,7 +267,6 @@ public abstract class SessionProcessor { * will no longer accept any requests after onCaptureSessionEnd() * returns. */ - @FlaggedApi(Flags.FLAG_CONCERT_MODE) public abstract void onCaptureSessionEnd(); /** @@ -293,7 +280,6 @@ public abstract class SessionProcessor { * @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 @@ public abstract class SessionProcessor { * forward calling {@link RequestProcessor#setRepeating} will simply * do nothing. */ - @FlaggedApi(Flags.FLAG_CONCERT_MODE) public abstract void stopRepeating(); /** @@ -326,7 +311,6 @@ public abstract class SessionProcessor { * @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 @@ public abstract class SessionProcessor { * 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 @@ public abstract class SessionProcessor { * @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 323712d817af..fc03b517e6d4 100644 --- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java @@ -873,17 +873,15 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes @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 0cd1c8ca89fe..ef7f3f8ab58b 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -1797,57 +1797,49 @@ public class CameraMetadataNative implements Parcelable { 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"); - } + return null; + } - if ((intrinsics.length / 5) != timestamps.length) { - throw new AssertionError(String.format( - "timestamps has %d entries but intrinsics has %d", timestamps.length, - intrinsics.length / 5)); - } + 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"); + } - 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.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 9a4ec5c94b5b..9157ef109356 100644 --- a/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java +++ b/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java @@ -31,7 +31,6 @@ import java.util.Arrays; * 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 @@ public final class LensIntrinsicsSample { * * @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 @@ public final class LensIntrinsicsSample { * * @return a long value (guaranteed to be finite) */ - @FlaggedApi(Flags.FLAG_CONCERT_MODE) public long getTimestampNanos() { return mTimestampNs; } @@ -72,7 +69,6 @@ public final class LensIntrinsicsSample { * @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/face/FaceSensorConfigurations.java b/core/java/android/hardware/face/FaceSensorConfigurations.java index 12471681f913..51c5f4c398a1 100644 --- a/core/java/android/hardware/face/FaceSensorConfigurations.java +++ b/core/java/android/hardware/face/FaceSensorConfigurations.java @@ -22,6 +22,7 @@ import android.annotation.Nullable; import android.content.Context; import android.hardware.biometrics.face.IFace; import android.hardware.biometrics.face.SensorProps; +import android.hardware.biometrics.face.virtualhal.IVirtualHal; import android.os.Binder; import android.os.Parcel; import android.os.Parcelable; @@ -160,6 +161,41 @@ public class FaceSensorConfigurations implements Parcelable { dest.writeByte((byte) (mResetLockoutRequiresChallenge ? 1 : 0)); dest.writeMap(mSensorPropsMap); } + /** + * Remap fqName of VHAL because the `virtual` instance is registered + * with IVirtulalHal now (IFace previously) + * @param fqName fqName to be translated + * @return real fqName + */ + public static String remapFqName(String fqName) { + if (!fqName.contains(IFace.DESCRIPTOR + "/virtual")) { + return fqName; //no remap needed for real hardware HAL + } else { + //new Vhal instance name + return fqName.replace("IFace", "virtualhal.IVirtualHal"); + } + } + /** + * @param fqName aidl interface instance name + * @return aidl interface + */ + public static IFace getIFace(String fqName) { + if (fqName.contains("virtual")) { + String fqNameMapped = remapFqName(fqName); + Slog.i(TAG, "getIFace fqName is mapped: " + fqName + "->" + fqNameMapped); + try { + IVirtualHal vhal = IVirtualHal.Stub.asInterface( + Binder.allowBlocking(ServiceManager.waitForService(fqNameMapped))); + return vhal.getFaceHal(); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception in vhal.getFaceHal() call" + fqNameMapped); + } + } + + return IFace.Stub.asInterface( + Binder.allowBlocking(ServiceManager.waitForDeclaredService(fqName))); + } + /** * Returns face sensor props for the HAL {@param instance}. @@ -173,14 +209,13 @@ public class FaceSensorConfigurations implements Parcelable { return props; } - final String fqName = IFace.DESCRIPTOR + "/" + instance; - IFace face = IFace.Stub.asInterface(Binder.allowBlocking( - ServiceManager.waitForDeclaredService(fqName))); try { - if (face != null) { - props = face.getSensorProps(); + final String fqName = IFace.DESCRIPTOR + "/" + instance; + final IFace fp = getIFace(fqName); + if (fp != null) { + props = fp.getSensorProps(); } else { - Slog.e(TAG, "Unable to get declared service: " + fqName); + Log.d(TAG, "IFace null for instance " + instance); } } catch (RemoteException e) { Log.d(TAG, "Unable to get sensor properties!"); diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index dbb6f92c6411..5f62b8be45a3 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -46,6 +46,7 @@ interface IPowerManager void userActivity(int displayId, long time, int event, int flags); void wakeUp(long time, int reason, String details, String opPackageName); + void wakeUpWithDisplayId(long time, int reason, String details, String opPackageName, int displayId); @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) void goToSleep(long time, int reason, int flags); @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 00ba3bf27c65..18f9b2b9d74f 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -139,7 +139,7 @@ interface IUserManager { 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 e4c12b6ff834..b9bae5b9f737 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -1567,27 +1567,9 @@ public final class PowerManager { } /** - * Forces the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group} - * to turn on. - * - * <p>If the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group} is - * turned off it will be turned on. Additionally, if the device is asleep it will be awoken. If - * the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group} is already - * on then nothing will happen. - * - * <p> - * This is what happens when the power key is pressed to turn on the screen. - * </p><p> - * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. - * </p> - * - * @param time The time when the request to wake up was issued, in the - * {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly - * order the wake up request with other power management functions. It should be set - * to the timestamp of the input event that caused the request to wake up. + * Forces the {@link android.view.Display#DEFAULT_DISPLAY default display} to turn on. * - * @see #userActivity - * @see #goToSleep + * @see #wakeUp(long, int, String, int) * * @deprecated Use {@link #wakeUp(long, int, String)} instead. * @removed Requires signature permission. @@ -1598,30 +1580,9 @@ public final class PowerManager { } /** - * Forces the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group} - * to turn on. - * - * <p>If the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group} is - * turned off it will be turned on. Additionally, if the device is asleep it will be awoken. If - * the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group} is already - * on then nothing will happen. - * - * <p> - * This is what happens when the power key is pressed to turn on the screen. - * </p><p> - * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. - * </p> - * - * @param time The time when the request to wake up was issued, in the - * {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly - * order the wake up request with other power management functions. It should be set - * to the timestamp of the input event that caused the request to wake up. - * - * @param details A free form string to explain the specific details behind the wake up for - * debugging purposes. + * Forces the {@link android.view.Display#DEFAULT_DISPLAY default display} to turn on. * - * @see #userActivity - * @see #goToSleep + * @see #wakeUp(long, int, String, int) * * @deprecated Use {@link #wakeUp(long, int, String)} instead. * @hide @@ -1635,9 +1596,23 @@ public final class PowerManager { /** * Forces the {@link android.view.Display#DEFAULT_DISPLAY default display} to turn on. * - * <p>If the {@link android.view.Display#DEFAULT_DISPLAY default display} is turned off it will - * be turned on. Additionally, if the device is asleep it will be awoken. If the {@link - * android.view.Display#DEFAULT_DISPLAY default display} is already on then nothing will happen. + * @see #wakeUp(long, int, String, int) + * @hide + */ + public void wakeUp(long time, @WakeReason int reason, String details) { + try { + mService.wakeUp(time, reason, details, mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Forces the display with the supplied displayId to turn on. + * + * <p>If the corresponding display is turned off, it will be turned on. Additionally, if the + * device is asleep it will be awoken. If the corresponding display is already on then nothing + * will happen. If the corresponding display does not exist, then nothing will happen. * * <p>If the device is an Android TV playback device, it will attempt to turn on the * HDMI-connected TV and become the current active source via the HDMI-CEC One Touch Play @@ -1658,14 +1633,16 @@ public final class PowerManager { * * @param details A free form string to explain the specific details behind the wake up for * debugging purposes. + * @param displayId The displayId of the display to be woken up. * * @see #userActivity * @see #goToSleep * @hide */ - public void wakeUp(long time, @WakeReason int reason, String details) { + public void wakeUp(long time, @WakeReason int reason, String details, int displayId) { try { - mService.wakeUp(time, reason, details, mContext.getOpPackageName()); + mService.wakeUpWithDisplayId(time, reason, details, mContext.getOpPackageName(), + displayId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 1ca4574e79b4..461f1e00c415 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -3706,9 +3706,13 @@ public class UserManager { * @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/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index b0791e36e124..bca5bcc99c7e 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -251,17 +251,18 @@ flag { } flag { - name: "replace_body_sensors_permission_enabled" - is_exported: true - namespace: "android_health_services" - description: "This flag is used to enable replacing permission BODY_SENSORS(and BODY_SENSORS_BACKGROUND) with granular health permission READ_HEART_RATE(and READ_HEALTH_DATA_IN_BACKGROUND)" - bug: "364638912" -} - -flag { name: "appop_access_tracking_logging_enabled" is_fixed_read_only: true namespace: "permissions" description: "Enables logging of the AppOp access tracking" bug: "365584286" } + +flag { + name: "replace_body_sensor_permission_enabled" + is_fixed_read_only: true + is_exported: true + namespace: "android_health_services" + description: "This fixed read-only flag is used to enable replacing permission BODY_SENSORS (and BODY_SENSORS_BACKGROUND) with granular health permission READ_HEART_RATE (and READ_HEALTH_DATA_IN_BACKGROUND)" + bug: "364638912" +} diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index a62281049678..27b1dfbd9b18 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -3046,6 +3046,11 @@ public final class ContactsContract { * <li> {@link #DEFAULT_ACCOUNT_STATE_CLOUD}: The default account is set to a * cloud-synced account. New raw contacts requested for insertion without a specified * {@link Account} will be saved in the default cloud account. </li> + * <li> {@link #DEFAULT_ACCOUNT_STATE_SIM}: The default account is set to a + * account that is associated with one of + * {@link SimContacts#getSimAccounts(ContentResolver)}. New raw contacts requested + * for insertion without a specified {@link Account} will be + * saved in this SIM account. </li> * </ul> */ @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED) @@ -3063,44 +3068,51 @@ public final class ContactsContract { public static final int DEFAULT_ACCOUNT_STATE_CLOUD = 3; /** + * A state indicating that the default account is set as an account that is + * associated with one of {@link SimContacts#getSimAccounts(ContentResolver)}. + */ + public static final int DEFAULT_ACCOUNT_STATE_SIM = 4; + + /** * The state of the default account. One of * {@link #DEFAULT_ACCOUNT_STATE_NOT_SET}, - * {@link #DEFAULT_ACCOUNT_STATE_LOCAL} or - * {@link #DEFAULT_ACCOUNT_STATE_CLOUD}. + * {@link #DEFAULT_ACCOUNT_STATE_LOCAL}, + * {@link #DEFAULT_ACCOUNT_STATE_CLOUD} + * {@link #DEFAULT_ACCOUNT_STATE_SIM}. */ @DefaultAccountState private final int mState; /** - * The account of the default account, when {@link mState} is { + * The account of the default account, when {@link #mState} is { * - * @link #STATE_SET_TO_CLOUD}, or null otherwise. + * @link #DEFAULT_ACCOUNT_STATE_CLOUD} or {@link #DEFAULT_ACCOUNT_STATE_SIM}, or + * null otherwise. */ - private final Account mCloudAccount; + private final Account mAccount; /** * Constructs a new `DefaultAccountAndState` instance with the specified state and * cloud * account. * - * @param state The state of the default account. - * @param cloudAccount The cloud account associated with the default account, - * or null if the state is not - * {@link #DEFAULT_ACCOUNT_STATE_CLOUD}. + * @param state The state of the default account. + * @param account The account associated with the default account if the state is + * {@link #DEFAULT_ACCOUNT_STATE_CLOUD} or + * {@link #DEFAULT_ACCOUNT_STATE_SIM}, or null otherwise. */ public DefaultAccountAndState(@DefaultAccountState int state, - @Nullable Account cloudAccount) { + @Nullable Account account) { if (!isValidDefaultAccountState(state)) { throw new IllegalArgumentException("Invalid default account state."); } - if ((state == DEFAULT_ACCOUNT_STATE_CLOUD) != (cloudAccount != null)) { + if (isCloudOrSimAccount(state) != (account != null)) { throw new IllegalArgumentException( - "Default account can be set to cloud if and only if the cloud " + "Default account can be set to cloud or SIM if and only if the " + "account is provided."); } this.mState = state; - this.mCloudAccount = - (mState == DEFAULT_ACCOUNT_STATE_CLOUD) ? cloudAccount : null; + this.mAccount = isCloudOrSimAccount(state) ? account : null; } /** @@ -3118,6 +3130,21 @@ public final class ContactsContract { return new DefaultAccountAndState(DEFAULT_ACCOUNT_STATE_CLOUD, cloudAccount); } + + /** + * Creates a `DefaultAccountAndState` instance representing a default account + * that is set to the sim and associated with the specified sim account. + * + * @param simAccount The non-null sim account associated with the default + * contacts account. + * @return A new `DefaultAccountAndState` instance with state + * {@link #DEFAULT_ACCOUNT_STATE_SIM}. + */ + public static @NonNull DefaultAccountAndState ofSim( + @NonNull Account simAccount) { + return new DefaultAccountAndState(DEFAULT_ACCOUNT_STATE_SIM, simAccount); + } + /** * Creates a `DefaultAccountAndState` instance representing a default account * that is set to the local device storage. @@ -3140,6 +3167,18 @@ public final class ContactsContract { return new DefaultAccountAndState(DEFAULT_ACCOUNT_STATE_NOT_SET, null); } + private static boolean isCloudOrSimAccount(@DefaultAccountState int state) { + return state == DEFAULT_ACCOUNT_STATE_CLOUD + || state == DEFAULT_ACCOUNT_STATE_SIM; + } + + private static boolean isValidDefaultAccountState(int state) { + return state == DEFAULT_ACCOUNT_STATE_NOT_SET + || state == DEFAULT_ACCOUNT_STATE_LOCAL + || state == DEFAULT_ACCOUNT_STATE_CLOUD + || state == DEFAULT_ACCOUNT_STATE_SIM; + } + /** * @return the state of the default account. */ @@ -3149,16 +3188,17 @@ public final class ContactsContract { } /** - * @return the cloud account associated with the default account, or null if the - * state is not {@link #DEFAULT_ACCOUNT_STATE_CLOUD}. + * @return the cloud account associated with the default account if the + * state is {@link #DEFAULT_ACCOUNT_STATE_CLOUD} or + * {@link #DEFAULT_ACCOUNT_STATE_SIM}. */ - public @Nullable Account getCloudAccount() { - return mCloudAccount; + public @Nullable Account getAccount() { + return mAccount; } @Override public int hashCode() { - return Objects.hash(mState, mCloudAccount); + return Objects.hash(mState, mAccount); } @Override @@ -3170,14 +3210,8 @@ public final class ContactsContract { return false; } - return mState == that.mState && Objects.equals(mCloudAccount, - that.mCloudAccount); - } - - private static boolean isValidDefaultAccountState(int state) { - return state == DEFAULT_ACCOUNT_STATE_NOT_SET - || state == DEFAULT_ACCOUNT_STATE_LOCAL - || state == DEFAULT_ACCOUNT_STATE_CLOUD; + return mState == that.mState && Objects.equals(mAccount, + that.mAccount); } /** @@ -3189,7 +3223,8 @@ public final class ContactsContract { @IntDef( prefix = {"DEFAULT_ACCOUNT_STATE_"}, value = {DEFAULT_ACCOUNT_STATE_NOT_SET, - DEFAULT_ACCOUNT_STATE_LOCAL, DEFAULT_ACCOUNT_STATE_CLOUD}) + DEFAULT_ACCOUNT_STATE_LOCAL, DEFAULT_ACCOUNT_STATE_CLOUD, + DEFAULT_ACCOUNT_STATE_SIM}) public @interface DefaultAccountState { } } diff --git a/core/java/android/security/forensic/OWNERS b/core/java/android/security/forensic/OWNERS new file mode 100644 index 000000000000..d9e82a6e42f2 --- /dev/null +++ b/core/java/android/security/forensic/OWNERS @@ -0,0 +1,8 @@ +# Bug component: 1630302 + +lizprucka@google.com +mteffeteller@google.com +myriamleggieri@google.com +rmneal@google.com +wenhaowang@google.com +willcoster@google.com diff --git a/core/java/android/security/responsible_apis_flags.aconfig b/core/java/android/security/responsible_apis_flags.aconfig index 56d3669ac50c..45e9def2c15f 100644 --- a/core/java/android/security/responsible_apis_flags.aconfig +++ b/core/java/android/security/responsible_apis_flags.aconfig @@ -52,3 +52,11 @@ flag { description: "Opt the system into enforcement of BAL" bug: "339403750" } + +flag { + name: "prevent_intent_redirect" + namespace: "responsible_apis" + description: "Prevent intent redirect attacks" + bug: "361143368" + is_fixed_read_only: true +}
\ No newline at end of file diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index d45b24ed69be..303197dfd82d 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -202,10 +202,8 @@ public class ZenModeConfig implements Parcelable { private static final int DEFAULT_CALLS_SOURCE = SOURCE_STAR; public static final String MANUAL_RULE_ID = "MANUAL_RULE"; - public static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE"; + public static final String EVENTS_OBSOLETE_RULE_ID = "EVENTS_DEFAULT_RULE"; public static final String EVERY_NIGHT_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE"; - public static final List<String> DEFAULT_RULE_IDS = Arrays.asList(EVERY_NIGHT_DEFAULT_RULE_ID, - EVENTS_DEFAULT_RULE_ID); public static final int[] ALL_DAYS = { Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY, Calendar.WEDNESDAY, Calendar.THURSDAY, Calendar.FRIDAY, Calendar.SATURDAY }; @@ -424,21 +422,10 @@ public class ZenModeConfig implements Parcelable { return policy; } + @FlaggedApi(Flags.FLAG_MODES_UI) public static ZenModeConfig getDefaultConfig() { ZenModeConfig config = new ZenModeConfig(); - EventInfo eventInfo = new EventInfo(); - eventInfo.reply = REPLY_YES_OR_MAYBE; - ZenRule events = new ZenRule(); - events.id = EVENTS_DEFAULT_RULE_ID; - events.conditionId = toEventConditionId(eventInfo); - events.component = ComponentName.unflattenFromString( - "android/com.android.server.notification.EventConditionProvider"); - events.enabled = false; - events.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - events.pkg = "android"; - config.automaticRules.put(EVENTS_DEFAULT_RULE_ID, events); - ScheduleInfo scheduleInfo = new ScheduleInfo(); scheduleInfo.days = new int[] {1, 2, 3, 4, 5, 6, 7}; scheduleInfo.startHour = 22; @@ -457,6 +444,13 @@ public class ZenModeConfig implements Parcelable { return config; } + // TODO: b/368247671 - Can be made a constant again when modes_ui is inlined + public static List<String> getDefaultRuleIds() { + return Flags.modesUi() + ? List.of(EVERY_NIGHT_DEFAULT_RULE_ID) + : List.of(EVERY_NIGHT_DEFAULT_RULE_ID, EVENTS_OBSOLETE_RULE_ID); + } + void ensureManualZenRule() { if (manualRule == null) { final ZenRule newRule = new ZenRule(); diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 384add5cf929..2ab16e91d987 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -2397,7 +2397,11 @@ public abstract class WallpaperService extends Service { // 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/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig index c83285a5c889..3599332af955 100644 --- a/core/java/android/text/flags/flags.aconfig +++ b/core/java/android/text/flags/flags.aconfig @@ -168,3 +168,13 @@ flag { description: "Decouple variation settings, weight and style information from Typeface class" bug: "361260253" } + +flag { + name: "handwriting_track_disabled" + namespace: "text" + description: "Handwriting initiator tracks focused view even if handwriting is disabled to fix initiation bug." + bug: "361256391" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java index ab9bd1fdfd72..f1329635f16c 100644 --- a/core/java/android/view/HandwritingInitiator.java +++ b/core/java/android/view/HandwritingInitiator.java @@ -17,6 +17,7 @@ package android.view; import static com.android.text.flags.Flags.handwritingCursorPosition; +import static com.android.text.flags.Flags.handwritingTrackDisabled; import static com.android.text.flags.Flags.handwritingUnsupportedMessage; import android.annotation.FlaggedApi; @@ -352,7 +353,7 @@ public class HandwritingInitiator { final View focusedView = getFocusedView(); - if (!view.isAutoHandwritingEnabled()) { + if (!handwritingTrackDisabled() && !view.isAutoHandwritingEnabled()) { clearFocusedView(focusedView); return; } @@ -363,7 +364,8 @@ public class HandwritingInitiator { updateFocusedView(view); if (mState != null && mState.mPendingFocusedView != null - && mState.mPendingFocusedView.get() == view) { + && mState.mPendingFocusedView.get() == view + && (!handwritingTrackDisabled() || view.isAutoHandwritingEnabled())) { startHandwriting(view); } } @@ -416,7 +418,7 @@ public class HandwritingInitiator { */ @VisibleForTesting public boolean updateFocusedView(@NonNull View view) { - if (!view.shouldInitiateHandwriting()) { + if (!handwritingTrackDisabled() && !view.shouldInitiateHandwriting()) { mFocusedView = null; return false; } @@ -424,8 +426,10 @@ public class HandwritingInitiator { final View focusedView = getFocusedView(); if (focusedView != view) { mFocusedView = new WeakReference<>(view); - // A new view just gain focus. By default, we should show hover icon for it. - mShowHoverIconForConnectedView = true; + if (!handwritingTrackDisabled() || view.shouldInitiateHandwriting()) { + // A new view just gain focus. By default, we should show hover icon for it. + mShowHoverIconForConnectedView = true; + } } return true; diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java index e90b1c0fc167..229e8ee75844 100644 --- a/core/java/android/view/ImeInsetsSourceConsumer.java +++ b/core/java/android/view/ImeInsetsSourceConsumer.java @@ -26,7 +26,6 @@ import android.annotation.Nullable; import android.os.IBinder; import android.os.Trace; import android.util.proto.ProtoOutputStream; -import android.view.SurfaceControl.Transaction; import android.view.inputmethod.Flags; import android.view.inputmethod.ImeTracker; import android.view.inputmethod.InputMethodManager; @@ -34,8 +33,6 @@ import android.view.inputmethod.InputMethodManager; import com.android.internal.inputmethod.ImeTracing; import com.android.internal.inputmethod.SoftInputShowHideReason; -import java.util.function.Supplier; - /** * Controls the visibility and animations of IME window insets source. * @hide @@ -54,10 +51,8 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { */ private boolean mIsRequestedVisibleAwaitingLeash; - public ImeInsetsSourceConsumer( - int id, InsetsState state, Supplier<Transaction> transactionSupplier, - InsetsController controller) { - super(id, WindowInsets.Type.ime(), state, transactionSupplier, controller); + public ImeInsetsSourceConsumer(int id, InsetsState state, InsetsController controller) { + super(id, WindowInsets.Type.ime(), state, controller); } @Override diff --git a/core/java/android/view/InsetsAnimationControlCallbacks.java b/core/java/android/view/InsetsAnimationControlCallbacks.java index 04bb6091672b..a0d8a173c3e5 100644 --- a/core/java/android/view/InsetsAnimationControlCallbacks.java +++ b/core/java/android/view/InsetsAnimationControlCallbacks.java @@ -54,13 +54,6 @@ public interface InsetsAnimationControlCallbacks { void notifyFinished(InsetsAnimationControlRunner runner, boolean shown); /** - * Apply the new params to the surface. - * @param params The {@link android.view.SyncRtSurfaceTransactionApplier.SurfaceParams} to - * apply. - */ - void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... params); - - /** * Post a message to release the Surface, guaranteed to happen after all * previous calls to applySurfaceParams. */ diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java index 91e9230cdc6a..97facc1ba472 100644 --- a/core/java/android/view/InsetsAnimationControlImpl.java +++ b/core/java/android/view/InsetsAnimationControlImpl.java @@ -99,6 +99,7 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro private final @InsetsType int mTypes; private @InsetsType int mControllingTypes; private final InsetsAnimationControlCallbacks mController; + private final SurfaceParamsApplier mSurfaceParamsApplier; private final WindowInsetsAnimation mAnimation; private final long mDurationMs; private final Interpolator mInterpolator; @@ -123,6 +124,7 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro public InsetsAnimationControlImpl(SparseArray<InsetsSourceControl> controls, @Nullable Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener, @InsetsType int types, InsetsAnimationControlCallbacks controller, + SurfaceParamsApplier surfaceParamsApplier, InsetsAnimationSpec insetsAnimationSpec, @AnimationType int animationType, @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation, CompatibilityInfo.Translator translator, @Nullable ImeTracker.Token statsToken) { @@ -131,6 +133,7 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro mTypes = types; mControllingTypes = types; mController = controller; + mSurfaceParamsApplier = surfaceParamsApplier; mInitialInsetsState = new InsetsState(state, true /* copySources */); if (frame != null) { final SparseIntArray idSideMap = new SparseIntArray(); @@ -258,6 +261,11 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro } @Override + public SurfaceParamsApplier getSurfaceParamsApplier() { + return mSurfaceParamsApplier; + } + + @Override @Nullable public ImeTracker.Token getStatsToken() { return mStatsToken; @@ -305,7 +313,7 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro updateLeashesForSide(SIDE_RIGHT, offset.right, params, outState, mPendingAlpha); updateLeashesForSide(SIDE_BOTTOM, offset.bottom, params, outState, mPendingAlpha); - mController.applySurfaceParams(params.toArray(new SurfaceParams[params.size()])); + mSurfaceParamsApplier.applySurfaceParams(params.toArray(new SurfaceParams[params.size()])); mCurrentInsets = mPendingInsets; mAnimation.setFraction(mPendingFraction); mCurrentAlpha = mPendingAlpha; diff --git a/core/java/android/view/InsetsAnimationControlRunner.java b/core/java/android/view/InsetsAnimationControlRunner.java index 8cb8b47dd0ec..4f102da4692a 100644 --- a/core/java/android/view/InsetsAnimationControlRunner.java +++ b/core/java/android/view/InsetsAnimationControlRunner.java @@ -77,6 +77,11 @@ public interface InsetsAnimationControlRunner { @AnimationType int getAnimationType(); /** + * @return The {@link SurfaceParamsApplier} this runner is using. + */ + SurfaceParamsApplier getSurfaceParamsApplier(); + + /** * @return The token tracking the current IME request or {@code null} otherwise. */ @Nullable @@ -99,4 +104,27 @@ public interface InsetsAnimationControlRunner { * @param fieldId FieldId of the implementation class */ void dumpDebug(ProtoOutputStream proto, long fieldId); + + /** + * Interface applying given surface operations. + */ + interface SurfaceParamsApplier { + + SurfaceParamsApplier DEFAULT = params -> { + final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + for (int i = params.length - 1; i >= 0; i--) { + SyncRtSurfaceTransactionApplier.applyParams(t, params[i], new float[9]); + } + t.apply(); + t.close(); + }; + + /** + * Apply the new params to the surface. + * + * @param params The {@link SyncRtSurfaceTransactionApplier.SurfaceParams} to apply. + */ + void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... params); + + } } diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java index fc185bc73735..8c2c4951a9f7 100644 --- a/core/java/android/view/InsetsAnimationThreadControlRunner.java +++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java @@ -17,7 +17,6 @@ package android.view; import static android.view.InsetsController.DEBUG; -import static android.view.SyncRtSurfaceTransactionApplier.applyParams; import android.annotation.Nullable; import android.annotation.UiThread; @@ -30,7 +29,6 @@ import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import android.view.InsetsController.AnimationType; import android.view.InsetsController.LayoutInsetsDuringAnimation; -import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams; import android.view.WindowInsets.Type.InsetsType; import android.view.WindowInsetsAnimation.Bounds; import android.view.inputmethod.ImeTracker; @@ -50,8 +48,6 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro private final InsetsAnimationControlCallbacks mCallbacks = new InsetsAnimationControlCallbacks() { - private final float[] mTmpFloat9 = new float[9]; - @Override @UiThread public <T extends InsetsAnimationControlRunner & InternalInsetsAnimationController> @@ -81,19 +77,6 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro } @Override - public void applySurfaceParams(SurfaceParams... params) { - if (DEBUG) Log.d(TAG, "applySurfaceParams"); - SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - for (int i = params.length - 1; i >= 0; i--) { - SyncRtSurfaceTransactionApplier.SurfaceParams surfaceParams = params[i]; - applyParams(t, surfaceParams, mTmpFloat9); - } - t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId()); - t.apply(); - t.close(); - } - - @Override public void releaseSurfaceControlFromRt(SurfaceControl sc) { if (DEBUG) Log.d(TAG, "releaseSurfaceControlFromRt"); // Since we don't push the SurfaceParams to the RT we can release directly @@ -106,6 +89,22 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro } }; + private SurfaceParamsApplier mSurfaceParamsApplier = new SurfaceParamsApplier() { + + private final float[] mTmpFloat9 = new float[9]; + + @Override + public void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... params) { + final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + for (int i = params.length - 1; i >= 0; i--) { + SyncRtSurfaceTransactionApplier.applyParams(t, params[i], mTmpFloat9); + } + t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId()); + t.apply(); + t.close(); + } + }; + @UiThread public InsetsAnimationThreadControlRunner(SparseArray<InsetsSourceControl> controls, @Nullable Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener, @@ -117,8 +116,8 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro mMainThreadHandler = mainThreadHandler; mOuterCallbacks = controller; mControl = new InsetsAnimationControlImpl(controls, frame, state, listener, types, - mCallbacks, insetsAnimationSpec, animationType, layoutInsetsDuringAnimation, - translator, statsToken); + mCallbacks, mSurfaceParamsApplier, insetsAnimationSpec, animationType, + layoutInsetsDuringAnimation, translator, statsToken); InsetsAnimationThread.getHandler().post(() -> { if (mControl.isCancelled()) { return; @@ -187,6 +186,11 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro } @Override + public SurfaceParamsApplier getSurfaceParamsApplier() { + return mSurfaceParamsApplier; + } + + @Override public void updateLayoutInsetsDuringAnimation( @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) { InsetsAnimationThread.getHandler().post( diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 8fdf91a2d87c..8ac553249378 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -29,7 +29,6 @@ import static android.view.WindowInsets.Type.captionBar; import static android.view.WindowInsets.Type.ime; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; -import static com.android.window.flags.Flags.insetsControlSeq; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -55,7 +54,6 @@ import android.util.Pair; import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import android.view.InsetsSourceConsumer.ShowResult; -import android.view.SurfaceControl.Transaction; import android.view.WindowInsets.Type; import android.view.WindowInsets.Type.InsetsType; import android.view.WindowInsetsAnimation.Bounds; @@ -85,7 +83,8 @@ import java.util.Objects; * Implements {@link WindowInsetsController} on the client. * @hide */ -public class InsetsController implements WindowInsetsController, InsetsAnimationControlCallbacks { +public class InsetsController implements WindowInsetsController, InsetsAnimationControlCallbacks, + InsetsAnimationControlRunner.SurfaceParamsApplier { private int mTypesBeingCancelled; @@ -307,7 +306,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } /** Not running an animation. */ - @VisibleForTesting public static final int ANIMATION_TYPE_NONE = -1; /** Running animation will show insets */ @@ -317,11 +315,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation public static final int ANIMATION_TYPE_HIDE = 1; /** Running animation is controlled by user via {@link #controlWindowInsetsAnimation} */ - @VisibleForTesting(visibility = PACKAGE) public static final int ANIMATION_TYPE_USER = 2; /** Running animation will resize insets */ - @VisibleForTesting public static final int ANIMATION_TYPE_RESIZE = 3; @Retention(RetentionPolicy.SOURCE) @@ -757,11 +753,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation public InsetsController(Host host) { this(host, (controller, id, type) -> { if (!Flags.refactorInsetsController() && type == ime()) { - return new ImeInsetsSourceConsumer(id, controller.mState, - Transaction::new, controller); + return new ImeInsetsSourceConsumer(id, controller.mState, controller); } else { - return new InsetsSourceConsumer(id, type, controller.mState, - Transaction::new, controller); + return new InsetsSourceConsumer(id, type, controller.mState, controller); } }, host.getHandler()); } @@ -882,9 +876,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @InsetsType int visibleTypes = 0; @InsetsType int[] cancelledUserAnimationTypes = {0}; for (int i = 0, size = newState.sourceSize(); i < size; i++) { - final InsetsSource source = insetsControlSeq() - ? new InsetsSource(newState.sourceAt(i)) - : newState.sourceAt(i); + final InsetsSource source = new InsetsSource(newState.sourceAt(i)); @InsetsType int type = source.getType(); @AnimationType int animationType = getAnimationType(type); final InsetsSourceConsumer consumer = mSourceConsumers.get(source.getId()); @@ -1525,9 +1517,15 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation insetsAnimationSpec, animationType, layoutInsetsDuringAnimation, mHost.getTranslator(), mHost.getHandler(), statsToken) : new InsetsAnimationControlImpl(controls, - frame, mState, listener, typesReady, this, insetsAnimationSpec, + frame, mState, listener, typesReady, this, this, insetsAnimationSpec, animationType, layoutInsetsDuringAnimation, mHost.getTranslator(), statsToken); + for (int i = controls.size() - 1; i >= 0; i--) { + final InsetsSourceConsumer consumer = mSourceConsumers.get(controls.keyAt(i)); + if (consumer != null) { + consumer.setSurfaceParamsApplier(runner.getSurfaceParamsApplier()); + } + } if ((typesReady & WindowInsets.Type.ime()) != 0) { ImeTracing.getInstance().triggerClientDump("InsetsAnimationControlImpl", mHost.getInputMethodManager(), null /* icProto */); diff --git a/core/java/android/view/InsetsResizeAnimationRunner.java b/core/java/android/view/InsetsResizeAnimationRunner.java index f90b8411e333..5262751cc6ed 100644 --- a/core/java/android/view/InsetsResizeAnimationRunner.java +++ b/core/java/android/view/InsetsResizeAnimationRunner.java @@ -94,6 +94,11 @@ public class InsetsResizeAnimationRunner implements InsetsAnimationControlRunner } @Override + public SurfaceParamsApplier getSurfaceParamsApplier() { + return SurfaceParamsApplier.DEFAULT; + } + + @Override @Nullable public ImeTracker.Token getStatsToken() { // Return null as resizing the IME view is not explicitly tracked. diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java index 391d757365e6..da788a78a95f 100644 --- a/core/java/android/view/InsetsSourceConsumer.java +++ b/core/java/android/view/InsetsSourceConsumer.java @@ -17,6 +17,7 @@ package android.view; import static android.view.InsetsController.ANIMATION_TYPE_NONE; +import static android.view.InsetsController.ANIMATION_TYPE_RESIZE; import static android.view.InsetsController.AnimationType; import static android.view.InsetsController.DEBUG; import static android.view.InsetsSourceConsumerProto.ANIMATION_STATE; @@ -28,16 +29,16 @@ import static android.view.InsetsSourceConsumerProto.SOURCE_CONTROL; import static android.view.InsetsSourceConsumerProto.TYPE_NUMBER; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; -import static com.android.window.flags.Flags.insetsControlSeq; import android.annotation.IntDef; import android.annotation.Nullable; +import android.graphics.Matrix; +import android.graphics.Point; import android.graphics.Rect; import android.os.IBinder; import android.text.TextUtils; import android.util.Log; import android.util.proto.ProtoOutputStream; -import android.view.SurfaceControl.Transaction; import android.view.WindowInsets.Type.InsetsType; import android.view.inputmethod.Flags; import android.view.inputmethod.ImeTracker; @@ -48,7 +49,6 @@ import com.android.internal.inputmethod.ImeTracing; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; -import java.util.function.Supplier; /** * Controls the visibility and animations of a single window insets source. @@ -92,10 +92,12 @@ public class InsetsSourceConsumer { private final int mType; private static final String TAG = "InsetsSourceConsumer"; - private final Supplier<Transaction> mTransactionSupplier; @Nullable private InsetsSourceControl mSourceControl; private boolean mHasWindowFocus; + private InsetsAnimationControlRunner.SurfaceParamsApplier mSurfaceParamsApplier = + InsetsAnimationControlRunner.SurfaceParamsApplier.DEFAULT; + private final Matrix mTmpMatrix = new Matrix(); /** * Whether the view has focus returned by {@link #onWindowFocusGained(boolean)}. @@ -108,16 +110,13 @@ public class InsetsSourceConsumer { * @param id The ID of the consumed insets. * @param type The {@link InsetsType} of the consumed insets. * @param state The current {@link InsetsState} of the consumed insets. - * @param transactionSupplier The source of new {@link Transaction} instances. The supplier - * must provide *new* instances, which will be explicitly closed by this class. * @param controller The {@link InsetsController} to use for insets interaction. */ public InsetsSourceConsumer(int id, @InsetsType int type, InsetsState state, - Supplier<Transaction> transactionSupplier, InsetsController controller) { + InsetsController controller) { mId = id; mType = type; mState = state; - mTransactionSupplier = transactionSupplier; mController = controller; } @@ -162,6 +161,9 @@ public class InsetsSourceConsumer { if (localVisible != serverVisible) { mController.notifyVisibilityChanged(); } + + // Reset the applier to the default one which has the most lightweight implementation. + setSurfaceParamsApplier(InsetsAnimationControlRunner.SurfaceParamsApplier.DEFAULT); } else { final boolean requestedVisible = isRequestedVisibleAwaitingControl(); final SurfaceControl oldLeash = lastControl != null ? lastControl.getLeash() : null; @@ -184,10 +186,11 @@ public class InsetsSourceConsumer { mController.notifyVisibilityChanged(); } - // If we have a new leash, make sure visibility is up-to-date, even though we - // didn't want to run an animation above. - if (mController.getAnimationType(mType) == ANIMATION_TYPE_NONE) { - applyRequestedVisibilityToControl(); + // If there is no animation controlling the leash, make sure the visibility and the + // position is up-to-date. Note: ANIMATION_TYPE_RESIZE doesn't control the leash. + final int animType = mController.getAnimationType(mType); + if (animType == ANIMATION_TYPE_NONE || animType == ANIMATION_TYPE_RESIZE) { + applyRequestedVisibilityAndPositionToControl(); } // Remove the surface that owned by last control when it lost. @@ -229,6 +232,15 @@ public class InsetsSourceConsumer { } /** + * Sets the SurfaceParamsApplier that the latest animation runner is using. The leash owned by + * this class is always applied by the applier, so that the transaction order can always be + * aligned with the calling sequence. + */ + void setSurfaceParamsApplier(InsetsAnimationControlRunner.SurfaceParamsApplier applier) { + mSurfaceParamsApplier = applier; + } + + /** * Called right after the animation is started or finished. */ @VisibleForTesting(visibility = PACKAGE) @@ -418,9 +430,6 @@ public class InsetsSourceConsumer { // Frame is changing while animating. Keep note of the new frame but keep existing frame // until animation is finished. - if (!insetsControlSeq()) { - newSource = new InsetsSource(newSource); - } mPendingFrame = new Rect(newSource.getFrame()); mPendingVisibleFrame = newSource.getVisibleFrame() != null ? new Rect(newSource.getVisibleFrame()) @@ -431,24 +440,30 @@ public class InsetsSourceConsumer { if (DEBUG) Log.d(TAG, "updateSource: " + newSource); } - private void applyRequestedVisibilityToControl() { - if (mSourceControl == null || mSourceControl.getLeash() == null) { + private void applyRequestedVisibilityAndPositionToControl() { + if (mSourceControl == null) { return; } - - final boolean requestedVisible = (mController.getRequestedVisibleTypes() & mType) != 0; - try (Transaction t = mTransactionSupplier.get()) { - if (DEBUG) Log.d(TAG, "applyRequestedVisibilityToControl: " + requestedVisible); - if (requestedVisible) { - t.show(mSourceControl.getLeash()); - } else { - t.hide(mSourceControl.getLeash()); - } - // Ensure the alpha value is aligned with the actual requested visibility. - t.setAlpha(mSourceControl.getLeash(), requestedVisible ? 1 : 0); - t.apply(); + final SurfaceControl leash = mSourceControl.getLeash(); + if (leash == null) { + return; } - onPerceptible(requestedVisible); + + final boolean visible = (mController.getRequestedVisibleTypes() & mType) != 0; + final Point surfacePosition = mSourceControl.getSurfacePosition(); + + if (DEBUG) Log.d(TAG, "applyRequestedVisibilityAndPositionToControl: visible=" + visible + + " position=" + surfacePosition); + + mTmpMatrix.setTranslate(surfacePosition.x, surfacePosition.y); + mSurfaceParamsApplier.applySurfaceParams( + new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(leash) + .withVisibility(visible) + .withAlpha(visible ? 1 : 0) + .withMatrix(mTmpMatrix) + .build()); + + onPerceptible(visible); } void dumpDebug(ProtoOutputStream proto, long fieldId) { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index d46e1f29597e..daa0c57cf08e 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -130,8 +130,6 @@ import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_ 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.insetsControlChangedItem; -import static com.android.window.flags.Flags.insetsControlSeq; import static com.android.window.flags.Flags.setScPropertiesInClient; import static com.android.window.flags.Flags.systemUiImmersiveConfirmationDialog; @@ -889,10 +887,7 @@ public final class ViewRootImpl implements ViewParent, /** Non-{@code null} if {@link #mActivityConfigCallback} is not {@code null}. */ @Nullable private ActivityWindowInfo mLastReportedActivityWindowInfo; - @Nullable - private final ClientWindowFrames mLastReportedFrames = insetsControlSeq() - ? new ClientWindowFrames() - : null; + private final ClientWindowFrames mLastReportedFrames = new ClientWindowFrames(); private int mLastReportedInsetsStateSeq = getInitSeq(); private int mLastReportedActiveControlsSeq = getInitSeq(); @@ -2317,9 +2312,6 @@ public final class ViewRootImpl implements ViewParent, } private void onClientWindowFramesChanged(@NonNull ClientWindowFrames inOutFrames) { - if (mLastReportedFrames == null) { - return; - } if (isIncomingSeqStale(mLastReportedFrames.seq, inOutFrames.seq)) { // If the incoming is stale, use the last reported instead. inOutFrames.setTo(mLastReportedFrames); @@ -2330,14 +2322,12 @@ public final class ViewRootImpl implements ViewParent, } private void onInsetsStateChanged(@NonNull InsetsState insetsState) { - if (insetsControlSeq()) { - if (isIncomingSeqStale(mLastReportedInsetsStateSeq, insetsState.getSeq())) { - // The incoming is stale. Skip. - return; - } - // Keep track of the latest. - mLastReportedInsetsStateSeq = insetsState.getSeq(); + if (isIncomingSeqStale(mLastReportedInsetsStateSeq, insetsState.getSeq())) { + // The incoming is stale. Skip. + return; } + // Keep track of the latest. + mLastReportedInsetsStateSeq = insetsState.getSeq(); if (mTranslator != null) { mTranslator.translateInsetsStateInScreenToAppWindow(insetsState); @@ -2352,15 +2342,13 @@ public final class ViewRootImpl implements ViewParent, return; } - if (insetsControlSeq()) { - if (isIncomingSeqStale(mLastReportedActiveControlsSeq, activeControls.getSeq())) { - // The incoming is stale. Skip. - activeControls.release(); - return; - } - // Keep track of the latest. - mLastReportedActiveControlsSeq = activeControls.getSeq(); + if (isIncomingSeqStale(mLastReportedActiveControlsSeq, activeControls.getSeq())) { + // The incoming is stale. Skip. + activeControls.release(); + return; } + // Keep track of the latest. + mLastReportedActiveControlsSeq = activeControls.getSeq(); final InsetsSourceControl[] controls = activeControls.get(); if (mTranslator != null) { @@ -11519,12 +11507,8 @@ public final class ViewRootImpl implements ViewParent, public void insetsControlChanged(InsetsState insetsState, InsetsSourceControl.Array activeControls) { final boolean isFromInsetsControlChangeItem; - if (insetsControlChangedItem()) { - isFromInsetsControlChangeItem = mIsFromTransactionItem; - mIsFromTransactionItem = false; - } else { - isFromInsetsControlChangeItem = false; - } + isFromInsetsControlChangeItem = mIsFromTransactionItem; + mIsFromTransactionItem = false; final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor == null) { if (isFromInsetsControlChangeItem) { diff --git a/core/java/android/window/flags/DesktopModeFlags.java b/core/java/android/window/flags/DesktopModeFlags.java index 395a85345277..944a106bf441 100644 --- a/core/java/android/window/flags/DesktopModeFlags.java +++ b/core/java/android/window/flags/DesktopModeFlags.java @@ -43,7 +43,7 @@ public enum DesktopModeFlags { // All desktop mode related flags to be overridden by developer option toggle will be added here ENABLE_DESKTOP_WINDOWING_MODE( Flags::enableDesktopWindowingMode, /* shouldOverrideByDevOption= */ true), - ENABLE_WINDOWING_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( @@ -58,12 +58,13 @@ public enum DesktopModeFlags { 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, false), + 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); + Flags::enableDesktopWindowingTaskbarRunningApps, true), + ENABLE_DESKTOP_WINDOWING_TRANSITIONS(Flags::enableDesktopWindowingTransitions, false); private static final String TAG = "DesktopModeFlagsUtil"; // Function called to obtain aconfig flag value. diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index e1402f8224eb..21eefef9ca89 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -111,6 +111,17 @@ flag { } flag { + name: "remove_activity_starter_dream_callback" + namespace: "windowing_frontend" + description: "Avoid a race with DreamManagerService callbacks for isDreaming by checking Activity state directly" + bug: "366452352" + metadata { + purpose: PURPOSE_BUGFIX + } + is_fixed_read_only: true +} + +flag { name: "supports_multi_instance_system_ui" is_exported: true namespace: "multitasking" @@ -266,3 +277,14 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "remove_starting_window_wait_for_multi_transitions" + namespace: "windowing_frontend" + description: "Avoid remove starting window too early when playing multiple transitions" + bug: "362347290" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig index 9ae3fc1fa3f0..f0ea7a82d763 100644 --- a/core/java/android/window/flags/windowing_sdk.aconfig +++ b/core/java/android/window/flags/windowing_sdk.aconfig @@ -68,27 +68,6 @@ flag { flag { namespace: "windowing_sdk" - name: "insets_control_changed_item" - description: "Pass insetsControlChanged through ClientTransaction to fix the racing" - bug: "339380439" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { - namespace: "windowing_sdk" - name: "insets_control_seq" - description: "Add seqId to InsetsControls to ensure the stale update is ignored" - bug: "339380439" - is_fixed_read_only: true - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { - namespace: "windowing_sdk" name: "move_animation_options_to_change" description: "Move AnimationOptions from TransitionInfo to each Change" bug: "327332488" diff --git a/core/java/com/android/internal/os/anr/OWNERS b/core/java/com/android/internal/os/anr/OWNERS index 9816752db891..1ad642f78cde 100644 --- a/core/java/com/android/internal/os/anr/OWNERS +++ b/core/java/com/android/internal/os/anr/OWNERS @@ -1,3 +1,2 @@ benmiles@google.com -gaillard@google.com mohamadmahmoud@google.com
\ No newline at end of file diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java index fbc058cc0330..b0e38e256430 100644 --- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java @@ -122,18 +122,20 @@ public class PerfettoProtoLogImpl extends IProtoLogClient.Stub implements IProto private final Lock mBackgroundServiceLock = new ReentrantLock(); private ExecutorService mBackgroundLoggingService = Executors.newSingleThreadExecutor(); - public PerfettoProtoLogImpl(@NonNull IProtoLogGroup[] groups) { + public PerfettoProtoLogImpl(@NonNull IProtoLogGroup[] groups) + throws ServiceManager.ServiceNotFoundException { this(null, null, null, () -> {}, groups); } - public PerfettoProtoLogImpl(@NonNull Runnable cacheUpdater, @NonNull IProtoLogGroup[] groups) { + public PerfettoProtoLogImpl(@NonNull Runnable cacheUpdater, @NonNull IProtoLogGroup[] groups) + throws ServiceManager.ServiceNotFoundException { this(null, null, null, cacheUpdater, groups); } public PerfettoProtoLogImpl( @NonNull String viewerConfigFilePath, @NonNull Runnable cacheUpdater, - @NonNull IProtoLogGroup[] groups) { + @NonNull IProtoLogGroup[] groups) throws ServiceManager.ServiceNotFoundException { this(viewerConfigFilePath, null, new ProtoLogViewerConfigReader(() -> { @@ -177,12 +179,14 @@ public class PerfettoProtoLogImpl extends IProtoLogClient.Stub implements IProto @Nullable ViewerConfigInputStreamProvider viewerConfigInputStreamProvider, @Nullable ProtoLogViewerConfigReader viewerConfigReader, @NonNull Runnable cacheUpdater, - @NonNull IProtoLogGroup[] groups) { + @NonNull IProtoLogGroup[] groups) throws ServiceManager.ServiceNotFoundException { this(viewerConfigFilePath, viewerConfigInputStreamProvider, viewerConfigReader, cacheUpdater, groups, ProtoLogDataSource::new, - IProtoLogConfigurationService.Stub - .asInterface(ServiceManager.getService(PROTOLOG_CONFIGURATION_SERVICE)) + android.tracing.Flags.clientSideProtoLogging() ? + IProtoLogConfigurationService.Stub.asInterface( + ServiceManager.getServiceOrThrow(PROTOLOG_CONFIGURATION_SERVICE) + ) : null ); } @@ -222,7 +226,7 @@ public class PerfettoProtoLogImpl extends IProtoLogClient.Stub implements IProto if (android.tracing.Flags.clientSideProtoLogging()) { mProtoLogConfigurationService = configurationService; Objects.requireNonNull(mProtoLogConfigurationService, - "ServiceManager returned a null ProtoLog Configuration Service"); + "A null ProtoLog Configuration Service was provided!"); try { var args = new ProtoLogConfigurationServiceImpl.RegisterClientArgs(); diff --git a/core/java/com/android/internal/protolog/ProtoLog.java b/core/java/com/android/internal/protolog/ProtoLog.java index bf77db7b6a33..adf03fe5f775 100644 --- a/core/java/com/android/internal/protolog/ProtoLog.java +++ b/core/java/com/android/internal/protolog/ProtoLog.java @@ -16,6 +16,8 @@ package com.android.internal.protolog; +import android.os.ServiceManager; + import com.android.internal.protolog.common.IProtoLog; import com.android.internal.protolog.common.IProtoLogGroup; import com.android.internal.protolog.common.LogLevel; @@ -76,7 +78,11 @@ public class ProtoLog { groups = allGroups.toArray(new IProtoLogGroup[0]); } - sProtoLogInstance = new PerfettoProtoLogImpl(groups); + try { + sProtoLogInstance = new PerfettoProtoLogImpl(groups); + } catch (ServiceManager.ServiceNotFoundException e) { + throw new RuntimeException(e); + } } } else { sProtoLogInstance = new LogcatOnlyProtoLogImpl(); diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java index 7bdcf2d14b19..5d67534b1b44 100644 --- a/core/java/com/android/internal/protolog/ProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java @@ -23,6 +23,7 @@ import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LO import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.VIEWER_CONFIG_PATH; import android.annotation.Nullable; +import android.os.ServiceManager; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -106,18 +107,23 @@ public class ProtoLogImpl { final var groups = sLogGroups.values().toArray(new IProtoLogGroup[0]); if (android.tracing.Flags.perfettoProtologTracing()) { - File f = new File(sViewerConfigPath); - if (!ProtoLog.REQUIRE_PROTOLOGTOOL && !f.exists()) { - // TODO(b/353530422): Remove - temporary fix to unblock b/352290057 - // In some tests the viewer config file might not exist in which we don't - // want to provide config path to the user - Log.w(LOG_TAG, "Failed to find viewerConfigFile when setting up " - + ProtoLogImpl.class.getSimpleName() + ". " - + "Setting up without a viewer config instead..."); - sServiceInstance = new PerfettoProtoLogImpl(sCacheUpdater, groups); - } else { - sServiceInstance = - new PerfettoProtoLogImpl(sViewerConfigPath, sCacheUpdater, groups); + try { + File f = new File(sViewerConfigPath); + if (!ProtoLog.REQUIRE_PROTOLOGTOOL && !f.exists()) { + // TODO(b/353530422): Remove - temporary fix to unblock b/352290057 + // In some tests the viewer config file might not exist in which we don't + // want to provide config path to the user + Log.w(LOG_TAG, "Failed to find viewerConfigFile when setting up " + + ProtoLogImpl.class.getSimpleName() + ". " + + "Setting up without a viewer config instead..."); + + sServiceInstance = new PerfettoProtoLogImpl(sCacheUpdater, groups); + } else { + sServiceInstance = + new PerfettoProtoLogImpl(sViewerConfigPath, sCacheUpdater, groups); + } + } catch (ServiceManager.ServiceNotFoundException e) { + throw new RuntimeException(e); } } else { var protologImpl = new LegacyProtoLogImpl( diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java index e65b4b65945f..c0a7383c9f06 100644 --- a/core/java/com/android/internal/widget/PointerLocationView.java +++ b/core/java/com/android/internal/widget/PointerLocationView.java @@ -16,14 +16,19 @@ package com.android.internal.widget; +import static java.lang.Float.NaN; + import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; +import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Insets; import android.graphics.Paint; import android.graphics.Paint.FontMetricsInt; import android.graphics.Path; +import android.graphics.PorterDuff; import android.graphics.RectF; import android.graphics.Region; import android.hardware.input.InputManager; @@ -65,11 +70,14 @@ public class PointerLocationView extends View implements InputDeviceListener, private static final PointerState EMPTY_POINTER_STATE = new PointerState(); public static class PointerState { - // Trace of previous points. - private float[] mTraceX = new float[32]; - private float[] mTraceY = new float[32]; - private boolean[] mTraceCurrent = new boolean[32]; - private int mTraceCount; + private float mCurrentX = NaN; + private float mCurrentY = NaN; + private float mPreviousX = NaN; + private float mPreviousY = NaN; + private float mFirstX = NaN; + private float mFirstY = NaN; + private boolean mPreviousPointIsHistorical; + private boolean mCurrentPointIsHistorical; // True if the pointer is down. @UnsupportedAppUsage @@ -96,31 +104,20 @@ public class PointerLocationView extends View implements InputDeviceListener, public PointerState() { } - public void clearTrace() { - mTraceCount = 0; - } - - public void addTrace(float x, float y, boolean current) { - int traceCapacity = mTraceX.length; - if (mTraceCount == traceCapacity) { - traceCapacity *= 2; - float[] newTraceX = new float[traceCapacity]; - System.arraycopy(mTraceX, 0, newTraceX, 0, mTraceCount); - mTraceX = newTraceX; - - float[] newTraceY = new float[traceCapacity]; - System.arraycopy(mTraceY, 0, newTraceY, 0, mTraceCount); - mTraceY = newTraceY; - - boolean[] newTraceCurrent = new boolean[traceCapacity]; - System.arraycopy(mTraceCurrent, 0, newTraceCurrent, 0, mTraceCount); - mTraceCurrent= newTraceCurrent; + public void addTrace(float x, float y, boolean isHistorical) { + if (Float.isNaN(mFirstX)) { + mFirstX = x; + } + if (Float.isNaN(mFirstY)) { + mFirstY = y; } - mTraceX[mTraceCount] = x; - mTraceY[mTraceCount] = y; - mTraceCurrent[mTraceCount] = current; - mTraceCount += 1; + mPreviousX = mCurrentX; + mPreviousY = mCurrentY; + mCurrentX = x; + mCurrentY = y; + mPreviousPointIsHistorical = mCurrentPointIsHistorical; + mCurrentPointIsHistorical = isHistorical; } } @@ -149,6 +146,12 @@ public class PointerLocationView extends View implements InputDeviceListener, private final SparseArray<PointerState> mPointers = new SparseArray<PointerState>(); private final PointerCoords mTempCoords = new PointerCoords(); + // Draw the trace of all pointers in the current gesture in a separate layer + // that is not cleared on every frame so that we don't have to re-draw the + // entire trace on each frame. + private final Bitmap mTraceBitmap; + private final Canvas mTraceCanvas; + private final Region mSystemGestureExclusion = new Region(); private final Region mSystemGestureExclusionRejected = new Region(); private final Path mSystemGestureExclusionPath = new Path(); @@ -197,6 +200,10 @@ public class PointerLocationView extends View implements InputDeviceListener, mPathPaint.setARGB(255, 0, 96, 255); mPathPaint.setStyle(Paint.Style.STROKE); + mTraceBitmap = Bitmap.createBitmap(getResources().getDisplayMetrics().widthPixels, + getResources().getDisplayMetrics().heightPixels, Bitmap.Config.ARGB_8888); + mTraceCanvas = new Canvas(mTraceBitmap); + configureDensityDependentFactors(); mSystemGestureExclusionPaint = new Paint(); @@ -256,7 +263,7 @@ public class PointerLocationView extends View implements InputDeviceListener, protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mTextPaint.getFontMetricsInt(mTextMetrics); - mHeaderBottom = mHeaderPaddingTop-mTextMetrics.ascent+mTextMetrics.descent+2; + mHeaderBottom = mHeaderPaddingTop - mTextMetrics.ascent + mTextMetrics.descent + 2; if (false) { Log.i("foo", "Metrics: ascent=" + mTextMetrics.ascent + " descent=" + mTextMetrics.descent @@ -269,6 +276,7 @@ public class PointerLocationView extends View implements InputDeviceListener, // Draw an oval. When angle is 0 radians, orients the major axis vertically, // angles less than or greater than 0 radians rotate the major axis left or right. private RectF mReusableOvalRect = new RectF(); + private void drawOval(Canvas canvas, float x, float y, float major, float minor, float angle, Paint paint) { canvas.save(Canvas.MATRIX_SAVE_FLAG); @@ -285,6 +293,8 @@ public class PointerLocationView extends View implements InputDeviceListener, protected void onDraw(Canvas canvas) { final int NP = mPointers.size(); + canvas.drawBitmap(mTraceBitmap, 0, 0, null); + if (!mSystemGestureExclusion.isEmpty()) { mSystemGestureExclusionPath.reset(); mSystemGestureExclusion.getBoundaryPath(mSystemGestureExclusionPath); @@ -303,32 +313,9 @@ public class PointerLocationView extends View implements InputDeviceListener, // Pointer trace. for (int p = 0; p < NP; p++) { final PointerState ps = mPointers.valueAt(p); + float lastX = ps.mCurrentX, lastY = ps.mCurrentY; - // Draw path. - final int N = ps.mTraceCount; - float lastX = 0, lastY = 0; - boolean haveLast = false; - boolean drawn = false; - mPaint.setARGB(255, 128, 255, 255); - for (int i=0; i < N; i++) { - float x = ps.mTraceX[i]; - float y = ps.mTraceY[i]; - if (Float.isNaN(x) || Float.isNaN(y)) { - haveLast = false; - continue; - } - if (haveLast) { - canvas.drawLine(lastX, lastY, x, y, mPathPaint); - final Paint paint = ps.mTraceCurrent[i - 1] ? mCurrentPointPaint : mPaint; - canvas.drawPoint(lastX, lastY, paint); - drawn = true; - } - lastX = x; - lastY = y; - haveLast = true; - } - - if (drawn) { + if (!Float.isNaN(lastX) && !Float.isNaN(lastY)) { // Draw velocity vector. mPaint.setARGB(255, 255, 64, 128); float xVel = ps.mXVelocity * (1000 / 60); @@ -353,7 +340,7 @@ public class PointerLocationView extends View implements InputDeviceListener, Math.max(getHeight(), getWidth()), mTargetPaint); // Draw current point. - int pressureLevel = (int)(ps.mCoords.pressure * 255); + int pressureLevel = (int) (ps.mCoords.pressure * 255); mPaint.setARGB(255, pressureLevel, 255, 255 - pressureLevel); canvas.drawPoint(ps.mCoords.x, ps.mCoords.y, mPaint); @@ -424,8 +411,7 @@ public class PointerLocationView extends View implements InputDeviceListener, .append(" / ").append(mMaxNumPointers) .toString(), 1, base, mTextPaint); - final int count = ps.mTraceCount; - if ((mCurDown && ps.mCurDown) || count == 0) { + if ((mCurDown && ps.mCurDown) || Float.isNaN(ps.mCurrentX)) { canvas.drawRect(itemW, mHeaderPaddingTop, (itemW * 2) - 1, bottom, mTextBackgroundPaint); canvas.drawText(mText.clear() @@ -437,8 +423,8 @@ public class PointerLocationView extends View implements InputDeviceListener, .append("Y: ").append(ps.mCoords.y, 1) .toString(), 1 + itemW * 2, base, mTextPaint); } else { - float dx = ps.mTraceX[count - 1] - ps.mTraceX[0]; - float dy = ps.mTraceY[count - 1] - ps.mTraceY[0]; + float dx = ps.mCurrentX - ps.mFirstX; + float dy = ps.mCurrentY - ps.mFirstY; canvas.drawRect(itemW, mHeaderPaddingTop, (itemW * 2) - 1, bottom, Math.abs(dx) < mVC.getScaledTouchSlop() ? mTextBackgroundPaint : mTextLevelPaint); @@ -565,9 +551,9 @@ public class PointerLocationView extends View implements InputDeviceListener, .append(" TouchMinor=").append(coords.touchMinor, 3) .append(" ToolMajor=").append(coords.toolMajor, 3) .append(" ToolMinor=").append(coords.toolMinor, 3) - .append(" Orientation=").append((float)(coords.orientation * 180 / Math.PI), 1) + .append(" Orientation=").append((float) (coords.orientation * 180 / Math.PI), 1) .append("deg") - .append(" Tilt=").append((float)( + .append(" Tilt=").append((float) ( coords.getAxisValue(MotionEvent.AXIS_TILT) * 180 / Math.PI), 1) .append("deg") .append(" Distance=").append(coords.getAxisValue(MotionEvent.AXIS_DISTANCE), 1) @@ -598,6 +584,7 @@ public class PointerLocationView extends View implements InputDeviceListener, mCurNumPointers = 0; mMaxNumPointers = 0; mVelocity.clear(); + mTraceCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); if (mAltVelocity != null) { mAltVelocity.clear(); } @@ -646,7 +633,8 @@ public class PointerLocationView extends View implements InputDeviceListener, logCoords("Pointer", action, i, coords, id, event); } if (ps != null) { - ps.addTrace(coords.x, coords.y, false); + ps.addTrace(coords.x, coords.y, true); + updateDrawTrace(ps); } } } @@ -659,7 +647,8 @@ public class PointerLocationView extends View implements InputDeviceListener, logCoords("Pointer", action, i, coords, id, event); } if (ps != null) { - ps.addTrace(coords.x, coords.y, true); + ps.addTrace(coords.x, coords.y, false); + updateDrawTrace(ps); ps.mXVelocity = mVelocity.getXVelocity(id); ps.mYVelocity = mVelocity.getYVelocity(id); if (mAltVelocity != null) { @@ -702,13 +691,26 @@ public class PointerLocationView extends View implements InputDeviceListener, if (mActivePointerId == id) { mActivePointerId = event.getPointerId(index == 0 ? 1 : 0); } - ps.addTrace(Float.NaN, Float.NaN, false); + ps.addTrace(Float.NaN, Float.NaN, true); } } invalidate(); } + private void updateDrawTrace(PointerState ps) { + mPaint.setARGB(255, 128, 255, 255); + float x = ps.mCurrentX; + float y = ps.mCurrentY; + float lastX = ps.mPreviousX; + float lastY = ps.mPreviousY; + if (!Float.isNaN(x) && !Float.isNaN(y) && !Float.isNaN(lastX) && !Float.isNaN(lastY)) { + mTraceCanvas.drawLine(lastX, lastY, x, y, mPathPaint); + Paint paint = ps.mPreviousPointIsHistorical ? mPaint : mCurrentPointPaint; + mTraceCanvas.drawPoint(lastX, lastY, paint); + } + } + @Override public boolean onTouchEvent(MotionEvent event) { onPointerEvent(event); @@ -767,7 +769,7 @@ public class PointerLocationView extends View implements InputDeviceListener, return true; default: return KeyEvent.isGamepadButton(keyCode) - || KeyEvent.isModifierKey(keyCode); + || KeyEvent.isModifierKey(keyCode); } } @@ -887,7 +889,7 @@ public class PointerLocationView extends View implements InputDeviceListener, public FasterStringBuilder append(int value, int zeroPadWidth) { final boolean negative = value < 0; if (negative) { - value = - value; + value = -value; if (value < 0) { append("-2147483648"); return this; @@ -973,26 +975,27 @@ public class PointerLocationView extends View implements InputDeviceListener, private ISystemGestureExclusionListener mSystemGestureExclusionListener = new ISystemGestureExclusionListener.Stub() { - @Override - public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion, - Region systemGestureExclusionUnrestricted) { - Region exclusion = Region.obtain(systemGestureExclusion); - Region rejected = Region.obtain(); - if (systemGestureExclusionUnrestricted != null) { - rejected.set(systemGestureExclusionUnrestricted); - rejected.op(exclusion, Region.Op.DIFFERENCE); - } - Handler handler = getHandler(); - if (handler != null) { - handler.post(() -> { - mSystemGestureExclusion.set(exclusion); - mSystemGestureExclusionRejected.set(rejected); - exclusion.recycle(); - invalidate(); - }); - } - } - }; + @Override + public void onSystemGestureExclusionChanged(int displayId, + Region systemGestureExclusion, + Region systemGestureExclusionUnrestricted) { + Region exclusion = Region.obtain(systemGestureExclusion); + Region rejected = Region.obtain(); + if (systemGestureExclusionUnrestricted != null) { + rejected.set(systemGestureExclusionUnrestricted); + rejected.op(exclusion, Region.Op.DIFFERENCE); + } + Handler handler = getHandler(); + if (handler != null) { + handler.post(() -> { + mSystemGestureExclusion.set(exclusion); + mSystemGestureExclusionRejected.set(rejected); + exclusion.recycle(); + invalidate(); + }); + } + } + }; @Override protected void onConfigurationChanged(Configuration newConfig) { diff --git a/core/proto/android/app/appstartinfo.proto b/core/proto/android/app/appstartinfo.proto index 78cf6f464558..8e9f4478e894 100644 --- a/core/proto/android/app/appstartinfo.proto +++ b/core/proto/android/app/appstartinfo.proto @@ -41,4 +41,5 @@ message ApplicationStartInfoProto { optional AppStartLaunchMode launch_mode = 11; optional bool was_force_stopped = 12; optional int64 monotonic_creation_time_ms = 13; + optional int32 start_component = 14; } diff --git a/core/proto/android/service/graphicsstats.proto b/core/proto/android/service/graphicsstats.proto index bb654f05b02d..d8365631c270 100644 --- a/core/proto/android/service/graphicsstats.proto +++ b/core/proto/android/service/graphicsstats.proto @@ -62,6 +62,9 @@ message GraphicsStatsProto { // 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/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index d0f1615e78e9..a9626a650cf9 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -2153,7 +2153,7 @@ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Deaktiver"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Få flere oplysninger"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Tilpassede Android-notifikationer blev erstattet af forbedrede notifikationer i Android 12. Denne funktion viser foreslåede handlinger og svar samt organiserer dine notifikationer.\n\nForbedrede notifikationer kan få adgang til indhold i notifikationer, bl.a. personlige oplysninger såsom beskeder og navne på kontakter. Funktionen kan også afvise eller svare på notifikationer, f.eks. ved at besvare telefonopkald og justere Forstyr ikke."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Adaptive Android-notifikationer blev erstattet af forbedrede notifikationer i Android 12. Denne funktion viser foreslåede handlinger og svar samt organiserer dine notifikationer.\n\nForbedrede notifikationer kan få adgang til indhold i notifikationer, bl.a. personlige oplysninger såsom beskeder og navne på kontakter. Funktionen kan også afvise eller svare på notifikationer, f.eks. ved at besvare telefonopkald og justere Forstyr ikke."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notifikation med oplysninger om rutinetilstand"</string> <string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Batterisparefunktion er aktiveret"</string> <string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Reducerer batteriforbruget for at forlænge batteritiden"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 14b512eb6d31..f40fb93ca6a9 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -642,7 +642,7 @@ <string name="permdesc_mediaLocation" msgid="597912899423578138">"એપને તમારા મીડિયા સંગ્રહમાંથી સ્થાનો વાંચવાની મંજૂરી આપે છે."</string> <string name="biometric_app_setting_name" msgid="3339209978734534457">"બાયોમેટ્રિક્સનો ઉપયોગ કરો"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"બાયોમેટ્રિક્સ અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો"</string> - <string name="biometric_dialog_default_title" msgid="55026799173208210">"તે તમે જ છો એ ચકાસો"</string> + <string name="biometric_dialog_default_title" msgid="55026799173208210">"આ તમે જ છો તેની ચકાસણી કરો"</string> <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"આગળ વધવા માટે બાયોમેટ્રિકનો ઉપયોગ કરો"</string> <string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"ચાલુ રાખવા માટે તમારા બાયોમેટ્રિક ડેટા અથવા સ્ક્રીન લૉક સુવિધાનો ઉપયોગ કરો"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"બાયોમેટ્રિક હાર્ડવેર ઉપલબ્ધ નથી"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 0997b4b972de..595b9baaa254 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -642,7 +642,7 @@ <string name="permdesc_mediaLocation" msgid="597912899423578138">"Қолданбаға медиамазмұн жинағынан геодеректерді оқуға мүмкіндік береді."</string> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Биометриканы пайдалану"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Биометриканы немесе экран құлпын пайдалану"</string> - <string name="biometric_dialog_default_title" msgid="55026799173208210">"Бұл сіз екеніңізді растаңыз"</string> + <string name="biometric_dialog_default_title" msgid="55026799173208210">"Cіз екеніңізді растаңыз"</string> <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Жалғастыру үшін биометрикаңызды пайдаланыңыз."</string> <string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Жалғастыру үшін биометриканы немесе экран құлпын пайдаланыңыз."</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрикалық жабдық жоқ"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index c671f461b7de..61d322951879 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -644,7 +644,7 @@ <string name="permdesc_mediaLocation" msgid="597912899423578138">"Umožňuje aplikácii čítať polohy zo zbierky médií."</string> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Použiť biometrické údaje"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Použiť biometrické údaje alebo zámku obrazovky"</string> - <string name="biometric_dialog_default_title" msgid="55026799173208210">"Overenie, že ste to vy"</string> + <string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrďte, že ste to vy"</string> <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Ak chcete pokračovať, použite biometrický údaj"</string> <string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Pokračujte použitím biometrických údajov alebo zámky obrazovky"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrický hardvér nie je k dispozícii"</string> @@ -2410,9 +2410,9 @@ <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Rozloženie klávesnice je nastavené na jazyky <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g> a <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Môžete to zmeniť klepnutím."</string> <string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fyzické klávesnice sú nakonfigurované"</string> <string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Klávesnice si zobrazíte klepnutím"</string> - <string name="profile_label_private" msgid="6463418670715290696">"Súkromné"</string> + <string name="profile_label_private" msgid="6463418670715290696">"Súkromný"</string> <string name="profile_label_clone" msgid="769106052210954285">"Klon"</string> - <string name="profile_label_work" msgid="3495359133038584618">"Pracovné"</string> + <string name="profile_label_work" msgid="3495359133038584618">"Pracovný"</string> <string name="profile_label_work_2" msgid="4691533661598632135">"2. pracovný"</string> <string name="profile_label_work_3" msgid="4834572253956798917">"3. pracovný"</string> <string name="profile_label_test" msgid="9168641926186071947">"Testovací"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 1f8a2f7dfcc9..70732664c973 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -642,7 +642,7 @@ <string name="permdesc_mediaLocation" msgid="597912899423578138">"మీ మీడియా సేకరణ నుండి లొకేషన్లను చదవడానికి యాప్ను అనుమతిస్తుంది."</string> <string name="biometric_app_setting_name" msgid="3339209978734534457">"బయోమెట్రిక్స్ను ఉపయోగించండి"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"బయోమెట్రిక్స్ను లేదా స్క్రీన్ లాక్ను ఉపయోగించండి"</string> - <string name="biometric_dialog_default_title" msgid="55026799173208210">"ఇది మీరేనని వెరిఫై చేసుకోండి"</string> + <string name="biometric_dialog_default_title" msgid="55026799173208210">"ఈ చర్య చేస్తోంది మీరేనని వెరిఫై చేయండి"</string> <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"కొనసాగించడానికి, మీ బయోమెట్రిక్ను ఉపయోగించండి"</string> <string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"కొనసాగించడానికి మీ బయోమెట్రిక్ లేదా స్క్రీన్ లాక్ను ఉపయోగించండి"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"బయోమెట్రిక్ హార్డ్వేర్ అందుబాటులో లేదు"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index a4d27527d480..e76dacdf0191 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -2439,7 +2439,7 @@ <string name="face_dangling_notification_msg" msgid="746235263598985384">"Hindi na makilala ang iyong face model. I-set up ulit ang Pag-unlock Gamit ang Mukha."</string> <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"I-set up"</string> <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Huwag muna"</string> - <string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm para kay/sa <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"Alarm para kay <xliff:g id="USER_NAME">%s</xliff:g>"</string> <string name="bg_user_sound_notification_button_switch_user" msgid="3091969648572788946">"Magpalit ng user"</string> <string name="bg_user_sound_notification_button_mute" msgid="4942158515665615243">"I-mute"</string> <string name="bg_user_sound_notification_message" msgid="8613881975316976673">"I-tap para i-mute ang tunog"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index f467f9264073..ad6fc0de5cd5 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -642,7 +642,7 @@ <string name="permdesc_mediaLocation" msgid="597912899423578138">"Uygulamanın medya koleksiyonunuzdaki konumları okumasına izin verir."</string> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biyometri kullan"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biyometri veya ekran kilidi kullan"</string> - <string name="biometric_dialog_default_title" msgid="55026799173208210">"Siz olduğunuzu doğrulayın"</string> + <string name="biometric_dialog_default_title" msgid="55026799173208210">"Kimliğinizi doğrulayın"</string> <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Devam etmek için biyometri kullanın"</string> <string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Devam etmek için biyometrik kimlik bilginizi veya ekran kilidinizi kullanın"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biyometrik donanım kullanılamıyor"</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 660068d969ec..52d9e3bbc5cc 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -2439,7 +2439,7 @@ <string name="face_dangling_notification_msg" msgid="746235263598985384">"آپ کے چہرے کا ماڈل مزید پہچانا نہیں جا سکتا۔ فیس اَن لاک کو دوبارہ سیٹ اپ کریں۔"</string> <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"سیٹ اپ کریں"</string> <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ابھی نہیں"</string> - <string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> کیلئے الارم"</string> + <string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> کیلئے الارم"</string> <string name="bg_user_sound_notification_button_switch_user" msgid="3091969648572788946">"صارف سوئچ کریں"</string> <string name="bg_user_sound_notification_button_mute" msgid="4942158515665615243">"خاموش کریں"</string> <string name="bg_user_sound_notification_message" msgid="8613881975316976673">"آواز کو خاموش کرنے کے لیے تھپتھپائیں"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 421b7d2c041d..07efad89010a 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4380,7 +4380,7 @@ modes dimensions {@link config_minPercentageMultiWindowSupportWidth} the device supports to determine if the activity can be shown in multi windowing modes. --> - <integer name="config_respectsActivityMinWidthHeightMultiWindow">0</integer> + <integer name="config_respectsActivityMinWidthHeightMultiWindow">-1</integer> <!-- This value is only used when the device checks activity min height to determine if it can be shown in multi windowing modes. @@ -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/config_telephony.xml b/core/res/res/values/config_telephony.xml index 69437b44fd6e..9854030ed0d1 100644 --- a/core/res/res/values/config_telephony.xml +++ b/core/res/res/values/config_telephony.xml @@ -287,6 +287,11 @@ <string name="config_satellite_demo_mode_sos_intent_action" translatable="false"></string> <java-symbol type="string" name="config_satellite_demo_mode_sos_intent_action" /> + <!-- The action of the intent that hidden menu sends to the app to launch esp loopback test mode + for sos emergency messaging via satellite. --> + <string name="config_satellite_test_with_esp_replies_intent_action" translatable="false"></string> + <java-symbol type="string" name="config_satellite_test_with_esp_replies_intent_action" /> + <!-- Whether outgoing satellite datagrams should be sent to modem in demo mode. When satellite is enabled for demo mode, if this config is enabled, outgoing datagrams will be sent to modem; otherwise, success results will be returned. If demo mode is disabled, outgoing diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 039665982482..06b36b8f74af 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/Android.bp b/core/tests/coretests/Android.bp index d98836f8ce20..e9ce71230a82 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -104,6 +104,7 @@ android_test { "mockito-target-extended-minus-junit4", "TestParameterInjector", "android.content.res.flags-aconfig-java", + "android.security.flags-aconfig-java", ], libs: [ diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java index 0837b458c3ba..0f73df92ca93 100644 --- a/core/tests/coretests/src/android/app/NotificationTest.java +++ b/core/tests/coretests/src/android/app/NotificationTest.java @@ -37,6 +37,7 @@ import static android.app.Notification.EXTRA_PICTURE; import static android.app.Notification.EXTRA_PICTURE_ICON; import static android.app.Notification.EXTRA_SUMMARY_TEXT; import static android.app.Notification.EXTRA_TITLE; +import static android.app.Notification.FLAG_CAN_COLORIZE; import static android.app.Notification.GROUP_ALERT_CHILDREN; import static android.app.Notification.GROUP_ALERT_SUMMARY; import static android.app.Notification.GROUP_KEY_SILENT; @@ -96,6 +97,7 @@ import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; import android.text.style.TextAppearanceSpan; import android.util.Pair; +import android.util.Slog; import android.widget.RemoteViews; import androidx.test.InstrumentationRegistry; @@ -126,6 +128,8 @@ public class NotificationTest { private Context mContext; + private RemoteViews mRemoteViews; + @Rule public TestRule compatChangeRule = new PlatformCompatChangeRule(); @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -133,23 +137,25 @@ public class NotificationTest { @Before public void setUp() { mContext = InstrumentationRegistry.getContext(); + mRemoteViews = new RemoteViews( + mContext.getPackageName(), R.layout.notification_template_header); } @Test public void testColorizedByPermission() { Notification n = new Notification.Builder(mContext, "test") - .setFlag(Notification.FLAG_CAN_COLORIZE, true) + .setFlag(FLAG_CAN_COLORIZE, true) .setColorized(true).setColor(Color.WHITE) .build(); assertTrue(n.isColorized()); n = new Notification.Builder(mContext, "test") - .setFlag(Notification.FLAG_CAN_COLORIZE, true) + .setFlag(FLAG_CAN_COLORIZE, true) .build(); assertFalse(n.isColorized()); n = new Notification.Builder(mContext, "test") - .setFlag(Notification.FLAG_CAN_COLORIZE, false) + .setFlag(FLAG_CAN_COLORIZE, false) .setColorized(true).setColor(Color.WHITE) .build(); assertFalse(n.isColorized()); @@ -215,6 +221,275 @@ public class NotificationTest { } @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testHasTitle_noStyle() { + Notification n = new Notification.Builder(mContext, "test") + .setContentTitle("TITLE") + .build(); + assertThat(n.hasTitle()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testHasTitle_bigText() { + Notification n = new Notification.Builder(mContext, "test") + .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) + .build(); + assertThat(n.hasTitle()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testHasTitle_noTitle() { + Notification n = new Notification.Builder(mContext, "test") + .setContentText("text not title") + .build(); + assertThat(n.hasTitle()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testContainsCustomViews_none() { + Notification np = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setContentText("test") + .build(); + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setContentText("test") + .setPublicVersion(np) + .build(); + assertThat(n.containsCustomViews()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testContainsCustomViews_content() { + Notification np = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setContentText("test") + .build(); + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setContentText("test") + .setCustomContentView(mRemoteViews) + .setPublicVersion(np) + .build(); + assertThat(n.containsCustomViews()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testContainsCustomViews_big() { + Notification np = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setContentText("test") + .build(); + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setContentText("test") + .setCustomBigContentView(mRemoteViews) + .setPublicVersion(np) + .build(); + assertThat(n.containsCustomViews()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testContainsCustomViews_headsUp() { + Notification np = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setContentText("test") + .build(); + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setContentText("test") + .setCustomHeadsUpContentView(mRemoteViews) + .setPublicVersion(np) + .build(); + assertThat(n.containsCustomViews()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testContainsCustomViews_content_public() { + Notification np = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setContentText("public") + .setCustomContentView(mRemoteViews) + .build(); + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setContentText("test") + .setPublicVersion(np) + .build(); + assertThat(n.containsCustomViews()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testContainsCustomViews_big_public() { + Notification np = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setContentText("test") + .setCustomBigContentView(mRemoteViews) + .build(); + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setContentText("test") + .setPublicVersion(np) + .build(); + assertThat(n.containsCustomViews()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testContainsCustomViews_headsUp_public() { + Notification np = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setContentText("test") + .setCustomHeadsUpContentView(mRemoteViews) + .build(); + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setContentText("test") + .setPublicVersion(np) + .build(); + assertThat(n.containsCustomViews()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testHasPromotableStyle_noStyle() { + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setContentText("test") + .build(); + assertThat(n.hasPromotableStyle()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testHasPromotableStyle_bigPicture() { + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.BigPictureStyle()) + .build(); + assertThat(n.hasPromotableStyle()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testHasPromotableStyle_bigText() { + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.BigTextStyle()) + .build(); + assertThat(n.hasPromotableStyle()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testHasPromotableStyle_no_messagingStyle() { + Notification.MessagingStyle style = new Notification.MessagingStyle("self name") + .setGroupConversation(true) + .setConversationTitle("test conversation title"); + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(style) + .build(); + assertThat(n.hasPromotableStyle()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testHasPromotableStyle_no_mediaStyle() { + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.MediaStyle()) + .build(); + assertThat(n.hasPromotableStyle()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testHasPromotableStyle_no_inboxStyle() { + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.InboxStyle()) + .build(); + assertThat(n.hasPromotableStyle()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testHasPromotableStyle_callText() { + PendingIntent answerIntent = createPendingIntent("answer"); + PendingIntent declineIntent = createPendingIntent("decline"); + Notification.CallStyle style = Notification.CallStyle.forIncomingCall( + new Person.Builder().setName("A Caller").build(), + declineIntent, + answerIntent + ); + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(style) + .build(); + assertThat(n.hasPromotableStyle()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testHasPromotableCharacteristics() { + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) + .setColor(Color.WHITE) + .setColorized(true) + .setFlag(FLAG_CAN_COLORIZE, true) + .build(); + assertThat(n.hasPromotableCharacteristics()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testHasPromotableCharacteristics_wrongStyle() { + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.InboxStyle()) + .setContentTitle("TITLE") + .setColor(Color.WHITE) + .setColorized(true) + .setFlag(FLAG_CAN_COLORIZE, true) + .build(); + assertThat(n.hasPromotableCharacteristics()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testHasPromotableCharacteristics_notColorized() { + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) + .setColor(Color.WHITE) + .build(); + assertThat(n.hasPromotableCharacteristics()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testHasPromotableCharacteristics_noTitle() { + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.BigTextStyle()) + .setColor(Color.WHITE) + .setColorized(true) + .setFlag(FLAG_CAN_COLORIZE, true) + .build(); + assertThat(n.hasPromotableCharacteristics()).isFalse(); + } + + @Test @EnableFlags(Flags.FLAG_API_RICH_ONGOING) public void testGetShortCriticalText_noneSet() { Notification n = new Notification.Builder(mContext, "test") diff --git a/core/tests/coretests/src/android/content/IntentTest.java b/core/tests/coretests/src/android/content/IntentTest.java new file mode 100644 index 000000000000..d169ce3c07d0 --- /dev/null +++ b/core/tests/coretests/src/android/content/IntentTest.java @@ -0,0 +1,99 @@ +/* + * 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.content; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertEquals; + +import android.net.Uri; +import android.os.Binder; +import android.os.IBinder; +import android.os.Parcel; +import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.security.Flags; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Build/Install/Run: + * atest FrameworksCoreTests:IntentTest + */ +@Presubmit +@SmallTest +@RunWith(AndroidJUnit4.class) +public class IntentTest { + private static final String TEST_ACTION = "android.content.IntentTest_test"; + private static final String TEST_EXTRA_NAME = "testExtraName"; + private static final Uri TEST_URI = Uri.parse("content://com.example/people"); + + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + + @Test + @RequiresFlagsEnabled(Flags.FLAG_PREVENT_INTENT_REDIRECT) + public void testReadFromParcelWithExtraIntentKeys() { + Intent intent = new Intent("TEST_ACTION"); + intent.putExtra(TEST_EXTRA_NAME, new Intent(TEST_ACTION)); + intent.putExtra(TEST_EXTRA_NAME + "2", 1); + + intent.collectExtraIntentKeys(); + final Parcel parcel = Parcel.obtain(); + intent.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + final Intent target = new Intent(); + target.readFromParcel(parcel); + + assertEquals(intent.getAction(), target.getAction()); + assertEquals(intent.getExtraIntentKeys(), target.getExtraIntentKeys()); + assertThat(intent.getExtraIntentKeys()).hasSize(1); + } + + @Test + public void testCreatorTokenInfo() { + Intent intent = new Intent(TEST_ACTION); + IBinder creatorToken = new Binder(); + + intent.setCreatorToken(creatorToken); + assertThat(intent.getCreatorToken()).isEqualTo(creatorToken); + + intent.removeCreatorTokenInfo(); + assertThat(intent.getCreatorToken()).isNull(); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_PREVENT_INTENT_REDIRECT) + public void testCollectExtraIntentKeys() { + Intent intent = new Intent(TEST_ACTION); + Intent extraIntent = new Intent(TEST_ACTION, TEST_URI); + intent.putExtra(TEST_EXTRA_NAME, extraIntent); + + intent.collectExtraIntentKeys(); + + assertThat(intent.getExtraIntentKeys()).hasSize(1); + assertThat(intent.getExtraIntentKeys()).contains(TEST_EXTRA_NAME); + } + +} diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java index 786f1e84728d..ba6f62c6ed19 100644 --- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java +++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java @@ -38,7 +38,6 @@ import android.graphics.Rect; import android.graphics.RectF; import android.platform.test.annotations.Presubmit; import android.util.SparseArray; -import android.view.SurfaceControl.Transaction; import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; @@ -79,7 +78,6 @@ public class InsetsAnimationControlImplTest { private SurfaceControl mNavLeash; private InsetsState mInsetsState; - @Mock Transaction mMockTransaction; @Mock InsetsController mMockController; @Mock WindowInsetsAnimationControlListener mMockListener; @@ -98,16 +96,14 @@ public class InsetsAnimationControlImplTest { mInsetsState.getOrCreateSource(ID_NAVIGATION_BAR, navigationBars()) .setFrame(new Rect(400, 0, 500, 500)); InsetsSourceConsumer topConsumer = new InsetsSourceConsumer(ID_STATUS_BAR, - WindowInsets.Type.statusBars(), mInsetsState, - () -> mMockTransaction, mMockController); + WindowInsets.Type.statusBars(), mInsetsState, mMockController); topConsumer.setControl( new InsetsSourceControl(ID_STATUS_BAR, WindowInsets.Type.statusBars(), mStatusLeash, true, new Point(0, 0), Insets.of(0, 100, 0, 0)), new int[1], new int[1]); InsetsSourceConsumer navConsumer = new InsetsSourceConsumer(ID_NAVIGATION_BAR, - WindowInsets.Type.navigationBars(), mInsetsState, - () -> mMockTransaction, mMockController); + WindowInsets.Type.navigationBars(), mInsetsState, mMockController); navConsumer.setControl( new InsetsSourceControl(ID_NAVIGATION_BAR, WindowInsets.Type.navigationBars(), mNavLeash, true, new Point(400, 0), Insets.of(0, 0, 100, 0)), @@ -131,8 +127,9 @@ public class InsetsAnimationControlImplTest { mController = new InsetsAnimationControlImpl(controls, new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(), - mMockController, spec /* insetsAnimationSpecCreator */, 0 /* animationType */, - 0 /* layoutInsetsDuringAnimation */, null /* translator */, null /* statsToken */); + mMockController, mMockController, spec /* insetsAnimationSpecCreator */, + 0 /* animationType */, 0 /* layoutInsetsDuringAnimation */, null /* translator */, + null /* statsToken */); mController.setReadyDispatched(true); } diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index bec8b1f76394..4516e9ce72fc 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -63,7 +63,6 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.CancellationSignal; import android.platform.test.annotations.Presubmit; -import android.view.SurfaceControl.Transaction; import android.view.WindowInsets.Type.InsetsType; import android.view.WindowInsetsController.OnControllableInsetsChangedListener; import android.view.WindowManager.BadTokenException; @@ -138,8 +137,7 @@ public class InsetsControllerTest { mTestHost = spy(new TestHost(mViewRoot)); mController = new InsetsController(mTestHost, (controller, id, type) -> { if (!Flags.refactorInsetsController() && type == ime()) { - return new InsetsSourceConsumer(id, type, controller.getState(), - Transaction::new, controller) { + return new InsetsSourceConsumer(id, type, controller.getState(), controller) { private boolean mImeRequestedShow; @@ -155,8 +153,7 @@ public class InsetsControllerTest { } }; } else { - return new InsetsSourceConsumer(id, type, controller.getState(), - Transaction::new, controller); + return new InsetsSourceConsumer(id, type, controller.getState(), controller); } }, mTestHandler); final Rect rect = new Rect(5, 5, 5, 5); diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java index 655cb4519d3c..d6d45e839f2f 100644 --- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java +++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java @@ -28,10 +28,7 @@ import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertTrue; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; import android.app.Instrumentation; import android.content.Context; @@ -39,7 +36,6 @@ import android.graphics.Insets; import android.graphics.Point; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; -import android.view.SurfaceControl.Transaction; import android.view.WindowManager.BadTokenException; import android.view.WindowManager.LayoutParams; import android.view.inputmethod.ImeTracker; @@ -51,7 +47,6 @@ import androidx.test.platform.app.InstrumentationRegistry; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -75,9 +70,9 @@ public class InsetsSourceConsumerTest { private SurfaceSession mSession = new SurfaceSession(); private SurfaceControl mLeash; - @Mock Transaction mMockTransaction; private InsetsSource mSpyInsetsSource; private boolean mRemoveSurfaceCalled = false; + private boolean mSurfaceParamsApplied = false; private InsetsController mController; private InsetsState mState; private ViewRootImpl mViewRoot; @@ -102,9 +97,14 @@ public class InsetsSourceConsumerTest { mSpyInsetsSource = Mockito.spy(new InsetsSource(ID_STATUS_BAR, statusBars())); mState.addSource(mSpyInsetsSource); - mController = new InsetsController(new ViewRootInsetsControllerHost(mViewRoot)); - mConsumer = new InsetsSourceConsumer(ID_STATUS_BAR, statusBars(), mState, - () -> mMockTransaction, mController) { + mController = new InsetsController(new ViewRootInsetsControllerHost(mViewRoot)) { + @Override + public void applySurfaceParams( + final SyncRtSurfaceTransactionApplier.SurfaceParams... params) { + mSurfaceParamsApplied = true; + } + }; + mConsumer = new InsetsSourceConsumer(ID_STATUS_BAR, statusBars(), mState, mController) { @Override public void removeSurface() { super.removeSurface(); @@ -148,8 +148,7 @@ public class InsetsSourceConsumerTest { InsetsState state = new InsetsState(); InsetsController controller = new InsetsController(new ViewRootInsetsControllerHost( mViewRoot)); - InsetsSourceConsumer consumer = new InsetsSourceConsumer( - ID_IME, ime(), state, null, controller); + InsetsSourceConsumer consumer = new InsetsSourceConsumer(ID_IME, ime(), state, controller); InsetsSource source = new InsetsSource(ID_IME, ime()); source.setFrame(0, 1, 2, 3); @@ -182,9 +181,9 @@ public class InsetsSourceConsumerTest { public void testRestore() { InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { mConsumer.setControl(null, new int[1], new int[1]); - reset(mMockTransaction); + mSurfaceParamsApplied = false; mController.setRequestedVisibleTypes(0 /* visibleTypes */, statusBars()); - verifyZeroInteractions(mMockTransaction); + assertFalse(mSurfaceParamsApplied); int[] hideTypes = new int[1]; mConsumer.setControl( new InsetsSourceControl(ID_STATUS_BAR, statusBars(), mLeash, @@ -200,8 +199,9 @@ public class InsetsSourceConsumerTest { InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { mController.setRequestedVisibleTypes(0 /* visibleTypes */, statusBars()); mConsumer.setControl(null, new int[1], new int[1]); - reset(mMockTransaction); - verifyZeroInteractions(mMockTransaction); + mLeash = new SurfaceControl.Builder(mSession) + .setName("testSurface") + .build(); mRemoveSurfaceCalled = false; int[] hideTypes = new int[1]; mConsumer.setControl( @@ -221,8 +221,7 @@ public class InsetsSourceConsumerTest { ViewRootInsetsControllerHost host = new ViewRootInsetsControllerHost(mViewRoot); InsetsController insetsController = new InsetsController(host, (ic, id, type) -> { if (type == ime()) { - return new InsetsSourceConsumer(ID_IME, ime(), state, - () -> mMockTransaction, ic) { + return new InsetsSourceConsumer(ID_IME, ime(), state, ic) { @Override public int requestShow(boolean fromController, ImeTracker.Token statsToken) { @@ -230,14 +229,14 @@ public class InsetsSourceConsumerTest { } }; } - return new InsetsSourceConsumer(id, type, ic.getState(), Transaction::new, ic); + return new InsetsSourceConsumer(id, type, ic.getState(), ic); }, host.getHandler()); InsetsSourceConsumer imeConsumer = insetsController.getSourceConsumer(ID_IME, ime()); // Initial IME insets source control with its leash. imeConsumer.setControl(new InsetsSourceControl(ID_IME, ime(), mLeash, false /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1]); - reset(mMockTransaction); + mSurfaceParamsApplied = false; // Verify when the app requests controlling show IME animation, the IME leash // visibility won't be updated when the consumer received the same leash in setControl. @@ -246,7 +245,7 @@ public class InsetsSourceConsumerTest { assertEquals(ANIMATION_TYPE_USER, insetsController.getAnimationType(ime())); imeConsumer.setControl(new InsetsSourceControl(ID_IME, ime(), mLeash, true /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1]); - verify(mMockTransaction, never()).show(mLeash); + assertFalse(mSurfaceParamsApplied); }); } } diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java index e240a0853f46..632721126714 100644 --- a/core/tests/coretests/src/android/view/ViewRootImplTest.java +++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java @@ -71,7 +71,6 @@ import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; import android.os.Binder; import android.os.SystemProperties; -import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; @@ -1599,7 +1598,6 @@ public class ViewRootImplTest { nativeCreateASurfaceControlFromSurface(mViewRootImpl.mSurface)); } - @EnableFlags(Flags.FLAG_INSETS_CONTROL_SEQ) @Test public void testHandleInsetsControlChanged() { mView = new View(sContext); diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java index 46dfcb5247fb..25f458e60852 100644 --- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java +++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java @@ -103,15 +103,7 @@ public class WindowOnBackInvokedDispatcherTest { private int mCallbackInfoCalls = 0; - private final BackMotionEvent mBackEvent = new BackMotionEvent( - /* touchX = */ 0, - /* touchY = */ 0, - /* progress = */ 0, - /* velocityX = */ 0, - /* velocityY = */ 0, - /* triggerBack = */ false, - /* swipeEdge = */ BackEvent.EDGE_LEFT, - /* departingAnimationTarget = */ null); + private final BackMotionEvent mBackEvent = backMotionEventFrom(/* progress */ 0f); private final MotionEvent mMotionEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 100, 100, 0); @@ -558,6 +550,7 @@ public class WindowOnBackInvokedDispatcherTest { OnBackInvokedCallbackInfo callbackInfo = assertSetCallbackInfo(); callbackInfo.getCallback().onBackStarted(mBackEvent); + callbackInfo.getCallback().onBackProgressed(backMotionEventFrom(/* progress */ 0.5f)); waitForIdle(); assertTrue(mDispatcher.mProgressAnimator.isBackAnimationInProgress()); @@ -575,6 +568,18 @@ public class WindowOnBackInvokedDispatcherTest { assertFalse(mDispatcher.mProgressAnimator.isBackAnimationInProgress()); } + private BackMotionEvent backMotionEventFrom(float progress) { + return new BackMotionEvent( + /* touchX = */ 0, + /* touchY = */ 0, + /* progress = */ progress, + /* velocityX = */ 0, + /* velocityY = */ 0, + /* triggerBack = */ false, + /* swipeEdge = */ BackEvent.EDGE_LEFT, + /* departingAnimationTarget = */ null); + } + private void verifyImeCallackRegistrations() throws RemoteException { // verify default callback is replaced with ImeBackAnimationController mDispatcher.registerOnBackInvokedCallbackUnchecked(mDefaultImeCallback, PRIORITY_DEFAULT); diff --git a/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java b/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java index 58834e6a4925..a311d0d81010 100644 --- a/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java +++ b/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java @@ -23,7 +23,7 @@ import static android.window.flags.DesktopModeFlags.ToggleOverride.OVERRIDE_UNSE 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; @@ -198,145 +198,145 @@ public class DesktopModeFlagsTest { @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 isTrue_dwFlagOn_overrideUnset_featureFlagOn_returnsTrue() { setOverride(OVERRIDE_UNSET_SETTING); // For unset overrides, follow flag - assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()).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) + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS) public void isTrue_dwFlagOn_overrideUnset_featureFlagOff_returnsFalse() { setOverride(OVERRIDE_UNSET_SETTING); // For unset overrides, follow flag - assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()).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 isTrue_dwFlagOn_overrideOn_featureFlagOn_returnsTrue() { setOverride(OVERRIDE_ON_SETTING); // When toggle override matches its default state (dw flag), don't override flags - assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()).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) + @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.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()).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 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.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()).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) + @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.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()).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 isTrue_dwFlagOff_overrideUnset_featureFlagOn_returnsTrue() { setOverride(OVERRIDE_UNSET_SETTING); // For unset overrides, follow flag - assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()).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 isTrue_dwFlagOff_overrideUnset_featureFlagOff_returnsFalse() { setOverride(OVERRIDE_UNSET_SETTING); // For unset overrides, follow flag - assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()).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 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.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()).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 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.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()).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 isTrue_dwFlagOff_overrideOff_featureFlagOn_returnsTrue() { setOverride(OVERRIDE_OFF_SETTING); // When toggle override matches its default state (dw flag), don't override flags - assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()).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 isTrue_dwFlagOff_overrideOff_featureFlagOff_returnsFalse() { setOverride(OVERRIDE_OFF_SETTING); // When toggle override matches its default state (dw flag), don't override flags - assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()).isFalse(); + assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse(); } @Test diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index e07471cd64bc..6d31578ac020 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -128,22 +128,6 @@ public final class Bitmap implements Parcelable { 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). */ @@ -167,6 +151,7 @@ public final class Bitmap implements Parcelable { mWidth = width; mHeight = height; mRequestPremultiplied = requestPremultiplied; + mNinePatchChunk = ninePatchChunk; mNinePatchInsets = ninePatchInsets; if (density >= 0) { @@ -174,9 +159,17 @@ public final class Bitmap implements Parcelable { } mNativePtr = nativeBitmap; - final int allocationByteCount = getAllocationByteCount(); - getRegistry(fromMalloc, allocationByteCount).registerNativeAllocation(this, mNativePtr); + 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); synchronized (Bitmap.class) { sAllBitmaps.put(this, null); } diff --git a/graphics/java/android/graphics/GraphicsStatsService.java b/graphics/java/android/graphics/GraphicsStatsService.java index dc785c5b0309..7a012bcde799 100644 --- a/graphics/java/android/graphics/GraphicsStatsService.java +++ b/graphics/java/android/graphics/GraphicsStatsService.java @@ -311,7 +311,7 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { 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 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { 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 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { 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 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { 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/Android.bp b/libs/WindowManager/Shell/Android.bp index 94809f2d258f..f8574294a3a2 100644 --- a/libs/WindowManager/Shell/Android.bp +++ b/libs/WindowManager/Shell/Android.bp @@ -147,8 +147,10 @@ java_library { java_library { name: "WindowManager-Shell-lite-proto", - srcs: ["src/com/android/wm/shell/desktopmode/education/data/proto/**/*.proto"], - + srcs: [ + "src/com/android/wm/shell/desktopmode/education/data/proto/**/*.proto", + "src/com/android/wm/shell/desktopmode/persistence/*.proto", + ], proto: { type: "lite", }, diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig index 526ccd55ce3d..63a288079401 100644 --- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig +++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig @@ -122,6 +122,16 @@ flag { } flag { + name: "enable_shell_top_task_tracking" + namespace: "multitasking" + description: "Enables tracking top tasks from the shell" + bug: "342627272" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "enable_bubble_bar_in_persistent_task_bar" namespace: "multitasking" description: "Enable bubble bar to be shown in the persistent task bar" diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.png Binary files differindex 991cdcf09416..c7b4c65b8c4b 100644 --- a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.png +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.png Binary files differindex 991cdcf09416..c7b4c65b8c4b 100644 --- a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.png +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.png diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_app_handle.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_app_handle.xml index c0ff1922edc8..1d1cdfa85040 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_app_handle.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_app_handle.xml @@ -28,6 +28,8 @@ android:layout_height="@dimen/desktop_mode_fullscreen_decor_caption_height" android:paddingVertical="16dp" android:paddingHorizontal="10dp" + android:screenReaderFocusable="true" + android:importantForAccessibility="yes" android:contentDescription="@string/handle_text" android:src="@drawable/decor_handle_dark" tools:tint="@color/desktop_mode_caption_handle_bar_dark" diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_app_header.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_app_header.xml index 7dcb3c237c51..3dbf7542ac6e 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_app_header.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_app_header.xml @@ -31,14 +31,16 @@ android:orientation="horizontal" android:clickable="true" android:focusable="true" + android:contentDescription="@string/desktop_mode_app_header_chip_text" android:layout_marginStart="12dp"> <ImageView android:id="@+id/application_icon" android:layout_width="@dimen/desktop_mode_caption_icon_radius" android:layout_height="@dimen/desktop_mode_caption_icon_radius" android:layout_gravity="center_vertical" - android:contentDescription="@string/app_icon_text" android:layout_marginStart="6dp" + android:clickable="false" + android:focusable="false" android:scaleType="centerCrop"/> <TextView @@ -53,18 +55,22 @@ android:layout_gravity="center_vertical" android:layout_weight="1" android:layout_marginStart="8dp" + android:clickable="false" + android:focusable="false" tools:text="Gmail"/> <ImageButton android:id="@+id/expand_menu_button" android:layout_width="16dp" android:layout_height="16dp" - android:contentDescription="@string/expand_menu_text" android:src="@drawable/ic_baseline_expand_more_24" android:background="@null" android:scaleType="fitCenter" android:clickable="false" android:focusable="false" + android:screenReaderFocusable="false" + android:importantForAccessibility="no" + android:contentDescription="@null" android:layout_marginHorizontal="8dp" android:layout_gravity="center_vertical"/> @@ -90,6 +96,7 @@ <com.android.wm.shell.windowdecor.MaximizeButtonView android:id="@+id/maximize_button_view" + android:importantForAccessibility="no" android:layout_width="44dp" android:layout_height="40dp" android:layout_gravity="end" diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml index 64f71c713d1c..6913e54c2b10 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml @@ -43,13 +43,15 @@ android:layout_height="@dimen/desktop_mode_caption_icon_radius" android:layout_marginStart="12dp" android:layout_marginEnd="12dp" - android:contentDescription="@string/app_icon_text"/> + android:contentDescription="@string/app_icon_text" + android:importantForAccessibility="no"/> <TextView android:id="@+id/application_name" android:layout_width="0dp" android:layout_height="wrap_content" tools:text="Gmail" + android:importantForAccessibility="no" android:textColor="?androidprv:attr/materialColorOnSurface" android:textSize="14sp" android:textFontWeight="500" diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml index 5fe3f2af63a0..35ef2393bb9b 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml @@ -41,6 +41,8 @@ android:id="@+id/maximize_menu_maximize_button" style="?android:attr/buttonBarButtonStyle" android:stateListAnimator="@null" + android:importantForAccessibility="yes" + android:contentDescription="@string/desktop_mode_maximize_menu_maximize_button_text" android:layout_marginRight="8dp" android:layout_marginBottom="4dp" android:alpha="0"/> @@ -53,6 +55,7 @@ android:layout_marginBottom="76dp" android:gravity="center" android:fontFamily="google-sans-text" + android:importantForAccessibility="no" android:text="@string/desktop_mode_maximize_menu_maximize_text" android:textColor="?androidprv:attr/materialColorOnSurface" android:alpha="0"/> @@ -78,6 +81,8 @@ android:layout_height="@dimen/desktop_mode_maximize_menu_button_height" android:layout_marginRight="4dp" android:background="@drawable/desktop_mode_maximize_menu_button_background" + android:importantForAccessibility="yes" + android:contentDescription="@string/desktop_mode_maximize_menu_snap_left_button_text" android:stateListAnimator="@null"/> <Button @@ -86,6 +91,8 @@ android:layout_width="41dp" android:layout_height="@dimen/desktop_mode_maximize_menu_button_height" android:background="@drawable/desktop_mode_maximize_menu_button_background" + android:importantForAccessibility="yes" + android:contentDescription="@string/desktop_mode_maximize_menu_snap_right_button_text" android:stateListAnimator="@null"/> </LinearLayout> <TextView @@ -96,6 +103,7 @@ android:layout_marginBottom="76dp" android:layout_gravity="center" android:gravity="center" + android:importantForAccessibility="no" android:fontFamily="google-sans-text" android:text="@string/desktop_mode_maximize_menu_snap_text" android:textColor="?androidprv:attr/materialColorOnSurface" diff --git a/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml b/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml index cf1b8947467e..b734d2d81455 100644 --- a/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml +++ b/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml @@ -19,7 +19,8 @@ <FrameLayout android:layout_width="44dp" - android:layout_height="40dp"> + android:layout_height="40dp" + android:importantForAccessibility="noHideDescendants"> <ProgressBar android:id="@+id/progress_bar" style="?android:attr/progressBarStyleHorizontal" diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml index e50d8dc59f4c..50aa4ca1a1f1 100644 --- a/libs/WindowManager/Shell/res/values-af/strings.xml +++ b/libs/WindowManager/Shell/res/values-af/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Bestuur vensters"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimeer skerm"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Gryp skerm vas"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Hierdie app se grootte kan nie verander word nie"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml index f29bbe7c4cdd..281e313d328f 100644 --- a/libs/WindowManager/Shell/res/values-am/strings.xml +++ b/libs/WindowManager/Shell/res/values-am/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"የማያ ገጹ መጠን አሳድግ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ማያ ገጹን አሳድግ"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ይህ መተግበሪያ መጠኑ ሊቀየር አይችልም"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml index d76a2a50f299..2c0b34a604a9 100644 --- a/libs/WindowManager/Shell/res/values-ar/strings.xml +++ b/libs/WindowManager/Shell/res/values-ar/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"تكبير الشاشة إلى أقصى حدّ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"التقاط صورة للشاشة"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"لا يمكن تغيير حجم نافذة هذا التطبيق"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml index 1fe79aca1ef2..c5e37162e2d9 100644 --- a/libs/WindowManager/Shell/res/values-as/strings.xml +++ b/libs/WindowManager/Shell/res/values-as/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্ৰীন মেক্সিমাইজ কৰক"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"স্ক্ৰীন স্নেপ কৰক"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"এই এপ্টোৰ আকাৰ সলনি কৰিব নোৱাৰি"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml index 299265532d66..e23e8d049a8f 100644 --- a/libs/WindowManager/Shell/res/values-az/strings.xml +++ b/libs/WindowManager/Shell/res/values-az/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Pəncərələri idarə edin"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranı maksimum böyüdün"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ekranı çəkin"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Bu tətbiqin ölçüsünü dəyişmək olmur"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> 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 12f14189e53d..283d1f5578cf 100644 --- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml +++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Povećaj ekran"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Uklopi ekran"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Veličina ove aplikacije ne može da se promeni"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml index 8aa43f7ab102..48914f1eb27c 100644 --- a/libs/WindowManager/Shell/res/values-be/strings.xml +++ b/libs/WindowManager/Shell/res/values-be/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Разгарнуць на ўвесь экран"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Размясціць на палавіне экрана"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Немагчыма змяніць памер праграмы"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml index b84778b4bca3..b385d285350b 100644 --- a/libs/WindowManager/Shell/res/values-bg/strings.xml +++ b/libs/WindowManager/Shell/res/values-bg/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Увеличаване на екрана"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Прилепване на екрана"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Това приложение не може да бъде преоразмерено"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml index 5e47e2a85de8..56fcf7f4fff5 100644 --- a/libs/WindowManager/Shell/res/values-bn/strings.xml +++ b/libs/WindowManager/Shell/res/values-bn/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্রিন বড় করুন"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"স্ক্রিনে অ্যাপ মানানসই হিসেবে ছোট বড় করুন"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"এই অ্যাপ ছোট বড় করা যাবে না"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml index bd7cddd59233..95362bbfeab5 100644 --- a/libs/WindowManager/Shell/res/values-bs/strings.xml +++ b/libs/WindowManager/Shell/res/values-bs/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiziraj ekran"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snimi ekran"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Nije moguće promijeniti veličinu aplikacije"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml index af54037e87f1..e0b25389e6f1 100644 --- a/libs/WindowManager/Shell/res/values-ca/strings.xml +++ b/libs/WindowManager/Shell/res/values-ca/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Gestiona les finestres"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximitza la pantalla"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajusta la pantalla"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"No es pot canviar la mida d\'aquesta aplicació"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml index dd4802ed963c..3aae52e4808a 100644 --- a/libs/WindowManager/Shell/res/values-cs/strings.xml +++ b/libs/WindowManager/Shell/res/values-cs/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximalizovat obrazovku"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Rozpůlit obrazovku"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Velikost aplikace nelze změnit"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml index fca92a171211..fdc59137dd5e 100644 --- a/libs/WindowManager/Shell/res/values-da/strings.xml +++ b/libs/WindowManager/Shell/res/values-da/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Administrer vinduer"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimér skærm"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Tilpas skærm"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Størrelsen på denne app kan ikke justeres"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml index 512bd7a64582..913e3d0abf0f 100644 --- a/libs/WindowManager/Shell/res/values-de/strings.xml +++ b/libs/WindowManager/Shell/res/values-de/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Fenster verwalten"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Bildschirm maximieren"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Bildschirm teilen"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Die Größe dieser App kann nicht geändert werden"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml index f66d8744c793..564fa910fdcd 100644 --- a/libs/WindowManager/Shell/res/values-el/strings.xml +++ b/libs/WindowManager/Shell/res/values-el/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Μεγιστοποίηση οθόνης"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Προβολή στο μισό της οθόνης"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Δεν είναι δυνατή η αλλαγή μεγέθους αυτής της εφαρμογής"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml index 0b11cb530a52..e4ece9386a3f 100644 --- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap screen"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"This app can\'t be resized"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml index a09e1e90b4d5..14fe60b3e3cb 100644 --- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximize Screen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap Screen"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"This app can\'t be resized"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml index 0b11cb530a52..e4ece9386a3f 100644 --- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap screen"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"This app can\'t be resized"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml index 0b11cb530a52..e4ece9386a3f 100644 --- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap screen"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"This app can\'t be resized"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml index 7662a14fa4c5..dda97abf7b03 100644 --- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximize Screen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap Screen"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"This app can\'t be resized"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml index 7a324e3dba7a..a4c03632cbe4 100644 --- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml +++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Administrar ventanas"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajustar pantalla"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"No se puede cambiar el tamaño de esta app"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml index 27272aae46a3..69f7d7b020d6 100644 --- a/libs/WindowManager/Shell/res/values-es/strings.xml +++ b/libs/WindowManager/Shell/res/values-es/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Gestionar ventanas"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajustar pantalla"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"No se puede cambiar el tamaño de esta aplicación"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml index d859f01fd6f0..3d929f6cd8d3 100644 --- a/libs/WindowManager/Shell/res/values-et/strings.xml +++ b/libs/WindowManager/Shell/res/values-et/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Akende haldamine"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Kuva täisekraanil"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Kuva poolel ekraanil"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Selle rakenduse aknasuurust ei saa muuta"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml index 999960b1a934..39bcf080fcf3 100644 --- a/libs/WindowManager/Shell/res/values-eu/strings.xml +++ b/libs/WindowManager/Shell/res/values-eu/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Kudeatu leihoak"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Handitu pantaila"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Zatitu pantaila"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Ezin zaio aldatu tamaina aplikazio honi"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml index e31a6caea9e3..9f607bf89656 100644 --- a/libs/WindowManager/Shell/res/values-fa/strings.xml +++ b/libs/WindowManager/Shell/res/values-fa/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"بزرگ کردن صفحه"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"بزرگ کردن صفحه"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"اندازه این برنامه را نمیتوان تغییر داد"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml index 71c3e36f487f..04b6241ca90b 100644 --- a/libs/WindowManager/Shell/res/values-fi/strings.xml +++ b/libs/WindowManager/Shell/res/values-fi/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Hallinnoi ikkunoita"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Suurenna näyttö"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Jaa näyttö"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Tämän sovellusikkunan kokoa ei voi muuttaa"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml index 790a29685ead..73129525ebdd 100644 --- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Gérer les fenêtres"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Agrandir l\'écran"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Aligner l\'écran"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Impossible de redimensionner cette appli"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml index 3472edd212b8..8f4e58f99a13 100644 --- a/libs/WindowManager/Shell/res/values-fr/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Gérer les fenêtres"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Mettre en plein écran"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Fractionner l\'écran"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Impossible de redimensionner cette appli"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml index 31cb71d939ff..5c0aa074b329 100644 --- a/libs/WindowManager/Shell/res/values-gl/strings.xml +++ b/libs/WindowManager/Shell/res/values-gl/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Xestionar as ventás"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Encaixar pantalla"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Non se pode cambiar o tamaño desta aplicación"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml index e1f58063ed49..a382d0b41652 100644 --- a/libs/WindowManager/Shell/res/values-gu/strings.xml +++ b/libs/WindowManager/Shell/res/values-gu/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"સ્ક્રીન કરો મોટી કરો"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"સ્ક્રીન સ્નૅપ કરો"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"આ ઍપના કદમાં વધઘટ કરી શકાતો નથી"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml index cea4b2359f5e..d6fc85b6cdcc 100644 --- a/libs/WindowManager/Shell/res/values-hi/strings.xml +++ b/libs/WindowManager/Shell/res/values-hi/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन को बड़ा करें"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"स्नैप स्क्रीन"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"इस ऐप्लिकेशन का साइज़ नहीं बदला जा सकता"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml index 23cddbc88b2d..f233c029c752 100644 --- a/libs/WindowManager/Shell/res/values-hr/strings.xml +++ b/libs/WindowManager/Shell/res/values-hr/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimalno povećaj zaslon"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Izradi snimku zaslona"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Nije moguće promijeniti veličinu aplikacije"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml index e3c3ced83e38..aaa4e2654f39 100644 --- a/libs/WindowManager/Shell/res/values-hu/strings.xml +++ b/libs/WindowManager/Shell/res/values-hu/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Ablakok kezelése"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Képernyő méretének maximalizálása"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Igazodás a képernyő adott részéhez"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Ezt az alkalmazást nem lehet átméretezni"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml index 56b609b8a832..cd21faab45c2 100644 --- a/libs/WindowManager/Shell/res/values-hy/strings.xml +++ b/libs/WindowManager/Shell/res/values-hy/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ծավալել էկրանը"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ծալել էկրանը"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Այս հավելվածի չափը հնարավոր չէ փոխել"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml index a83d51e3c1f6..ba0683deecd8 100644 --- a/libs/WindowManager/Shell/res/values-in/strings.xml +++ b/libs/WindowManager/Shell/res/values-in/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Kelola Jendela"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Perbesar Layar"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Gabungkan Layar"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Ukuran aplikasi ini tidak dapat diubah"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml index e7590cbd0778..b427eaf23290 100644 --- a/libs/WindowManager/Shell/res/values-is/strings.xml +++ b/libs/WindowManager/Shell/res/values-is/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Stjórna gluggum"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Stækka skjá"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Smelluskjár"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Ekki er hægt að breyta stærð þessa forrits"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml index bd74fbed9ac7..9eb9d4e3a403 100644 --- a/libs/WindowManager/Shell/res/values-it/strings.xml +++ b/libs/WindowManager/Shell/res/values-it/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Gestisci finestre"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Massimizza schermo"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Aggancia schermo"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Non è possibile ridimensionare questa app"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml index d8533bbd814d..3e82198201b9 100644 --- a/libs/WindowManager/Shell/res/values-iw/strings.xml +++ b/libs/WindowManager/Shell/res/values-iw/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"הגדלת המסך"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"כיווץ המסך"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"לא ניתן לשנות את גודל החלון של האפליקציה הזו"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml index 26540c7ddc59..5d8dc5e85462 100644 --- a/libs/WindowManager/Shell/res/values-ja/strings.xml +++ b/libs/WindowManager/Shell/res/values-ja/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"画面の最大化"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"画面のスナップ"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"このアプリはサイズ変更できません"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml index d2fbcb1c66fc..de08b9ca2d7e 100644 --- a/libs/WindowManager/Shell/res/values-ka/strings.xml +++ b/libs/WindowManager/Shell/res/values-ka/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"აპლიკაციის გაშლა სრულ ეკრანზე"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"აპლიკაციის დაპატარავება ეკრანზე"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"აპის ზომის შეცვლა შეუძლებელია"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml index 43c2f83d884d..dd4e5c94fc27 100644 --- a/libs/WindowManager/Shell/res/values-kk/strings.xml +++ b/libs/WindowManager/Shell/res/values-kk/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Экранды ұлғайту"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Экранды бөлу"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Бұл қолданбаның өлшемі өзгертілмейді."</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml index c0bf1bf07f47..96fe62e4f034 100644 --- a/libs/WindowManager/Shell/res/values-km/strings.xml +++ b/libs/WindowManager/Shell/res/values-km/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ពង្រីកអេក្រង់"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ថតអេក្រង់"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"មិនអាចប្ដូរទំហំកម្មវិធីនេះបានទេ"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml index 92b8ad444666..b38f74411db2 100644 --- a/libs/WindowManager/Shell/res/values-kn/strings.xml +++ b/libs/WindowManager/Shell/res/values-kn/strings.xml @@ -34,8 +34,8 @@ <string name="dock_forced_resizable" msgid="7429086980048964687">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ಆ್ಯಪ್ ಕೆಲಸ ಮಾಡದೇ ಇರಬಹುದು"</string> <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಆ್ಯಪ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string> <string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"ಈ ಆ್ಯಪ್ ಅನ್ನು 1 ವಿಂಡೋದಲ್ಲಿ ಮಾತ್ರ ತೆರೆಯಬಹುದು"</string> - <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ಸೆಕೆಂಡರಿ ಡಿಸ್ಪ್ಲೇಗಳಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್ ಕಾರ್ಯ ನಿರ್ವಹಿಸದೇ ಇರಬಹುದು."</string> - <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ಸೆಕೆಂಡರಿ ಡಿಸ್ಪ್ಲೇಗಳಲ್ಲಿ ಪ್ರಾರಂಭಿಸುವಿಕೆಯನ್ನು ಅಪ್ಲಿಕೇಶನ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string> + <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ಸೆಕೆಂಡರಿ ಡಿಸ್ಪ್ಲೇಗಳಲ್ಲಿ ಆ್ಯಪ್ ಕಾರ್ಯ ನಿರ್ವಹಿಸದೇ ಇರಬಹುದು."</string> + <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ಸೆಕೆಂಡರಿ ಡಿಸ್ಪ್ಲೇಗಳಲ್ಲಿ ಪ್ರಾರಂಭಿಸುವಿಕೆಯನ್ನು ಆ್ಯಪ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string> <string name="accessibility_divider" msgid="6407584574218956849">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಡಿವೈಡರ್"</string> <string name="divider_title" msgid="1963391955593749442">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಡಿವೈಡರ್"</string> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ಎಡ ಫುಲ್ ಸ್ಕ್ರೀನ್"</string> @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ಸ್ಕ್ರೀನ್ ಅನ್ನು ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ಸ್ನ್ಯಾಪ್ ಸ್ಕ್ರೀನ್"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml index b52c8a169eff..421d4666911e 100644 --- a/libs/WindowManager/Shell/res/values-ko/strings.xml +++ b/libs/WindowManager/Shell/res/values-ko/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"화면 최대화"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"화면 분할"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"이 앱은 크기를 조절할 수 없습니다."</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml index f994d1e82dd3..abafd7ac0330 100644 --- a/libs/WindowManager/Shell/res/values-ky/strings.xml +++ b/libs/WindowManager/Shell/res/values-ky/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Экранды чоңойтуу"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Экранды сүрөткө тартып алуу"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Бул колдонмонун өлчөмүн өзгөртүүгө болбойт"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml index 459f3a218a31..5bc5316494b3 100644 --- a/libs/WindowManager/Shell/res/values-lo/strings.xml +++ b/libs/WindowManager/Shell/res/values-lo/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ປັບຈໍໃຫຍ່ສຸດ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ສະແນັບໜ້າຈໍ"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ບໍ່ສາມາດປັບຂະໜາດແອັບນີ້ໄດ້"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml index 2bfd9d32093a..01a72ee4cced 100644 --- a/libs/WindowManager/Shell/res/values-lt/strings.xml +++ b/libs/WindowManager/Shell/res/values-lt/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Išskleisti ekraną"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Sutraukti ekraną"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Negalima keisti šios programos dydžio"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml index b6012740b4cd..2f235babd721 100644 --- a/libs/WindowManager/Shell/res/values-lv/strings.xml +++ b/libs/WindowManager/Shell/res/values-lv/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Pārvaldīt logus"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimizēt ekrānu"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Fiksēt ekrānu"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Šīs lietotnes loga lielumu nevar mainīt."</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml index 96e7f2527e0b..e58d8fc945f4 100644 --- a/libs/WindowManager/Shell/res/values-mk/strings.xml +++ b/libs/WindowManager/Shell/res/values-mk/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Максимизирај го екранот"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Подели го екранот на половина"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Не може да се промени големината на апликацијава"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml index a77c203c325e..d51c3fb70a9e 100644 --- a/libs/WindowManager/Shell/res/values-ml/strings.xml +++ b/libs/WindowManager/Shell/res/values-ml/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"സ്ക്രീൻ വലുതാക്കുക"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"സ്ക്രീൻ സ്നാപ്പ് ചെയ്യുക"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ഈ ആപ്പിന്റെ വലുപ്പം മാറ്റാനാകില്ല"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml index 5c7f5483922d..f7e6a6c87890 100644 --- a/libs/WindowManager/Shell/res/values-mn/strings.xml +++ b/libs/WindowManager/Shell/res/values-mn/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Дэлгэцийг томруулах"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Дэлгэцийг таллах"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Энэ аппын хэмжээг өөрчлөх боломжгүй"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml index a78b37b43c8b..483228424d44 100644 --- a/libs/WindowManager/Shell/res/values-mr/strings.xml +++ b/libs/WindowManager/Shell/res/values-mr/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन मोठी करा"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"स्क्रीन स्नॅप करा"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"या अॅपचा आकार बदलला जाऊ शकत नाही"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml index fa2c1c52318b..e510d723f1e5 100644 --- a/libs/WindowManager/Shell/res/values-ms/strings.xml +++ b/libs/WindowManager/Shell/res/values-ms/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Urus Tetingkap"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimumkan Skrin"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Tangkap Skrin"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Apl ini tidak boleh diubah saiz"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml index 48449c0ce834..aac6f8420d7a 100644 --- a/libs/WindowManager/Shell/res/values-my/strings.xml +++ b/libs/WindowManager/Shell/res/values-my/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"စခရင်ကို ချဲ့မည်"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"စခရင်ကို ချုံ့မည်"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ဤအက်ပ်ကို အရွယ်ပြင်၍ မရပါ"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml index 5697f0de6bdc..175133d1744a 100644 --- a/libs/WindowManager/Shell/res/values-nb/strings.xml +++ b/libs/WindowManager/Shell/res/values-nb/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Administrer vinduene"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimer skjermen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Fest skjermen"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Du kan ikke endre størrelse på denne appen"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml index 365a3b378f43..d3a7e12c0df4 100644 --- a/libs/WindowManager/Shell/res/values-ne/strings.xml +++ b/libs/WindowManager/Shell/res/values-ne/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रिन ठुलो बनाउनुहोस्"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"स्क्रिन स्न्याप गर्नुहोस्"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"यो एपको आकार बदल्न मिल्दैन"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml index 9cf1551ac0dc..747afe3eb034 100644 --- a/libs/WindowManager/Shell/res/values-nl/strings.xml +++ b/libs/WindowManager/Shell/res/values-nl/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Vensters beheren"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Scherm maximaliseren"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Scherm halveren"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Het formaat van deze app kan niet worden aangepast"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml index 9f7342cb4059..a5adcbe36db1 100644 --- a/libs/WindowManager/Shell/res/values-or/strings.xml +++ b/libs/WindowManager/Shell/res/values-or/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ସ୍କ୍ରିନକୁ ବଡ଼ କରନ୍ତୁ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ସ୍କ୍ରିନକୁ ସ୍ନାପ କରନ୍ତୁ"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ଏହି ଆପକୁ ରିସାଇଜ କରାଯାଇପାରିବ ନାହିଁ"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml index 48fa55213b66..5a4e61a2303b 100644 --- a/libs/WindowManager/Shell/res/values-pa/strings.xml +++ b/libs/WindowManager/Shell/res/values-pa/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ਸਕ੍ਰੀਨ ਦਾ ਆਕਾਰ ਵਧਾਓ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ਸਕ੍ਰੀਨ ਨੂੰ ਸਨੈਪ ਕਰੋ"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ਇਸ ਐਪ ਦਾ ਆਕਾਰ ਬਦਲਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml index 211ae9852450..a14bb99286f8 100644 --- a/libs/WindowManager/Shell/res/values-pl/strings.xml +++ b/libs/WindowManager/Shell/res/values-pl/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Zarządzaj oknami"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksymalizuj ekran"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Przyciągnij ekran"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Nie można zmienić rozmiaru tej aplikacji"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml index dfae5d84bfdc..75c445c6f35c 100644 --- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Gerenciar 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 o menu"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ampliar tela"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajustar tela"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Não é possível redimensionar o app"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml index 1399b26ec68c..1d31d0d92309 100644 --- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar ecrã"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Encaixar ecrã"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Não é possível redimensionar esta app"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml index dfae5d84bfdc..75c445c6f35c 100644 --- a/libs/WindowManager/Shell/res/values-pt/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Gerenciar 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 o menu"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ampliar tela"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajustar tela"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Não é possível redimensionar o app"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml index 2f458e9bc0de..3c763ea8a6a4 100644 --- a/libs/WindowManager/Shell/res/values-ro/strings.xml +++ b/libs/WindowManager/Shell/res/values-ro/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizează fereastra"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Micșorează fereastra și fixeaz-o"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Aplicația nu poate fi redimensionată"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml index a7fdd41d2dda..a6c20adc4c2e 100644 --- a/libs/WindowManager/Shell/res/values-ru/strings.xml +++ b/libs/WindowManager/Shell/res/values-ru/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Развернуть на весь экран"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Свернуть"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Изменить размер приложения нельзя."</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml index bbfafb6035ac..ed762699bc49 100644 --- a/libs/WindowManager/Shell/res/values-si/strings.xml +++ b/libs/WindowManager/Shell/res/values-si/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"තිරය උපරිම කරන්න"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ස්නැප් තිරය"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"මෙම යෙදුම ප්රතිප්රමාණ කළ නොහැක"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml index da7a834d0072..529a6932c9ce 100644 --- a/libs/WindowManager/Shell/res/values-sk/strings.xml +++ b/libs/WindowManager/Shell/res/values-sk/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Správa okien"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximalizovať obrazovku"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Zobraziť polovicu obrazovky"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Veľkosť tejto aplikácie sa nedá zmeniť"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml index 0434e5440f10..fe08e04b21a3 100644 --- a/libs/WindowManager/Shell/res/values-sl/strings.xml +++ b/libs/WindowManager/Shell/res/values-sl/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiraj zaslon"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Pripni zaslon"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Velikosti te aplikacije ni mogoče spremeniti"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml index 65a270da90c5..a4a7e744c426 100644 --- a/libs/WindowManager/Shell/res/values-sq/strings.xml +++ b/libs/WindowManager/Shell/res/values-sq/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Menaxho dritaret"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimizo ekranin"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Regjistro ekranin"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Përmasat e këtij aplikacioni nuk mund të ndryshohen"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml index caa9c7dad9b5..9545ccf7a810 100644 --- a/libs/WindowManager/Shell/res/values-sr/strings.xml +++ b/libs/WindowManager/Shell/res/values-sr/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Повећај екран"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Уклопи екран"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Величина ове апликације не може да се промени"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml index 681ef8ba97e4..c43f5dfa7b02 100644 --- a/libs/WindowManager/Shell/res/values-sv/strings.xml +++ b/libs/WindowManager/Shell/res/values-sv/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximera skärmen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Fäst skärmen"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Det går inte att ändra storlek på appen"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml index bb314a3ac153..c6ce023a5ca7 100644 --- a/libs/WindowManager/Shell/res/values-sw/strings.xml +++ b/libs/WindowManager/Shell/res/values-sw/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Dhibiti Windows"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Panua Dirisha kwenye Skrini"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Panga Madirisha kwenye Skrini"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Huwezi kubadilisha ukubwa wa programu hii"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml index 686e705dc68a..2c2f31978b0f 100644 --- a/libs/WindowManager/Shell/res/values-ta/strings.xml +++ b/libs/WindowManager/Shell/res/values-ta/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"திரையைப் பெரிதாக்கு"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"திரையை ஸ்னாப் செய்"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"இந்த ஆப்ஸின் அளவை மாற்ற முடியாது"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml index 7b554d936eb1..8691c9d5aa26 100644 --- a/libs/WindowManager/Shell/res/values-te/strings.xml +++ b/libs/WindowManager/Shell/res/values-te/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"స్క్రీన్ సైజ్ను పెంచండి"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"స్క్రీన్ను స్నాప్ చేయండి"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ఈ యాప్ సైజ్ను మార్చడం సాధ్యపడదు"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml index 59deabb2a2e0..07e141601d08 100644 --- a/libs/WindowManager/Shell/res/values-th/strings.xml +++ b/libs/WindowManager/Shell/res/values-th/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ขยายหน้าจอให้ใหญ่สุด"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"สแนปหน้าจอ"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"ปรับขนาดแอปนี้ไม่ได้"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml index 79e968d87b14..477700e7bbdf 100644 --- a/libs/WindowManager/Shell/res/values-tl/strings.xml +++ b/libs/WindowManager/Shell/res/values-tl/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"I-maximize ang Screen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"I-snap ang Screen"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Hindi nare-resize ang app na ito"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml index e5bca20178c2..b0c253965970 100644 --- a/libs/WindowManager/Shell/res/values-tr/strings.xml +++ b/libs/WindowManager/Shell/res/values-tr/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Pencereleri yönet"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranı Büyüt"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ekranın Yarısına Tuttur"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Bu uygulama yeniden boyutlandırılamaz"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml index 0e877b005615..dd64c6642104 100644 --- a/libs/WindowManager/Shell/res/values-uk/strings.xml +++ b/libs/WindowManager/Shell/res/values-uk/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Розгорнути екран"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Зафіксувати екран"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Розмір вікна цього додатка не можна змінити"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml index 06807957b37a..aa311c2978c8 100644 --- a/libs/WindowManager/Shell/res/values-ur/strings.xml +++ b/libs/WindowManager/Shell/res/values-ur/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"اسکرین کو بڑا کریں"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"اسکرین کا اسناپ شاٹ لیں"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"اس ایپ کا سائز تبدیل نہیں کیا جا سکتا"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml index 4e0eb532a2a4..8754629df761 100644 --- a/libs/WindowManager/Shell/res/values-uz/strings.xml +++ b/libs/WindowManager/Shell/res/values-uz/strings.xml @@ -126,8 +126,15 @@ <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranni yoyish"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ekranni biriktirish"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Bu ilova hajmini oʻzgartirish imkonsiz"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml index c5d76ea79355..abac3fe824bb 100644 --- a/libs/WindowManager/Shell/res/values-vi/strings.xml +++ b/libs/WindowManager/Shell/res/values-vi/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Quản lý cửa sổ"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Mở rộng màn hình"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Điều chỉnh kích thước màn hình"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Không thể đổi kích thước của ứng dụng này"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml index 1202168e1f64..5a61decdcfb9 100644 --- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"最大化屏幕"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"屏幕快照"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"无法调整此应用的大小"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml index a23b147ee566..e1c303e198bb 100644 --- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"畫面最大化"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"貼齊畫面"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"此應用程式無法調整大小"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml index e70a8ad50f56..97e36c300a4a 100644 --- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml @@ -123,12 +123,18 @@ <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="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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"畫面最大化"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"貼齊畫面"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"這個應用程式無法調整大小"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml index 13a2a0fa977a..74c7169fefa3 100644 --- a/libs/WindowManager/Shell/res/values-zu/strings.xml +++ b/libs/WindowManager/Shell/res/values-zu/strings.xml @@ -123,12 +123,18 @@ <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="manage_windows_text" msgid="5567366688493093920">"Phatha Amawindi"</string> <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> + <!-- no translation found for desktop_mode_app_header_chip_text (6366422614991687237) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Khulisa Isikrini Sifike Ekugcineni"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Thwebula Isikrini"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="1049800446363800707">"Le app ayikwazi ukushintshwa usayizi"</string> + <!-- no translation found for desktop_mode_maximize_menu_maximize_button_text (3090199175564175845) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_left_button_text (8077452201179893424) --> + <skip /> + <!-- no translation found for desktop_mode_maximize_menu_snap_right_button_text (7117751068945657304) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml index a6da421dbbb9..bda56860d3ba 100644 --- a/libs/WindowManager/Shell/res/values/strings.xml +++ b/libs/WindowManager/Shell/res/values/strings.xml @@ -300,12 +300,19 @@ <string name="close_text">Close</string> <!-- Accessibility text for the handle menu close menu button [CHAR LIMIT=NONE] --> <string name="collapse_menu_text">Close Menu</string> - <!-- Accessibility text for the handle menu open menu button [CHAR LIMIT=NONE] --> - <string name="expand_menu_text">Open Menu</string> + <!-- Accessibility text for the App Header's App Chip [CHAR LIMIT=NONE] --> + <string name="desktop_mode_app_header_chip_text">Open Menu</string> <!-- Maximize menu maximize button string. --> <string name="desktop_mode_maximize_menu_maximize_text">Maximize Screen</string> <!-- Maximize menu snap buttons string. --> <string name="desktop_mode_maximize_menu_snap_text">Snap Screen</string> <!-- Snap resizing non-resizable string. --> <string name="desktop_mode_non_resizable_snap_text">This app can\'t be resized</string> + <!-- Accessibility text for the Maximize Menu's maximize button [CHAR LIMIT=NONE] --> + <string name="desktop_mode_maximize_menu_maximize_button_text">Maximize</string> + <!-- Accessibility text for the Maximize Menu's snap left button [CHAR LIMIT=NONE] --> + <string name="desktop_mode_maximize_menu_snap_left_button_text">Snap left</string> + <!-- Accessibility text for the Maximize Menu's snap right button [CHAR LIMIT=NONE] --> + <string name="desktop_mode_maximize_menu_snap_right_button_text">Snap right</string> + </resources> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index 7e6f43458ba6..4607a8ec1210 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -584,7 +584,8 @@ public class ShellTaskOrganizer extends TaskOrganizer { final boolean windowModeChanged = data.getTaskInfo().getWindowingMode() != taskInfo.getWindowingMode(); final boolean visibilityChanged = data.getTaskInfo().isVisible != taskInfo.isVisible; - if (windowModeChanged || visibilityChanged) { + if (windowModeChanged || (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM + && visibilityChanged)) { mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskRunningInfoChanged(taskInfo)); } 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 80a9b675ebd8..96a07755fea9 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 @@ -18,7 +18,6 @@ package com.android.wm.shell.dagger; import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT; -import android.annotation.NonNull; import android.annotation.Nullable; import android.app.KeyguardManager; import android.content.Context; @@ -79,6 +78,7 @@ 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; +import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.draganddrop.GlobalDragListener; import com.android.wm.shell.freeform.FreeformComponents; @@ -116,8 +116,6 @@ import com.android.wm.shell.unfold.qualifier.UnfoldTransition; import com.android.wm.shell.windowdecor.CaptionWindowDecorViewModel; 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.WindowDecorViewHostSupplier; import dagger.Binds; import dagger.Lazy; @@ -249,8 +247,7 @@ public abstract class WMShellModule { MultiInstanceHelper multiInstanceHelper, Optional<DesktopTasksLimiter> desktopTasksLimiter, WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository, - Optional<DesktopActivityOrientationChangeHandler> desktopActivityOrientationHandler, - WindowDecorViewHostSupplier windowDecorViewHostSupplier) { + Optional<DesktopActivityOrientationChangeHandler> desktopActivityOrientationHandler) { if (DesktopModeStatus.canEnterDesktopMode(context)) { return new DesktopModeWindowDecorViewModel( context, @@ -275,8 +272,7 @@ public abstract class WMShellModule { multiInstanceHelper, desktopTasksLimiter, windowDecorCaptionHandleRepository, - desktopActivityOrientationHandler, - windowDecorViewHostSupplier); + desktopActivityOrientationHandler); } return new CaptionWindowDecorViewModel( context, @@ -290,8 +286,7 @@ public abstract class WMShellModule { displayController, rootTaskDisplayAreaOrganizer, syncQueue, - transitions, - windowDecorViewHostSupplier); + transitions); } @WMSingleton @@ -382,13 +377,6 @@ public abstract class WMShellModule { context, shellInit, transitions, windowDecorViewModel); } - @WMSingleton - @Provides - static WindowDecorViewHostSupplier provideWindowDecorViewHostSupplier( - @ShellMainThread @NonNull CoroutineScope mainScope) { - return new DefaultWindowDecorViewHostSupplier(mainScope); - } - // // One handed mode // @@ -712,8 +700,14 @@ public abstract class WMShellModule { @WMSingleton @Provides @DynamicOverride - static DesktopModeTaskRepository provideDesktopModeTaskRepository() { - return new DesktopModeTaskRepository(); + static DesktopModeTaskRepository provideDesktopModeTaskRepository( + Context context, + ShellInit shellInit, + DesktopPersistentRepository desktopPersistentRepository, + @ShellMainThread CoroutineScope mainScope + ) { + return new DesktopModeTaskRepository(context, shellInit, desktopPersistentRepository, + mainScope); } @WMSingleton @@ -798,6 +792,14 @@ public abstract class WMShellModule { shellTaskOrganizer, appHandleEducationDatastoreRepository, applicationScope); } + @WMSingleton + @Provides + static DesktopPersistentRepository provideDesktopPersistentRepository( + Context context, + @ShellBackgroundThread CoroutineScope bgScope) { + return new DesktopPersistentRepository(context, bgScope); + } + // // Drag and drop // diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt index 9d041692200d..759ed035895e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt @@ -16,6 +16,7 @@ package com.android.wm.shell.desktopmode +import android.content.Context import android.graphics.Rect import android.graphics.Region import android.util.ArrayMap @@ -27,13 +28,27 @@ import androidx.core.util.forEach import androidx.core.util.keyIterator import androidx.core.util.valueIterator import com.android.internal.protolog.ProtoLog +import com.android.window.flags.Flags +import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository +import com.android.wm.shell.desktopmode.persistence.DesktopTask +import com.android.wm.shell.desktopmode.persistence.DesktopTaskState import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE +import com.android.wm.shell.shared.annotations.ShellMainThread +import com.android.wm.shell.shared.desktopmode.DesktopModeStatus +import com.android.wm.shell.sysui.ShellInit import java.io.PrintWriter import java.util.concurrent.Executor import java.util.function.Consumer +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch /** Tracks task data for Desktop Mode. */ -class DesktopModeTaskRepository { +class DesktopModeTaskRepository ( + private val context: Context, + shellInit: ShellInit, + private val persistentRepository: DesktopPersistentRepository, + @ShellMainThread private val mainCoroutineScope: CoroutineScope, +){ /** * Task data tracked per desktop. @@ -54,7 +69,15 @@ class DesktopModeTaskRepository { // TODO(b/332682201): Remove when the repository state is updated via TransitionObserver val closingTasks: ArraySet<Int> = ArraySet(), val freeformTasksInZOrder: ArrayList<Int> = ArrayList(), - ) + ) { + fun deepCopy(): DesktopTaskData = DesktopTaskData( + activeTasks = ArraySet(activeTasks), + visibleTasks = ArraySet(visibleTasks), + minimizedTasks = ArraySet(minimizedTasks), + closingTasks = ArraySet(closingTasks), + freeformTasksInZOrder = ArrayList(freeformTasksInZOrder) + ) + } /* Current wallpaper activity token to remove wallpaper activity when last task is removed. */ var wallpaperActivityToken: WindowContainerToken? = null @@ -77,6 +100,40 @@ class DesktopModeTaskRepository { this[displayId] ?: DesktopTaskData().also { this[displayId] = it } } + init { + if (DesktopModeStatus.canEnterDesktopMode(context)) { + shellInit.addInitCallback(::initRepoFromPersistentStorage, this) + } + } + + private fun initRepoFromPersistentStorage() { + if (!Flags.enableDesktopWindowingPersistence()) return + // TODO: b/365962554 - Handle the case that user moves to desktop before it's initialized + mainCoroutineScope.launch { + val desktop = persistentRepository.readDesktop() + val maxTasks = + DesktopModeStatus.getMaxTaskLimit(context).takeIf { it > 0 } + ?: desktop.zOrderedTasksCount + + desktop.zOrderedTasksList + // Reverse it so we initialize the repo from bottom to top. + .reversed() + .map { taskId -> + desktop.tasksByTaskIdMap.getOrDefault( + taskId, + DesktopTask.getDefaultInstance() + ) + } + .filter { task -> task.desktopTaskState == DesktopTaskState.VISIBLE } + .take(maxTasks) + .forEach { task -> + addOrMoveFreeformTaskToTop(desktop.displayId, task.taskId) + addActiveTask(desktop.displayId, task.taskId) + updateTaskVisibility(desktop.displayId, task.taskId, visible = false) + } + } + } + /** Adds [activeTasksListener] to be notified of updates to active tasks. */ fun addActiveTaskListener(activeTasksListener: ActiveTasksListener) { activeTasksListeners.add(activeTasksListener) @@ -266,12 +323,18 @@ class DesktopModeTaskRepository { desktopTaskDataByDisplayId.getOrCreate(displayId).freeformTasksInZOrder.add(0, taskId) // Unminimize the task if it is minimized. unminimizeTask(displayId, taskId) + if (Flags.enableDesktopWindowingPersistence()) { + updatePersistentRepository(displayId) + } } /** Minimizes the task for [taskId] and [displayId] */ fun minimizeTask(displayId: Int, taskId: Int) { logD("Minimize Task: display=%d, task=%d", displayId, taskId) desktopTaskDataByDisplayId.getOrCreate(displayId).minimizedTasks.add(taskId) + if (Flags.enableDesktopWindowingPersistence()) { + updatePersistentRepository(displayId) + } } /** Unminimizes the task for [taskId] and [displayId] */ @@ -315,7 +378,10 @@ class DesktopModeTaskRepository { // Remove task from unminimized task if it is minimized. unminimizeTask(displayId, taskId) removeActiveTask(taskId) - updateTaskVisibility(displayId, taskId, visible = false); + updateTaskVisibility(displayId, taskId, visible = false) + if (Flags.enableDesktopWindowingPersistence()) { + updatePersistentRepository(displayId) + } } /** @@ -352,6 +418,27 @@ class DesktopModeTaskRepository { fun saveBoundsBeforeMaximize(taskId: Int, bounds: Rect) = boundsBeforeMaximizeByTaskId.set(taskId, Rect(bounds)) + private fun updatePersistentRepository(displayId: Int) { + // Create a deep copy of the data + desktopTaskDataByDisplayId[displayId]?.deepCopy()?.let { desktopTaskDataByDisplayIdCopy -> + mainCoroutineScope.launch { + try { + persistentRepository.addOrUpdateDesktop( + visibleTasks = desktopTaskDataByDisplayIdCopy.visibleTasks, + minimizedTasks = desktopTaskDataByDisplayIdCopy.minimizedTasks, + freeformTasksInZOrder = desktopTaskDataByDisplayIdCopy.freeformTasksInZOrder + ) + } catch (exception: Exception) { + logE( + "An exception occurred while updating the persistent repository \n%s", + exception.stackTrace + ) + } + } + } + } + + internal fun dump(pw: PrintWriter, prefix: String) { val innerPrefix = "$prefix " pw.println("${prefix}DesktopModeTaskRepository") @@ -390,6 +477,10 @@ class DesktopModeTaskRepository { ProtoLog.w(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) } + private fun logE(msg: String, vararg arguments: Any?) { + ProtoLog.e(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + companion object { private const val TAG = "DesktopModeTaskRepository" } 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 f3ae3ed45f41..968f40c3df5d 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 @@ -58,6 +58,7 @@ import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE import com.android.internal.jank.InteractionJankMonitor import com.android.internal.policy.ScreenDecorationsUtils import com.android.internal.protolog.ProtoLog +import com.android.window.flags.Flags import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.common.DisplayController @@ -80,8 +81,8 @@ import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.recents.RecentTasksController import com.android.wm.shell.recents.RecentsTransitionHandler import com.android.wm.shell.recents.RecentsTransitionStateListener -import com.android.wm.shell.shared.TransitionUtil import com.android.wm.shell.shared.ShellSharedConstants +import com.android.wm.shell.shared.TransitionUtil import com.android.wm.shell.shared.annotations.ExternalThread import com.android.wm.shell.shared.annotations.ShellMainThread import android.window.flags.DesktopModeFlags @@ -728,7 +729,7 @@ class DesktopTasksController( // exclude current task since maximize/restore transition has not taken place yet. .filterNot { taskId -> taskId == excludeTaskId } .any { taskId -> - val taskInfo = shellTaskOrganizer.getRunningTaskInfo(taskId)!! + val taskInfo = shellTaskOrganizer.getRunningTaskInfo(taskId) ?: return false val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) val stableBounds = Rect().apply { displayLayout?.getStableBounds(this) } logD("taskInfo = %s", taskInfo) @@ -896,6 +897,7 @@ class DesktopTasksController( val nonMinimizedTasksOrderedFrontToBack = taskRepository.getActiveNonMinimizedOrderedTasks(displayId) // If we're adding a new Task we might need to minimize an old one + // TODO(b/365725441): Handle non running task minimization val taskToMinimize: RunningTaskInfo? = if (newTaskIdInFront != null && desktopTasksLimiter.isPresent) { desktopTasksLimiter @@ -907,12 +909,26 @@ class DesktopTasksController( } else { null } + nonMinimizedTasksOrderedFrontToBack // If there is a Task to minimize, let it stay behind the Home Task .filter { taskId -> taskId != taskToMinimize?.taskId } - .mapNotNull { taskId -> shellTaskOrganizer.getRunningTaskInfo(taskId) } .reversed() // Start from the back so the front task is brought forward last - .forEach { task -> wct.reorder(task.token, /* onTop= */ true) } + .forEach { taskId -> + val runningTaskInfo = shellTaskOrganizer.getRunningTaskInfo(taskId) + if (runningTaskInfo != null) { + // Task is already running, reorder it to the front + wct.reorder(runningTaskInfo.token, /* onTop= */ true) + } else if (Flags.enableDesktopWindowingPersistence()) { + // Task is not running, start it + wct.startTask( + taskId, + ActivityOptions.makeBasic().apply { + launchWindowingMode = WINDOWING_MODE_FREEFORM + }.toBundle(), + ) + } + } taskbarDesktopTaskListener?. onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding(displayId)) @@ -1211,6 +1227,7 @@ class DesktopTasksController( wct.reorder(task.token, true) return wct } + // TODO(b/365723620): Handle non running tasks that were launched after reboot. // 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.ENABLE_CASCADING_WINDOWS.isTrue() diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepository.kt new file mode 100644 index 000000000000..3f41d7cf4e86 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepository.kt @@ -0,0 +1,201 @@ +/* + * 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.persistence + +import android.content.Context +import android.util.ArraySet +import android.util.Log +import android.view.Display.DEFAULT_DISPLAY +import androidx.datastore.core.CorruptionException +import androidx.datastore.core.DataStore +import androidx.datastore.core.DataStoreFactory +import androidx.datastore.core.Serializer +import androidx.datastore.dataStoreFile +import com.android.framework.protobuf.InvalidProtocolBufferException +import com.android.wm.shell.shared.annotations.ShellBackgroundThread +import java.io.IOException +import java.io.InputStream +import java.io.OutputStream +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.first + +/** + * Persistent repository for storing desktop mode related data. + * + * The main constructor is public only for testing purposes. + */ +class DesktopPersistentRepository( + private val dataStore: DataStore<DesktopPersistentRepositories>, +) { + constructor( + context: Context, + @ShellBackgroundThread bgCoroutineScope: CoroutineScope, + ) : this( + DataStoreFactory.create( + serializer = DesktopPersistentRepositoriesSerializer, + produceFile = { context.dataStoreFile(DESKTOP_REPOSITORIES_DATASTORE_FILE) }, + scope = bgCoroutineScope)) + + /** Provides `dataStore.data` flow and handles exceptions thrown during collection */ + private val dataStoreFlow: Flow<DesktopPersistentRepositories> = + dataStore.data.catch { exception -> + // dataStore.data throws an IOException when an error is encountered when reading data + if (exception is IOException) { + Log.e( + TAG, + "Error in reading desktop mode related data from datastore, data is " + + "stored in a file named $DESKTOP_REPOSITORIES_DATASTORE_FILE", + exception) + } else { + throw exception + } + } + + /** + * Reads and returns the [DesktopRepositoryState] proto object from the DataStore for a user. If + * the DataStore is empty or there's an error reading, it returns the default value of Proto. + */ + private suspend fun getDesktopRepositoryState( + userId: Int = DEFAULT_USER_ID + ): DesktopRepositoryState = + try { + dataStoreFlow + .first() + .desktopRepoByUserMap + .getOrDefault(userId, DesktopRepositoryState.getDefaultInstance()) + } catch (e: Exception) { + Log.e(TAG, "Unable to read from datastore", e) + DesktopRepositoryState.getDefaultInstance() + } + + /** + * Reads the [Desktop] of a desktop filtering by the [userId] and [desktopId]. Executes the + * [callback] using the [mainCoroutineScope]. + */ + suspend fun readDesktop( + userId: Int = DEFAULT_USER_ID, + desktopId: Int = DEFAULT_DESKTOP_ID, + ): Desktop = + try { + val repository = getDesktopRepositoryState(userId) + repository.getDesktopOrThrow(desktopId) + } catch (e: Exception) { + Log.e(TAG, "Unable to get desktop info from persistent repository", e) + Desktop.getDefaultInstance() + } + + /** Adds or updates a desktop stored in the datastore */ + suspend fun addOrUpdateDesktop( + userId: Int = DEFAULT_USER_ID, + desktopId: Int = 0, + visibleTasks: ArraySet<Int> = ArraySet(), + minimizedTasks: ArraySet<Int> = ArraySet(), + freeformTasksInZOrder: ArrayList<Int> = ArrayList(), + ) { + // TODO: b/367609270 - Improve the API to support multi-user + try { + dataStore.updateData { desktopPersistentRepositories: DesktopPersistentRepositories -> + val currentRepository = + desktopPersistentRepositories.getDesktopRepoByUserOrDefault( + userId, DesktopRepositoryState.getDefaultInstance()) + val desktop = + getDesktop(currentRepository, desktopId) + .toBuilder() + .updateTaskStates(visibleTasks, minimizedTasks) + .updateZOrder(freeformTasksInZOrder) + + desktopPersistentRepositories + .toBuilder() + .putDesktopRepoByUser( + userId, + currentRepository + .toBuilder() + .putDesktop(desktopId, desktop.build()) + .build()) + .build() + } + } catch (exception: IOException) { + Log.e( + TAG, + "Error in updating desktop mode related data, data is " + + "stored in a file named $DESKTOP_REPOSITORIES_DATASTORE_FILE", + exception) + } + } + + private fun getDesktop(currentRepository: DesktopRepositoryState, desktopId: Int): Desktop = + // If there are no desktops set up, create one on the default display + currentRepository.getDesktopOrDefault( + desktopId, + Desktop.newBuilder().setDesktopId(desktopId).setDisplayId(DEFAULT_DISPLAY).build()) + + companion object { + private const val TAG = "DesktopPersistenceRepo" + private const val DESKTOP_REPOSITORIES_DATASTORE_FILE = "desktop_persistent_repositories.pb" + + private const val DEFAULT_USER_ID = 1000 + private const val DEFAULT_DESKTOP_ID = 0 + + object DesktopPersistentRepositoriesSerializer : Serializer<DesktopPersistentRepositories> { + + override val defaultValue: DesktopPersistentRepositories = + DesktopPersistentRepositories.getDefaultInstance() + + override suspend fun readFrom(input: InputStream): DesktopPersistentRepositories = + try { + DesktopPersistentRepositories.parseFrom(input) + } catch (exception: InvalidProtocolBufferException) { + throw CorruptionException("Cannot read proto.", exception) + } + + override suspend fun writeTo(t: DesktopPersistentRepositories, output: OutputStream) = + t.writeTo(output) + } + + private fun Desktop.Builder.updateTaskStates( + visibleTasks: ArraySet<Int>, + minimizedTasks: ArraySet<Int> + ): Desktop.Builder { + clearTasksByTaskId() + putAllTasksByTaskId( + visibleTasks.associateWith { + createDesktopTask(it, state = DesktopTaskState.VISIBLE) + }) + putAllTasksByTaskId( + minimizedTasks.associateWith { + createDesktopTask(it, state = DesktopTaskState.MINIMIZED) + }) + return this + } + + private fun Desktop.Builder.updateZOrder( + freeformTasksInZOrder: ArrayList<Int> + ): Desktop.Builder { + clearZOrderedTasks() + addAllZOrderedTasks(freeformTasksInZOrder) + return this + } + + private fun createDesktopTask( + taskId: Int, + state: DesktopTaskState = DesktopTaskState.VISIBLE + ): DesktopTask = + DesktopTask.newBuilder().setTaskId(taskId).setDesktopTaskState(state).build() + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/persistent_desktop_repositories.proto b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/persistent_desktop_repositories.proto new file mode 100644 index 000000000000..010523162cec --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/persistent_desktop_repositories.proto @@ -0,0 +1,33 @@ +syntax = "proto2"; + +option java_package = "com.android.wm.shell.desktopmode.persistence"; +option java_multiple_files = true; + +// Represents the state of a task in desktop. +enum DesktopTaskState { + VISIBLE = 0; + MINIMIZED = 1; +} + +message DesktopTask { + optional int32 task_id = 1; + optional DesktopTaskState desktop_task_state= 2; +} + +message Desktop { + optional int32 display_id = 1; + optional int32 desktop_id = 2; + // Stores a mapping between task id and the tasks. The key is the task id. + map<int32, DesktopTask> tasks_by_task_id = 3; + repeated int32 z_ordered_tasks = 4; +} + +message DesktopRepositoryState { + // Stores a mapping between a repository and the desktops in it. The key is the desktop id. + map<int32, Desktop> desktop = 1; +} + +message DesktopPersistentRepositories { + // Stores a mapping between a user and their desktop repository. The key is the user id. + map<int32, DesktopRepositoryState> desktop_repo_by_user = 1; +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index 1573291aef63..f40e0bac1b4e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -358,12 +358,9 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { if (mode == TRANSIT_CHANGE && change.hasFlags(FLAG_IS_DISPLAY)) { if (info.getType() == TRANSIT_CHANGE) { - int anim = getRotationAnimationHint(change, info, mDisplayController); + final int anim = getRotationAnimationHint(change, info, mDisplayController); isSeamlessDisplayChange = anim == ROTATION_ANIMATION_SEAMLESS; if (!(isSeamlessDisplayChange || anim == ROTATION_ANIMATION_JUMPCUT)) { - if (wallpaperTransit != WALLPAPER_TRANSITION_NONE) { - anim |= ScreenRotationAnimation.ANIMATION_HINT_HAS_WALLPAPER; - } startRotationAnimation(startTransaction, change, info, anim, animations, onAnimFinish); isDisplayRotationAnimationStarted = true; @@ -829,26 +826,24 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { @NonNull Runnable finishCallback, @NonNull TransactionPool pool, @NonNull ShellExecutor mainExecutor, @Nullable Point position, float cornerRadius, @Nullable Rect clipRect, boolean isActivity) { - final DefaultAnimationAdapter adapter = new DefaultAnimationAdapter(anim, leash, - position, clipRect, cornerRadius, isActivity); - buildSurfaceAnimation(animations, anim, finishCallback, pool, mainExecutor, adapter); - } - - /** Builds an animator for the surface and adds it to the `animations` list. */ - static void buildSurfaceAnimation(@NonNull ArrayList<Animator> animations, - @NonNull Animation anim, @NonNull Runnable finishCallback, - @NonNull TransactionPool pool, @NonNull ShellExecutor mainExecutor, - @NonNull AnimationAdapter updateListener) { final SurfaceControl.Transaction transaction = pool.acquire(); - updateListener.setTransaction(transaction); final ValueAnimator va = ValueAnimator.ofFloat(0f, 1f); + final Transformation transformation = new Transformation(); + final float[] matrix = new float[9]; // Animation length is already expected to be scaled. va.overrideDurationScale(1.0f); va.setDuration(anim.computeDurationHint()); + final ValueAnimator.AnimatorUpdateListener updateListener = animation -> { + final long currentPlayTime = Math.min(va.getDuration(), va.getCurrentPlayTime()); + + applyTransformation(currentPlayTime, transaction, leash, anim, transformation, matrix, + position, cornerRadius, clipRect, isActivity); + }; va.addUpdateListener(updateListener); final Runnable finisher = () -> { - updateListener.onAnimationUpdate(va); + applyTransformation(va.getDuration(), transaction, leash, anim, transformation, matrix, + position, cornerRadius, clipRect, isActivity); pool.release(transaction); mainExecutor.execute(() -> { @@ -1012,88 +1007,37 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { || animType == ANIM_FROM_STYLE; } - /** The animation adapter for buildSurfaceAnimation. */ - abstract static class AnimationAdapter implements ValueAnimator.AnimatorUpdateListener { - @NonNull final SurfaceControl mLeash; - @NonNull SurfaceControl.Transaction mTransaction; - private Choreographer mChoreographer; - - AnimationAdapter(@NonNull SurfaceControl leash) { - mLeash = leash; + private static void applyTransformation(long time, SurfaceControl.Transaction t, + SurfaceControl leash, Animation anim, Transformation tmpTransformation, float[] matrix, + Point position, float cornerRadius, @Nullable Rect immutableClipRect, + boolean isActivity) { + tmpTransformation.clear(); + anim.getTransformation(time, tmpTransformation); + if (com.android.graphics.libgui.flags.Flags.edgeExtensionShader() + && anim.getExtensionEdges() != 0x0 && isActivity) { + t.setEdgeExtensionEffect(leash, anim.getExtensionEdges()); } - - void setTransaction(@NonNull SurfaceControl.Transaction transaction) { - mTransaction = transaction; + if (position != null) { + tmpTransformation.getMatrix().postTranslate(position.x, position.y); } - - @Override - public void onAnimationUpdate(@NonNull ValueAnimator animator) { - applyTransformation(animator); - if (mChoreographer == null) { - mChoreographer = Choreographer.getInstance(); - } - mTransaction.setFrameTimelineVsync(mChoreographer.getVsyncId()); - mTransaction.apply(); + t.setMatrix(leash, tmpTransformation.getMatrix(), matrix); + t.setAlpha(leash, tmpTransformation.getAlpha()); + + final Rect clipRect = immutableClipRect == null ? null : new Rect(immutableClipRect); + Insets extensionInsets = Insets.min(tmpTransformation.getInsets(), Insets.NONE); + if (!extensionInsets.equals(Insets.NONE) && clipRect != null && !clipRect.isEmpty()) { + // Clip out any overflowing edge extension + clipRect.inset(extensionInsets); + t.setCrop(leash, clipRect); } - abstract void applyTransformation(@NonNull ValueAnimator animator); - } - - private static class DefaultAnimationAdapter extends AnimationAdapter { - final Transformation mTransformation = new Transformation(); - final float[] mMatrix = new float[9]; - @NonNull final Animation mAnim; - @Nullable final Point mPosition; - @Nullable final Rect mClipRect; - final float mCornerRadius; - final boolean mIsActivity; - - DefaultAnimationAdapter(@NonNull Animation anim, @NonNull SurfaceControl leash, - @Nullable Point position, @Nullable Rect clipRect, float cornerRadius, - boolean isActivity) { - super(leash); - mAnim = anim; - mPosition = (position != null && (position.x != 0 || position.y != 0)) - ? position : null; - mClipRect = (clipRect != null && !clipRect.isEmpty()) ? clipRect : null; - mCornerRadius = cornerRadius; - mIsActivity = isActivity; + if (anim.hasRoundedCorners() && cornerRadius > 0 && clipRect != null) { + // We can only apply rounded corner if a crop is set + t.setCrop(leash, clipRect); + t.setCornerRadius(leash, cornerRadius); } - @Override - void applyTransformation(@NonNull ValueAnimator animator) { - final long currentPlayTime = Math.min(animator.getDuration(), - animator.getCurrentPlayTime()); - final Transformation transformation = mTransformation; - final SurfaceControl.Transaction t = mTransaction; - final SurfaceControl leash = mLeash; - transformation.clear(); - mAnim.getTransformation(currentPlayTime, transformation); - if (com.android.graphics.libgui.flags.Flags.edgeExtensionShader() - && mIsActivity && mAnim.getExtensionEdges() != 0) { - t.setEdgeExtensionEffect(leash, mAnim.getExtensionEdges()); - } - if (mPosition != null) { - transformation.getMatrix().postTranslate(mPosition.x, mPosition.y); - } - t.setMatrix(leash, transformation.getMatrix(), mMatrix); - t.setAlpha(leash, transformation.getAlpha()); - - if (mClipRect != null) { - Rect clipRect = mClipRect; - final Insets extensionInsets = Insets.min(transformation.getInsets(), Insets.NONE); - if (!extensionInsets.equals(Insets.NONE)) { - // Clip out any overflowing edge extension. - clipRect = new Rect(mClipRect); - clipRect.inset(extensionInsets); - t.setCrop(leash, clipRect); - } - if (mCornerRadius > 0 && mAnim.hasRoundedCorners()) { - // Rounded corner can only be applied if a crop is set. - t.setCrop(leash, clipRect); - t.setCornerRadius(leash, mCornerRadius); - } - } - } + t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId()); + t.apply(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java index b9d11a3d0c06..5802e2ca8133 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java @@ -25,9 +25,12 @@ import static com.android.wm.shell.transition.DefaultTransitionHandler.buildSurf import static com.android.wm.shell.transition.Transitions.TAG; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ArgbEvaluator; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.content.Context; +import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Rect; import android.hardware.HardwareBuffer; @@ -35,7 +38,6 @@ import android.util.Slog; import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; -import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.window.ScreenCapture; @@ -72,9 +74,6 @@ import java.util.ArrayList; */ class ScreenRotationAnimation { static final int MAX_ANIMATION_DURATION = 10 * 1000; - static final int ANIMATION_HINT_HAS_WALLPAPER = 1 << 8; - /** It must cover all WindowManager#ROTATION_ANIMATION_*. */ - private static final int ANIMATION_TYPE_MASK = 0xff; private final Context mContext; private final TransactionPool mTransactionPool; @@ -82,7 +81,7 @@ class ScreenRotationAnimation { /** The leash of the changing window container. */ private final SurfaceControl mSurfaceControl; - private final int mAnimType; + private final int mAnimHint; private final int mStartWidth; private final int mStartHeight; private final int mEndWidth; @@ -99,12 +98,6 @@ class ScreenRotationAnimation { private SurfaceControl mBackColorSurface; /** The leash using to animate screenshot layer. */ private final SurfaceControl mAnimLeash; - /** - * The container with background color for {@link #mSurfaceControl}. It is only created if - * {@link #mSurfaceControl} may be translucent. E.g. visible wallpaper with alpha < 1 (dimmed). - * That prevents flickering of alpha blending. - */ - private SurfaceControl mBackEffectSurface; // The current active animation to move from the old to the new rotated // state. Which animation is run here will depend on the old and new @@ -122,7 +115,7 @@ class ScreenRotationAnimation { Transaction t, TransitionInfo.Change change, SurfaceControl rootLeash, int animHint) { mContext = context; mTransactionPool = pool; - mAnimType = animHint & ANIMATION_TYPE_MASK; + mAnimHint = animHint; mSurfaceControl = change.getLeash(); mStartWidth = change.getStartAbsBounds().width(); @@ -177,20 +170,11 @@ class ScreenRotationAnimation { } hardwareBuffer.close(); } - if ((animHint & ANIMATION_HINT_HAS_WALLPAPER) != 0) { - mBackEffectSurface = new SurfaceControl.Builder() - .setCallsite("ShellRotationAnimation").setParent(rootLeash) - .setEffectLayer().setOpaque(true).setName("BackEffect").build(); - t.reparent(mSurfaceControl, mBackEffectSurface) - .setColor(mBackEffectSurface, - new float[] {mStartLuma, mStartLuma, mStartLuma}) - .show(mBackEffectSurface); - } t.setLayer(mAnimLeash, SCREEN_FREEZE_LAYER_BASE); t.show(mAnimLeash); // Crop the real content in case it contains a larger child layer, e.g. wallpaper. - t.setCrop(getEnterSurface(), new Rect(0, 0, mEndWidth, mEndHeight)); + t.setCrop(mSurfaceControl, new Rect(0, 0, mEndWidth, mEndHeight)); if (!isCustomRotate()) { mBackColorSurface = new SurfaceControl.Builder() @@ -215,12 +199,7 @@ class ScreenRotationAnimation { } private boolean isCustomRotate() { - return mAnimType == ROTATION_ANIMATION_CROSSFADE || mAnimType == ROTATION_ANIMATION_JUMPCUT; - } - - /** Returns the surface which contains the real content to animate enter. */ - private SurfaceControl getEnterSurface() { - return mBackEffectSurface != null ? mBackEffectSurface : mSurfaceControl; + return mAnimHint == ROTATION_ANIMATION_CROSSFADE || mAnimHint == ROTATION_ANIMATION_JUMPCUT; } private void setScreenshotTransform(SurfaceControl.Transaction t) { @@ -281,7 +260,7 @@ class ScreenRotationAnimation { final boolean customRotate = isCustomRotate(); if (customRotate) { mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, - mAnimType == ROTATION_ANIMATION_JUMPCUT ? R.anim.rotation_animation_jump_exit + mAnimHint == ROTATION_ANIMATION_JUMPCUT ? R.anim.rotation_animation_jump_exit : R.anim.rotation_animation_xfade_exit); mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, R.anim.rotation_animation_enter); @@ -335,11 +314,7 @@ class ScreenRotationAnimation { } else { startDisplayRotation(animations, finishCallback, mainExecutor); startScreenshotRotationAnimation(animations, finishCallback, mainExecutor); - if (mBackEffectSurface != null && mStartLuma > 0.1f) { - // Animate from the color of background to black for smooth alpha blending. - buildLumaAnimation(animations, mStartLuma, 0f /* endLuma */, mBackEffectSurface, - animationScale, finishCallback, mainExecutor); - } + //startColorAnimation(mTransaction, animationScale); } return true; @@ -347,7 +322,7 @@ class ScreenRotationAnimation { private void startDisplayRotation(@NonNull ArrayList<Animator> animations, @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) { - buildSurfaceAnimation(animations, mRotateEnterAnimation, getEnterSurface(), finishCallback, + buildSurfaceAnimation(animations, mRotateEnterAnimation, mSurfaceControl, finishCallback, mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */, null /* clipRect */, false /* isActivity */); } @@ -366,17 +341,40 @@ class ScreenRotationAnimation { null /* clipRect */, false /* isActivity */); } - private void buildLumaAnimation(@NonNull ArrayList<Animator> animations, - float startLuma, float endLuma, SurfaceControl surface, float animationScale, - @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) { - final long durationMillis = (long) (mContext.getResources().getInteger( - R.integer.config_screen_rotation_color_transition) * animationScale); - final LumaAnimation animation = new LumaAnimation(durationMillis); - // Align the end with the enter animation. - animation.setStartOffset(mRotateEnterAnimation.getDuration() - durationMillis); - final LumaAnimationAdapter adapter = new LumaAnimationAdapter(surface, startLuma, endLuma); - buildSurfaceAnimation(animations, animation, finishCallback, mTransactionPool, - mainExecutor, adapter); + private void startColorAnimation(float animationScale, @NonNull ShellExecutor animExecutor) { + int colorTransitionMs = mContext.getResources().getInteger( + R.integer.config_screen_rotation_color_transition); + final float[] rgbTmpFloat = new float[3]; + final int startColor = Color.rgb(mStartLuma, mStartLuma, mStartLuma); + final int endColor = Color.rgb(mEndLuma, mEndLuma, mEndLuma); + final long duration = colorTransitionMs * (long) animationScale; + final Transaction t = mTransactionPool.acquire(); + + final ValueAnimator va = ValueAnimator.ofFloat(0f, 1f); + // Animation length is already expected to be scaled. + va.overrideDurationScale(1.0f); + va.setDuration(duration); + va.addUpdateListener(animation -> { + final long currentPlayTime = Math.min(va.getDuration(), va.getCurrentPlayTime()); + final float fraction = currentPlayTime / va.getDuration(); + applyColor(startColor, endColor, rgbTmpFloat, fraction, mBackColorSurface, t); + }); + va.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationCancel(Animator animation) { + applyColor(startColor, endColor, rgbTmpFloat, 1f /* fraction */, mBackColorSurface, + t); + mTransactionPool.release(t); + } + + @Override + public void onAnimationEnd(Animator animation) { + applyColor(startColor, endColor, rgbTmpFloat, 1f /* fraction */, mBackColorSurface, + t); + mTransactionPool.release(t); + } + }); + animExecutor.execute(va::start); } public void kill() { @@ -391,47 +389,21 @@ class ScreenRotationAnimation { if (mBackColorSurface != null && mBackColorSurface.isValid()) { t.remove(mBackColorSurface); } - if (mBackEffectSurface != null && mBackEffectSurface.isValid()) { - t.remove(mBackEffectSurface); - } t.apply(); mTransactionPool.release(t); } - /** A no-op wrapper to provide animation duration. */ - private static class LumaAnimation extends Animation { - LumaAnimation(long durationMillis) { - setDuration(durationMillis); - } - } - - private static class LumaAnimationAdapter extends DefaultTransitionHandler.AnimationAdapter { - final float[] mColorArray = new float[3]; - final float mStartLuma; - final float mEndLuma; - final AccelerateInterpolator mInterpolation; - - LumaAnimationAdapter(@NonNull SurfaceControl leash, float startLuma, float endLuma) { - super(leash); - mStartLuma = startLuma; - mEndLuma = endLuma; - // Make the initial progress color lighter if the background is light. That avoids - // darker content when fading into the entering surface. - final float factor = Math.min(3f, (Math.max(0.5f, mStartLuma) - 0.5f) * 10); - Slog.d(TAG, "Luma=" + mStartLuma + " factor=" + factor); - mInterpolation = factor > 0.5f ? new AccelerateInterpolator(factor) : null; - } - - @Override - void applyTransformation(ValueAnimator animator) { - final float fraction = mInterpolation != null - ? mInterpolation.getInterpolation(animator.getAnimatedFraction()) - : animator.getAnimatedFraction(); - final float luma = mStartLuma + fraction * (mEndLuma - mStartLuma); - mColorArray[0] = luma; - mColorArray[1] = luma; - mColorArray[2] = luma; - mTransaction.setColor(mLeash, mColorArray); + private static void applyColor(int startColor, int endColor, float[] rgbFloat, + float fraction, SurfaceControl surface, SurfaceControl.Transaction t) { + final int color = (Integer) ArgbEvaluator.getInstance().evaluate(fraction, startColor, + endColor); + Color middleColor = Color.valueOf(color); + rgbFloat[0] = middleColor.red(); + rgbFloat[1] = middleColor.green(); + rgbFloat[2] = middleColor.blue(); + if (surface.isValid()) { + t.setColor(surface, rgbFloat); } + t.apply(); } } 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 431461a27e6f..f5b2340b87a7 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 @@ -63,7 +63,6 @@ import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.windowdecor.extension.TaskInfoKt; -import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier; /** * View model for the window decoration with a caption and shadows. Works with @@ -85,7 +84,6 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { private final Transitions mTransitions; private final Region mExclusionRegion = Region.obtain(); private final InputManager mInputManager; - private final WindowDecorViewHostSupplier mWindowDecorViewHostSupplier; private TaskOperations mTaskOperations; /** @@ -123,8 +121,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { DisplayController displayController, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, SyncTransactionQueue syncQueue, - Transitions transitions, - WindowDecorViewHostSupplier windowDecorViewHostSupplier) { + Transitions transitions) { mContext = context; mMainExecutor = shellExecutor; mMainHandler = mainHandler; @@ -136,7 +133,6 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; mSyncQueue = syncQueue; mTransitions = transitions; - mWindowDecorViewHostSupplier = windowDecorViewHostSupplier; if (!Transitions.ENABLE_SHELL_TRANSITIONS) { mTaskOperations = new TaskOperations(null, mContext, mSyncQueue); } @@ -300,8 +296,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { mMainHandler, mBgExecutor, mMainChoreographer, - mSyncQueue, - mWindowDecorViewHostSupplier); + mSyncQueue); mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration); final FluidResizeTaskPositioner taskPositioner = 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 d0eba23f7d45..05065be7171c 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 @@ -58,7 +58,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.windowdecor.extension.TaskInfoKt; -import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier; /** * Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with @@ -90,10 +89,8 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL Handler handler, @ShellBackgroundThread ShellExecutor bgExecutor, Choreographer choreographer, - SyncTransactionQueue syncQueue, - WindowDecorViewHostSupplier windowDecorViewHostSupplier) { - super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface, - windowDecorViewHostSupplier); + SyncTransactionQueue syncQueue) { + super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface); mHandler = handler; mBgExecutor = bgExecutor; mChoreographer = choreographer; 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 c59d92912e80..272508f46d33 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 @@ -130,7 +130,6 @@ import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionReg import com.android.wm.shell.windowdecor.extension.InsetsStateKt; import com.android.wm.shell.windowdecor.extension.TaskInfoKt; import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder; -import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier; import kotlin.Pair; import kotlin.Unit; @@ -169,7 +168,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private final WindowDecorCaptionHandleRepository mWindowDecorCaptionHandleRepository; private final Optional<DesktopTasksLimiter> mDesktopTasksLimiter; private final AppHeaderViewHolder.Factory mAppHeaderViewHolderFactory; - private final WindowDecorViewHostSupplier mWindowDecorViewHostSupplier; private boolean mTransitionDragActive; private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>(); @@ -239,8 +237,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { MultiInstanceHelper multiInstanceHelper, Optional<DesktopTasksLimiter> desktopTasksLimiter, WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository, - Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler, - WindowDecorViewHostSupplier windowDecorViewHostSupplier) { + Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler) { this( context, shellExecutor, @@ -260,7 +257,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { genericLinksParser, assistContentRequester, multiInstanceHelper, - windowDecorViewHostSupplier, new DesktopModeWindowDecoration.Factory(), new InputMonitorFactory(), SurfaceControl.Transaction::new, @@ -294,7 +290,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { AppToWebGenericLinksParser genericLinksParser, AssistContentRequester assistContentRequester, MultiInstanceHelper multiInstanceHelper, - WindowDecorViewHostSupplier windowDecorViewHostSupplier, DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory, InputMonitorFactory inputMonitorFactory, Supplier<SurfaceControl.Transaction> transactionFactory, @@ -322,7 +317,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mMultiInstanceHelper = multiInstanceHelper; mShellCommandHandler = shellCommandHandler; mWindowManager = windowManager; - mWindowDecorViewHostSupplier = windowDecorViewHostSupplier; mDesktopModeWindowDecorFactory = desktopModeWindowDecorFactory; mInputMonitorFactory = inputMonitorFactory; mTransactionFactory = transactionFactory; @@ -1412,8 +1406,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mGenericLinksParser, mAssistContentRequester, mMultiInstanceHelper, - mWindowDecorCaptionHandleRepository, - mWindowDecorViewHostSupplier); + mWindowDecorCaptionHandleRepository); mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration); final TaskPositioner taskPositioner = mTaskPositionerFactory.create( 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 b63f82bfacd3..8a53f5ba4a51 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 @@ -38,6 +38,7 @@ import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getResiz import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.WindowConfiguration.WindowingMode; import android.app.assist.AssistContent; @@ -98,7 +99,6 @@ import com.android.wm.shell.windowdecor.extension.TaskInfoKt; import com.android.wm.shell.windowdecor.viewholder.AppHandleViewHolder; import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder; import com.android.wm.shell.windowdecor.viewholder.WindowDecorationViewHolder; -import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier; import kotlin.Pair; import kotlin.Unit; @@ -144,9 +144,12 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private Function0<Unit> mOnManageWindowsClickListener; private DragPositioningCallback mDragPositioningCallback; private DragResizeInputListener mDragResizeListener; + private Runnable mCurrentViewHostRunnable = null; private RelayoutParams mRelayoutParams = new RelayoutParams(); private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult = new WindowDecoration.RelayoutResult<>(); + private final Runnable mViewHostRunnable = + () -> updateViewHost(mRelayoutParams, null /* onDrawTransaction */, mResult); private final Point mPositionInParent = new Point(); private HandleMenu mHandleMenu; @@ -203,8 +206,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin AppToWebGenericLinksParser genericLinksParser, AssistContentRequester assistContentRequester, MultiInstanceHelper multiInstanceHelper, - WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository, - WindowDecorViewHostSupplier windowDecorViewHostSupplier) { + WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository) { this (context, userContext, displayController, splitScreenController, taskOrganizer, taskInfo, taskSurface, handler, bgExecutor, choreographer, syncQueue, appHeaderViewHolderFactory, rootTaskDisplayAreaOrganizer, genericLinksParser, @@ -212,7 +214,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin SurfaceControl.Builder::new, SurfaceControl.Transaction::new, WindowContainerTransaction::new, SurfaceControl::new, new WindowManagerWrapper( context.getSystemService(WindowManager.class)), - new SurfaceControlViewHostFactory() {}, windowDecorViewHostSupplier, + new SurfaceControlViewHostFactory() {}, DefaultMaximizeMenuFactory.INSTANCE, DefaultHandleMenuFactory.INSTANCE, multiInstanceHelper, windowDecorCaptionHandleRepository); @@ -240,7 +242,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin Supplier<SurfaceControl> surfaceControlSupplier, WindowManagerWrapper windowManagerWrapper, SurfaceControlViewHostFactory surfaceControlViewHostFactory, - WindowDecorViewHostSupplier windowDecorViewHostSupplier, MaximizeMenuFactory maximizeMenuFactory, HandleMenuFactory handleMenuFactory, MultiInstanceHelper multiInstanceHelper, @@ -248,7 +249,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface, surfaceControlBuilderSupplier, surfaceControlTransactionSupplier, windowContainerTransactionSupplier, surfaceControlSupplier, - surfaceControlViewHostFactory, windowDecorViewHostSupplier); + surfaceControlViewHostFactory); mSplitScreenController = splitScreenController; mHandler = handler; mBgExecutor = bgExecutor; @@ -362,6 +363,73 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) { Trace.beginSection("DesktopModeWindowDecoration#relayout"); + if (taskInfo.isFreeform()) { + // The Task is in Freeform mode -> show its header in sync since it's an integral part + // of the window itself - a delayed header might cause bad UX. + relayoutInSync(taskInfo, startT, finishT, applyStartTransactionOnDraw, + shouldSetTaskPositionAndCrop); + } else { + // The Task is outside Freeform mode -> allow the handle view to be delayed since the + // handle is just a small addition to the window. + relayoutWithDelayedViewHost(taskInfo, startT, finishT, applyStartTransactionOnDraw, + shouldSetTaskPositionAndCrop); + } + Trace.endSection(); + } + + /** Run the whole relayout phase immediately without delay. */ + private void relayoutInSync(ActivityManager.RunningTaskInfo taskInfo, + SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, + boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) { + // Clear the current ViewHost runnable as we will update the ViewHost here + clearCurrentViewHostRunnable(); + updateRelayoutParamsAndSurfaces(taskInfo, startT, finishT, applyStartTransactionOnDraw, + shouldSetTaskPositionAndCrop); + if (mResult.mRootView != null) { + updateViewHost(mRelayoutParams, startT, mResult); + } + } + + /** + * Clear the current ViewHost runnable - to ensure it doesn't run once relayout params have been + * updated. + */ + private void clearCurrentViewHostRunnable() { + if (mCurrentViewHostRunnable != null) { + mHandler.removeCallbacks(mCurrentViewHostRunnable); + mCurrentViewHostRunnable = null; + } + } + + /** + * Relayout the window decoration but repost some of the work, to unblock the current callstack. + */ + private void relayoutWithDelayedViewHost(ActivityManager.RunningTaskInfo taskInfo, + SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, + boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) { + if (applyStartTransactionOnDraw) { + throw new IllegalArgumentException( + "We cannot both sync viewhost ondraw and delay viewhost creation."); + } + // Clear the current ViewHost runnable as we will update the ViewHost here + clearCurrentViewHostRunnable(); + updateRelayoutParamsAndSurfaces(taskInfo, startT, finishT, + false /* applyStartTransactionOnDraw */, shouldSetTaskPositionAndCrop); + 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. + return; + } + // Store the current runnable so it can be removed if we start a new relayout. + mCurrentViewHostRunnable = mViewHostRunnable; + mHandler.post(mCurrentViewHostRunnable); + } + + @SuppressLint("MissingPermission") + private void updateRelayoutParamsAndSurfaces(ActivityManager.RunningTaskInfo taskInfo, + SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, + boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) { + Trace.beginSection("DesktopModeWindowDecoration#updateRelayoutParamsAndSurfaces"); if (Flags.enableDesktopWindowingAppToWeb()) { setCapturedLink(taskInfo.capturedLink, taskInfo.capturedLinkTimestamp); @@ -378,8 +446,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final SurfaceControl oldDecorationSurface = mDecorationContainerSurface; final WindowContainerTransaction wct = new WindowContainerTransaction(); - Trace.beginSection("DesktopModeWindowDecoration#relayout-inner"); - relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult); + Trace.beginSection("DesktopModeWindowDecoration#relayout-updateViewsAndSurfaces"); + updateViewsAndSurfaces(mRelayoutParams, startT, finishT, wct, oldRootView, mResult); Trace.endSection(); // After this line, mTaskInfo is up-to-date and should be used instead of taskInfo @@ -394,7 +462,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin notifyNoCaptionHandle(); } disposeStatusBarInputLayer(); - Trace.endSection(); // DesktopModeWindowDecoration#relayout + Trace.endSection(); // DesktopModeWindowDecoration#updateRelayoutParamsAndSurfaces return; } @@ -402,12 +470,12 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin disposeStatusBarInputLayer(); mWindowDecorViewHolder = createViewHolder(); } + Trace.beginSection("DesktopModeWindowDecoration#relayout-binding"); final Point position = new Point(); if (isAppHandle(mWindowDecorViewHolder)) { position.set(determineHandlePosition()); } - Trace.beginSection("DesktopModeWindowDecoration#relayout-bindData"); if (canEnterDesktopMode(mContext) && Flags.enableDesktopWindowingAppHandleEducation()) { notifyCaptionStateChanged(); } @@ -425,7 +493,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } updateDragResizeListener(oldDecorationSurface); updateMaximizeMenu(startT); - Trace.endSection(); // DesktopModeWindowDecoration#relayout + Trace.endSection(); // DesktopModeWindowDecoration#updateRelayoutParamsAndSurfaces } private boolean isCaptionVisible() { @@ -610,7 +678,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin || !Flags.enableHandleInputFix()) { return; } - ((AppHandleViewHolder) mWindowDecorViewHolder).disposeStatusBarInputLayer(); + asAppHandle(mWindowDecorViewHolder).disposeStatusBarInputLayer(); } private WindowDecorationViewHolder createViewHolder() { @@ -647,6 +715,22 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin return viewHolder instanceof AppHandleViewHolder; } + @Nullable + private AppHandleViewHolder asAppHandle(WindowDecorationViewHolder viewHolder) { + if (viewHolder instanceof AppHandleViewHolder) { + return (AppHandleViewHolder) viewHolder; + } + return null; + } + + @Nullable + private AppHeaderViewHolder asAppHeader(WindowDecorationViewHolder viewHolder) { + if (viewHolder instanceof AppHeaderViewHolder) { + return (AppHeaderViewHolder) viewHolder; + } + return null; + } + @VisibleForTesting static void updateRelayoutParams( RelayoutParams relayoutParams, @@ -663,10 +747,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin relayoutParams.mLayoutResId = captionLayoutId; relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode()); relayoutParams.mCaptionWidthId = getCaptionWidthId(relayoutParams.mLayoutResId); - // Allow the handle view to be delayed since the handle is just a small addition to the - // window, whereas the header cannot be delayed because it is expected to be visible from - // the first frame. - relayoutParams.mAsyncViewHost = isAppHandle; if (isAppHeader) { if (TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo)) { @@ -1025,7 +1105,15 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin */ void closeMaximizeMenu() { if (!isMaximizeMenuActive()) return; - mMaximizeMenu.close(); + mMaximizeMenu.close(() -> { + // Request the accessibility service to refocus on the maximize button after closing + // the menu. + final AppHeaderViewHolder appHeader = asAppHeader(mWindowDecorViewHolder); + if (appHeader != null) { + appHeader.requestAccessibilityFocus(); + } + return Unit.INSTANCE; + }); mMaximizeMenu = null; } @@ -1053,7 +1141,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin loadAppInfoIfNeeded(); updateGenericLink(); final boolean supportsMultiInstance = mMultiInstanceHelper - .supportsMultiInstanceSplit(mTaskInfo.baseActivity); + .supportsMultiInstanceSplit(mTaskInfo.baseActivity) + && Flags.enableDesktopWindowingMultiInstanceFeatures(); final boolean shouldShowManageWindowsButton = supportsMultiInstance && mMinimumInstancesFound; mHandleMenu = mHandleMenuFactory.create( @@ -1340,10 +1429,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mExclusionRegionListener.onExclusionRegionDismissed(mTaskInfo.taskId); disposeResizeVeil(); disposeStatusBarInputLayer(); + clearCurrentViewHostRunnable(); if (canEnterDesktopMode(mContext) && Flags.enableDesktopWindowingAppHandleEducation()) { notifyNoCaptionHandle(); } - super.close(); } @@ -1370,7 +1459,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin */ private Region getGlobalExclusionRegion() { Region exclusionRegion; - if (mDragResizeListener != null && mTaskInfo.isResizeable) { + if (mDragResizeListener != null && isDragResizable(mTaskInfo)) { exclusionRegion = mDragResizeListener.getCornersRegion(); } else { exclusionRegion = new Region(); @@ -1407,7 +1496,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin void setAnimatingTaskResizeOrReposition(boolean animatingTaskResizeOrReposition) { if (mRelayoutParams.mLayoutResId == R.layout.desktop_mode_app_handle) return; - ((AppHeaderViewHolder) mWindowDecorViewHolder) + asAppHeader(mWindowDecorViewHolder) .setAnimatingTaskResizeOrReposition(animatingTaskResizeOrReposition); } @@ -1415,16 +1504,14 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin * Called when there is a {@link MotionEvent#ACTION_HOVER_EXIT} on the maximize window button. */ void onMaximizeButtonHoverExit() { - ((AppHeaderViewHolder) mWindowDecorViewHolder) - .onMaximizeWindowHoverExit(); + asAppHeader(mWindowDecorViewHolder).onMaximizeWindowHoverExit(); } /** * Called when there is a {@link MotionEvent#ACTION_HOVER_ENTER} on the maximize window button. */ void onMaximizeButtonHoverEnter() { - ((AppHeaderViewHolder) mWindowDecorViewHolder) - .onMaximizeWindowHoverEnter(); + asAppHeader(mWindowDecorViewHolder).onMaximizeWindowHoverEnter(); } @Override @@ -1456,8 +1543,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin AppToWebGenericLinksParser genericLinksParser, AssistContentRequester assistContentRequester, MultiInstanceHelper multiInstanceHelper, - WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository, - WindowDecorViewHostSupplier windowDecorViewHostSupplier) { + WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository) { return new DesktopModeWindowDecoration( context, userContext, @@ -1475,8 +1561,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin genericLinksParser, assistContentRequester, multiInstanceHelper, - windowDecorCaptionHandleRepository, - windowDecorViewHostSupplier); + windowDecorCaptionHandleRepository); } } 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 5b3f26318825..9a5b4f54dd36 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 @@ -23,8 +23,6 @@ import android.content.Context import android.content.res.ColorStateList import android.content.res.Resources import android.graphics.Bitmap -import android.graphics.BlendMode -import android.graphics.BlendModeColorFilter import android.graphics.Point import android.graphics.PointF import android.graphics.Rect @@ -568,9 +566,7 @@ class HandleMenu( appIconBitmap: Bitmap?, appName: CharSequence? ) { - appInfoPill.background.colorFilter = BlendModeColorFilter( - style.backgroundColor, BlendMode.MULTIPLY - ) + appInfoPill.background.setTint(style.backgroundColor) collapseMenuButton.apply { imageTintList = ColorStateList.valueOf(style.textColor) @@ -584,9 +580,7 @@ class HandleMenu( } private fun bindWindowingPill(style: MenuStyle) { - windowingPill.background.colorFilter = BlendModeColorFilter( - style.backgroundColor, BlendMode.MULTIPLY - ) + windowingPill.background.setTint(style.backgroundColor) // TODO: Remove once implemented. floatingBtn.visibility = View.GONE @@ -612,23 +606,19 @@ class HandleMenu( } screenshotBtn.apply { isGone = !SHOULD_SHOW_SCREENSHOT_BUTTON - background.colorFilter = - BlendModeColorFilter(style.backgroundColor, BlendMode.MULTIPLY - ) + background.setTint(style.backgroundColor) setTextColor(style.textColor) compoundDrawableTintList = ColorStateList.valueOf(style.textColor) } newWindowBtn.apply { isGone = !shouldShowNewWindowButton - background.colorFilter = - BlendModeColorFilter(style.backgroundColor, BlendMode.MULTIPLY) + background.setTint(style.backgroundColor) setTextColor(style.textColor) compoundDrawableTintList = ColorStateList.valueOf(style.textColor) } manageWindowBtn.apply { isGone = !shouldShowManageWindowsButton - background.colorFilter = - BlendModeColorFilter(style.backgroundColor, BlendMode.MULTIPLY) + background.setTint(style.backgroundColor) setTextColor(style.textColor) compoundDrawableTintList = ColorStateList.valueOf(style.textColor) } @@ -637,9 +627,7 @@ class HandleMenu( private fun bindOpenInBrowserPill(style: MenuStyle) { openInBrowserPill.apply { isGone = !shouldShowBrowserPill - background.colorFilter = BlendModeColorFilter( - style.backgroundColor, BlendMode.MULTIPLY - ) + background.setTint(style.backgroundColor) } browserBtn.apply { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt index 9590ccdc3b97..0c475f12f53b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt @@ -26,6 +26,7 @@ import android.view.View.SCALE_Y import android.view.View.TRANSLATION_Y import android.view.View.TRANSLATION_Z import android.view.ViewGroup +import android.view.accessibility.AccessibilityEvent import android.widget.Button import androidx.core.animation.doOnEnd import androidx.core.view.children @@ -83,7 +84,12 @@ class HandleMenuAnimator( animateWindowingPillOpen() animateMoreActionsPillOpen() animateOpenInBrowserPill() - runAnimations() + runAnimations { + appInfoPill.post { + appInfoPill.requireViewById<View>(R.id.collapse_menu_button).sendAccessibilityEvent( + AccessibilityEvent.TYPE_VIEW_FOCUSED) + } + } } /** @@ -98,7 +104,12 @@ class HandleMenuAnimator( animateWindowingPillOpen() animateMoreActionsPillOpen() animateOpenInBrowserPill() - runAnimations() + runAnimations { + appInfoPill.post { + appInfoPill.requireViewById<View>(R.id.collapse_menu_button).sendAccessibilityEvent( + AccessibilityEvent.TYPE_VIEW_FOCUSED) + } + } } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt index 9c73e4a38aa9..0cb219ae4b81 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt @@ -51,6 +51,7 @@ import android.view.View.TRANSLATION_Z import android.view.ViewGroup import android.view.WindowManager import android.view.WindowlessWindowManager +import android.view.accessibility.AccessibilityEvent import android.widget.Button import android.widget.TextView import android.window.TaskConstants @@ -116,19 +117,24 @@ class MaximizeMenu( onHoverListener = onHoverListener, onOutsideTouchListener = onOutsideTouchListener ) - maximizeMenuView?.animateOpenMenu() + maximizeMenuView?.let { view -> + view.animateOpenMenu(onEnd = { + view.requestAccessibilityFocus() + }) + } } /** Closes the maximize window and releases its view. */ - fun close() { + fun close(onEnd: () -> Unit) { val view = maximizeMenuView val menu = maximizeMenu if (view == null) { menu?.releaseView() } else { - view.animateCloseMenu { + view.animateCloseMenu(onEnd = { menu?.releaseView() - } + onEnd.invoke() + }) } maximizeMenu = null maximizeMenuView = null @@ -351,7 +357,7 @@ class MaximizeMenu( } /** Animate the opening of the menu */ - fun animateOpenMenu() { + fun animateOpenMenu(onEnd: () -> Unit) { maximizeButton.setLayerType(View.LAYER_TYPE_HARDWARE, null) maximizeText.setLayerType(View.LAYER_TYPE_HARDWARE, null) menuAnimatorSet = AnimatorSet() @@ -419,6 +425,7 @@ class MaximizeMenu( onEnd = { maximizeButton.setLayerType(View.LAYER_TYPE_SOFTWARE, null) maximizeText.setLayerType(View.LAYER_TYPE_SOFTWARE, null) + onEnd.invoke() } ) menuAnimatorSet?.start() @@ -499,6 +506,14 @@ class MaximizeMenu( menuAnimatorSet?.start() } + /** Request that the accessibility service focus on the menu. */ + fun requestAccessibilityFocus() { + // Focus the first button in the menu by default. + maximizeButton.post { + maximizeButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED) + } + } + /** Cancel the menu animation. */ private fun cancelAnimation() { menuAnimatorSet?.cancel() diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java index 369484558325..c1a55b48a02a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java @@ -62,8 +62,6 @@ import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams.OccludingCaptionElement; import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer; import com.android.wm.shell.windowdecor.extension.InsetsStateKt; -import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHost; -import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier; import java.util.ArrayList; import java.util.Arrays; @@ -118,7 +116,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> final Supplier<SurfaceControl.Transaction> mSurfaceControlTransactionSupplier; final Supplier<WindowContainerTransaction> mWindowContainerTransactionSupplier; final SurfaceControlViewHostFactory mSurfaceControlViewHostFactory; - @NonNull private final WindowDecorViewHostSupplier mWindowDecorViewHostSupplier; private final DisplayController.OnDisplaysChangedListener mOnDisplaysChangedListener = new DisplayController.OnDisplaysChangedListener() { @Override @@ -140,7 +137,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> Context mDecorWindowContext; SurfaceControl mDecorationContainerSurface; - private WindowDecorViewHost mDecorViewHost; + SurfaceControl mCaptionContainerSurface; + private WindowlessWindowManager mCaptionWindowManager; + private SurfaceControlViewHost mViewHost; private Configuration mWindowDecorConfig; TaskDragResizer mTaskDragResizer; boolean mIsCaptionVisible; @@ -159,13 +158,11 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> DisplayController displayController, ShellTaskOrganizer taskOrganizer, RunningTaskInfo taskInfo, - SurfaceControl taskSurface, - @NonNull WindowDecorViewHostSupplier windowDecorViewHostSupplier) { + SurfaceControl taskSurface) { this(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface, SurfaceControl.Builder::new, SurfaceControl.Transaction::new, WindowContainerTransaction::new, SurfaceControl::new, - new SurfaceControlViewHostFactory() {}, - windowDecorViewHostSupplier); + new SurfaceControlViewHostFactory() {}); } WindowDecoration( @@ -179,8 +176,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier, Supplier<WindowContainerTransaction> windowContainerTransactionSupplier, Supplier<SurfaceControl> surfaceControlSupplier, - SurfaceControlViewHostFactory surfaceControlViewHostFactory, - @NonNull WindowDecorViewHostSupplier windowDecorViewHostSupplier) { + SurfaceControlViewHostFactory surfaceControlViewHostFactory) { mContext = context; mUserContext = userContext; mDisplayController = displayController; @@ -191,7 +187,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> mSurfaceControlTransactionSupplier = surfaceControlTransactionSupplier; mWindowContainerTransactionSupplier = windowContainerTransactionSupplier; mSurfaceControlViewHostFactory = surfaceControlViewHostFactory; - mWindowDecorViewHostSupplier = windowDecorViewHostSupplier; mDisplay = mDisplayController.getDisplay(mTaskInfo.displayId); final InsetsState insetsState = mDisplayController.getInsetsState(mTaskInfo.displayId); mIsStatusBarVisible = insetsState != null @@ -217,7 +212,15 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> void relayout(RelayoutParams params, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, WindowContainerTransaction wct, T rootView, RelayoutResult<T> outResult) { - Trace.beginSection("WindowDecoration#relayout"); + updateViewsAndSurfaces(params, startT, finishT, wct, rootView, outResult); + if (outResult.mRootView != null) { + updateViewHost(params, startT, outResult); + } + } + + protected void updateViewsAndSurfaces(RelayoutParams params, + SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, + WindowContainerTransaction wct, T rootView, RelayoutResult<T> outResult) { outResult.reset(); if (params.mRunningTaskInfo != null) { mTaskInfo = params.mRunningTaskInfo; @@ -228,21 +231,17 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> if (!mTaskInfo.isVisible) { releaseViews(wct); finishT.hide(mTaskSurface); - Trace.endSection(); // WindowDecoration#relayout return; } - Trace.beginSection("WindowDecoration#relayout-inflateIfNeeded"); + inflateIfNeeded(params, wct, rootView, oldLayoutResId, outResult); - Trace.endSection(); - final boolean hasCaptionView = outResult.mRootView != null; - if (!hasCaptionView) { - Trace.endSection(); // WindowDecoration#relayout + if (outResult.mRootView == null) { + // Didn't manage to create a root view, early out. return; } + rootView = null; // Clear it just in case we use it accidentally - Trace.beginSection("WindowDecoration#relayout-updateCaptionVisibility"); updateCaptionVisibility(outResult.mRootView); - Trace.endSection(); final Rect taskBounds = mTaskInfo.getConfiguration().windowConfiguration.getBounds(); outResult.mWidth = taskBounds.width(); @@ -255,23 +254,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> ? loadDimensionPixelSize(resources, params.mCaptionWidthId) : taskBounds.width(); outResult.mCaptionX = (outResult.mWidth - outResult.mCaptionWidth) / 2; - Trace.beginSection("WindowDecoration#relayout-acquire"); - if (mDecorViewHost == null) { - mDecorViewHost = mWindowDecorViewHostSupplier.acquire(mDecorWindowContext, mDisplay); - } - Trace.endSection(); - - final SurfaceControl captionSurface = mDecorViewHost.getSurfaceControl(); - Trace.beginSection("WindowDecoration#relayout-updateSurfacesAndInsets"); updateDecorationContainerSurface(startT, outResult); - updateCaptionContainerSurface(captionSurface, startT, outResult); + updateCaptionContainerSurface(startT, outResult); updateCaptionInsets(params, wct, outResult, taskBounds); updateTaskSurface(params, startT, finishT, outResult); - Trace.endSection(); - - outResult.mRootView.setPadding(0, params.mCaptionTopPadding, 0, 0); - updateViewHierarchy(params, outResult, startT); - Trace.endSection(); // WindowDecoration#relayout } private void inflateIfNeeded(RelayoutParams params, WindowContainerTransaction wct, @@ -319,32 +305,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> return (T) LayoutInflater.from(context).inflate(layoutResId, null); } - private void updateViewHierarchy(@NonNull RelayoutParams params, - @NonNull RelayoutResult<T> outResult, @NonNull SurfaceControl.Transaction startT) { - Trace.beginSection("WindowDecoration#updateViewHierarchy"); - final WindowManager.LayoutParams lp = - new WindowManager.LayoutParams( - outResult.mCaptionWidth, - outResult.mCaptionHeight, - TYPE_APPLICATION, - FLAG_NOT_FOCUSABLE | FLAG_SPLIT_TOUCH, - PixelFormat.TRANSPARENT); - lp.setTitle("Caption of Task=" + mTaskInfo.taskId); - lp.setTrustedOverlay(); - lp.inputFeatures = params.mInputFeatures; - if (params.mAsyncViewHost) { - if (params.mApplyStartTransactionOnDraw) { - throw new IllegalArgumentException( - "We cannot both sync viewhost ondraw and delay viewhost creation."); - } - mDecorViewHost.updateViewAsync(outResult.mRootView, lp, mTaskInfo.getConfiguration()); - } else { - mDecorViewHost.updateView(outResult.mRootView, lp, mTaskInfo.getConfiguration(), - params.mApplyStartTransactionOnDraw ? startT : null); - } - Trace.endSection(); - } - private void updateDecorationContainerSurface( SurfaceControl.Transaction startT, RelayoutResult<T> outResult) { if (mDecorationContainerSurface == null) { @@ -365,14 +325,23 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .show(mDecorationContainerSurface); } - private void updateCaptionContainerSurface(@NonNull SurfaceControl captionSurface, + private void updateCaptionContainerSurface( SurfaceControl.Transaction startT, RelayoutResult<T> outResult) { - startT.reparent(captionSurface, mDecorationContainerSurface) - .setWindowCrop(captionSurface, outResult.mCaptionWidth, + if (mCaptionContainerSurface == null) { + final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get(); + mCaptionContainerSurface = builder + .setName("Caption container of Task=" + mTaskInfo.taskId) + .setContainerLayer() + .setParent(mDecorationContainerSurface) + .setCallsite("WindowDecoration.updateCaptionContainerSurface") + .build(); + } + + startT.setWindowCrop(mCaptionContainerSurface, outResult.mCaptionWidth, outResult.mCaptionHeight) - .setPosition(captionSurface, outResult.mCaptionX, 0 /* y */) - .setLayer(captionSurface, CAPTION_LAYER_Z_ORDER) - .show(captionSurface); + .setPosition(mCaptionContainerSurface, outResult.mCaptionX, 0 /* y */) + .setLayer(mCaptionContainerSurface, CAPTION_LAYER_Z_ORDER) + .show(mCaptionContainerSurface); } private void updateCaptionInsets(RelayoutParams params, WindowContainerTransaction wct, @@ -466,6 +435,64 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> } } + /** + * Updates a {@link SurfaceControlViewHost} to connect the window decoration surfaces with our + * View hierarchy. + * + * @param params parameters to use from the last relayout + * @param onDrawTransaction a transaction to apply in sync with #onDraw + * @param outResult results to use from the last relayout + * + */ + protected void updateViewHost(RelayoutParams params, + SurfaceControl.Transaction onDrawTransaction, RelayoutResult<T> outResult) { + Trace.beginSection("CaptionViewHostLayout"); + if (mCaptionWindowManager == null) { + // Put caption under a container surface because ViewRootImpl sets the destination frame + // of windowless window layers and BLASTBufferQueue#update() doesn't support offset. + mCaptionWindowManager = new WindowlessWindowManager( + mTaskInfo.getConfiguration(), mCaptionContainerSurface, + null /* hostInputToken */); + } + mCaptionWindowManager.setConfiguration(mTaskInfo.getConfiguration()); + final WindowManager.LayoutParams lp = + new WindowManager.LayoutParams( + outResult.mCaptionWidth, + outResult.mCaptionHeight, + TYPE_APPLICATION, + FLAG_NOT_FOCUSABLE | FLAG_SPLIT_TOUCH, + PixelFormat.TRANSPARENT); + lp.setTitle("Caption of Task=" + mTaskInfo.taskId); + lp.setTrustedOverlay(); + lp.inputFeatures = params.mInputFeatures; + if (mViewHost == null) { + Trace.beginSection("CaptionViewHostLayout-new"); + mViewHost = mSurfaceControlViewHostFactory.create(mDecorWindowContext, mDisplay, + mCaptionWindowManager); + if (params.mApplyStartTransactionOnDraw) { + if (onDrawTransaction == null) { + throw new IllegalArgumentException("Trying to sync a null Transaction"); + } + mViewHost.getRootSurfaceControl().applyTransactionOnDraw(onDrawTransaction); + } + outResult.mRootView.setPadding(0, params.mCaptionTopPadding, 0, 0); + mViewHost.setView(outResult.mRootView, lp); + Trace.endSection(); + } else { + Trace.beginSection("CaptionViewHostLayout-relayout"); + if (params.mApplyStartTransactionOnDraw) { + if (onDrawTransaction == null) { + throw new IllegalArgumentException("Trying to sync a null Transaction"); + } + mViewHost.getRootSurfaceControl().applyTransactionOnDraw(onDrawTransaction); + } + outResult.mRootView.setPadding(0, params.mCaptionTopPadding, 0, 0); + mViewHost.relayout(lp); + Trace.endSection(); + } + Trace.endSection(); // CaptionViewHostLayout + } + private Rect calculateBoundingRect(@NonNull OccludingCaptionElement element, int elementWidthPx, @NonNull Rect captionRect) { switch (element.mAlignment) { @@ -553,11 +580,18 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> } void releaseViews(WindowContainerTransaction wct) { + if (mViewHost != null) { + mViewHost.release(); + mViewHost = null; + } + + mCaptionWindowManager = null; + final SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get(); boolean released = false; - if (mDecorViewHost != null) { - mWindowDecorViewHostSupplier.release(mDecorViewHost, t); - mDecorViewHost = null; + if (mCaptionContainerSurface != null) { + t.remove(mCaptionContainerSurface); + mCaptionContainerSurface = null; released = true; } @@ -708,7 +742,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> boolean mApplyStartTransactionOnDraw; boolean mSetTaskPositionAndCrop; - boolean mAsyncViewHost; void reset() { mLayoutResId = Resources.ID_NULL; @@ -725,7 +758,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> mApplyStartTransactionOnDraw = false; mSetTaskPositionAndCrop = false; - mAsyncViewHost = false; mWindowDecorConfig = null; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt index 9c7d644afb7e..8c102ebfb590 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt @@ -22,6 +22,7 @@ import android.content.res.ColorStateList import android.graphics.Color import android.graphics.Point import android.hardware.input.InputManager +import android.os.Bundle import android.os.Handler import android.view.MotionEvent.ACTION_DOWN import android.view.SurfaceControl @@ -29,7 +30,12 @@ import android.view.View import android.view.View.OnClickListener import android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS import android.view.WindowManager +import android.view.accessibility.AccessibilityEvent +import android.view.accessibility.AccessibilityNodeInfo +import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction import android.widget.ImageButton +import androidx.core.view.ViewCompat +import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat import com.android.internal.policy.SystemBarUtils import com.android.window.flags.Flags import com.android.wm.shell.R @@ -67,6 +73,20 @@ internal class AppHandleViewHolder( captionView.setOnTouchListener(onCaptionTouchListener) captionHandle.setOnTouchListener(onCaptionTouchListener) captionHandle.setOnClickListener(onCaptionButtonClickListener) + captionHandle.accessibilityDelegate = object : View.AccessibilityDelegate() { + override fun sendAccessibilityEvent(host: View, eventType: Int) { + when (eventType) { + AccessibilityEvent.TYPE_VIEW_HOVER_ENTER, + AccessibilityEvent.TYPE_VIEW_HOVER_EXIT -> { + // Caption Handle itself can't get a11y focus because it's under the status + // bar, so pass through TYPE_VIEW_HOVER a11y events to the status bar + // input layer, so that it can get a11y focus on the caption handle's behalf + statusBarInputLayer?.view?.sendAccessibilityEvent(eventType) + } + else -> super.sendAccessibilityEvent(host, eventType) + } + } + } } override fun bindData( @@ -134,9 +154,53 @@ internal class AppHandleViewHolder( captionHandle.dispatchTouchEvent(event) return@setOnTouchListener true } + setupAppHandleA11y(view) windowManagerWrapper.updateViewLayout(view, lp) } + private fun setupAppHandleA11y(view: View) { + view.accessibilityDelegate = object : View.AccessibilityDelegate() { + override fun onInitializeAccessibilityNodeInfo( + host: View, + info: AccessibilityNodeInfo + ) { + // Allow the status bar input layer to be a11y clickable so it can interact with + // a11y services on behalf of caption handle (due to being under status bar) + super.onInitializeAccessibilityNodeInfo(host, info) + info.addAction(AccessibilityAction.ACTION_CLICK) + host.isClickable = true + } + + override fun performAccessibilityAction( + host: View, + action: Int, + args: Bundle? + ): Boolean { + // Passthrough the a11y click action so the caption handle, so that app handle menu + // is opened on a11y click, similar to a real click + if (action == AccessibilityAction.ACTION_CLICK.id) { + captionHandle.performClick() + } + return super.performAccessibilityAction(host, action, args) + } + + override fun onPopulateAccessibilityEvent(host: View, event: AccessibilityEvent) { + super.onPopulateAccessibilityEvent(host, event) + // When the status bar input layer is focused, use the content description of the + // caption handle so that it appears as "App handle" and not "Unlabelled view" + if (event.eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) { + event.text.add(captionHandle.contentDescription) + } + } + } + + // Update a11y action text so that Talkback announces "Press double tap to open app handle + // menu" while focused on status bar input layer + ViewCompat.replaceAccessibilityAction( + view, AccessibilityActionCompat.ACTION_CLICK, "Open app handle menu", null + ) + } + private fun updateStatusBarInputLayer(globalPosition: Point) { statusBarInputLayer?.setPosition( SurfaceControl.Transaction(), @@ -173,7 +237,8 @@ internal class AppHandleViewHolder( return taskInfo.taskDescription ?.let { taskDescription -> if (Color.alpha(taskDescription.statusBarColor) != 0 && - taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) { + taskInfo.windowingMode == WINDOWING_MODE_FREEFORM + ) { Color.valueOf(taskDescription.statusBarColor).luminance() < 0.5 } else { taskDescription.systemBarsAppearance and APPEARANCE_LIGHT_STATUS_BARS == 0 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 af6a819bb705..e9961655d979 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 @@ -30,6 +30,7 @@ import android.graphics.drawable.shapes.RoundRectShape import android.view.View import android.view.View.OnLongClickListener import android.view.ViewTreeObserver.OnGlobalLayoutListener +import android.view.accessibility.AccessibilityEvent import android.widget.ImageButton import android.widget.ImageView import android.widget.TextView @@ -263,7 +264,11 @@ class AppHeaderViewHolder( override fun onHandleMenuOpened() {} - override fun onHandleMenuClosed() {} + override fun onHandleMenuClosed() { + openMenuButton.post { + openMenuButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED) + } + } fun setAnimatingTaskResizeOrReposition(animatingTaskResizeOrReposition: Boolean) { // If animating a task resize or reposition, cancel any running hover animations @@ -309,6 +314,12 @@ class AppHeaderViewHolder( ) } + fun requestAccessibilityFocus() { + maximizeWindowButton.post { + maximizeWindowButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED) + } + } + private fun getHeaderStyle(header: Header): HeaderStyle { return HeaderStyle( background = getHeaderBackground(header), 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 deleted file mode 100644 index 139e6790b744..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHost.kt +++ /dev/null @@ -1,146 +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.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 [SurfaceControlViewHost]. - * - * 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( - private val context: Context, - @ShellMainThread private val mainScope: CoroutineScope, - 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() = rootSurface - - override fun updateView( - view: View, - attrs: WindowManager.LayoutParams, - configuration: Configuration, - onDrawTransaction: SurfaceControl.Transaction? - ) { - Trace.beginSection("DefaultWindowDecorViewHost#updateView") - clearCurrentUpdateJob() - updateViewHost(view, attrs, configuration, onDrawTransaction) - Trace.endSection() - } - - override fun updateViewAsync( - view: View, - attrs: WindowManager.LayoutParams, - configuration: Configuration - ) { - Trace.beginSection("DefaultWindowDecorViewHost#updateViewAsync") - clearCurrentUpdateJob() - currentUpdateJob = mainScope.launch { - updateViewHost(view, attrs, configuration, onDrawTransaction = null) - } - Trace.endSection() - } - - override fun release(t: SurfaceControl.Transaction) { - clearCurrentUpdateJob() - viewHost?.release() - t.remove(rootSurface) - } - - private fun updateViewHost( - view: View, - attrs: WindowManager.LayoutParams, - configuration: Configuration, - onDrawTransaction: SurfaceControl.Transaction? - ) { - Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost") - if (wwm == null) { - wwm = WindowlessWindowManager(configuration, rootSurface, null) - } - 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/DefaultWindowDecorViewHostSupplier.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostSupplier.kt deleted file mode 100644 index 9997e8f564d8..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostSupplier.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.wm.shell.windowdecor.viewhost - -import android.content.Context -import android.view.Display -import android.view.SurfaceControl -import com.android.wm.shell.shared.annotations.ShellMainThread -import kotlinx.coroutines.CoroutineScope - -/** - * A supplier of [DefaultWindowDecorViewHost]s. It creates a new one every time one is requested. - */ -class DefaultWindowDecorViewHostSupplier( - @ShellMainThread private val mainScope: CoroutineScope, -) : WindowDecorViewHostSupplier<DefaultWindowDecorViewHost> { - - override fun acquire(context: Context, display: Display): DefaultWindowDecorViewHost { - return DefaultWindowDecorViewHost(context, mainScope, display) - } - - override fun release(viewHost: DefaultWindowDecorViewHost, t: SurfaceControl.Transaction) { - viewHost.release(t) - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHost.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHost.kt deleted file mode 100644 index 3fbaea8bd1bf..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHost.kt +++ /dev/null @@ -1,49 +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.res.Configuration -import android.view.SurfaceControl -import android.view.View -import android.view.WindowManager -import com.android.wm.shell.windowdecor.WindowDecoration - -/** - * An interface for a utility that hosts a [WindowDecoration]'s [View] hierarchy under a - * [SurfaceControl]. - */ -interface WindowDecorViewHost { - /** The surface where the underlying [View] hierarchy is being rendered. */ - val surfaceControl: SurfaceControl - - /** Synchronously update the view hierarchy of this view host. */ - fun updateView( - view: View, - attrs: WindowManager.LayoutParams, - configuration: Configuration, - onDrawTransaction: SurfaceControl.Transaction? - ) - - /** Asynchronously update the view hierarchy of this view host. */ - fun updateViewAsync( - view: View, - attrs: WindowManager.LayoutParams, - configuration: Configuration - ) - - /** Releases the underlying [View] hierarchy and removes the backing [SurfaceControl]. */ - fun release(t: SurfaceControl.Transaction) -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHostSupplier.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHostSupplier.kt deleted file mode 100644 index 0e2358446d12..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHostSupplier.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.wm.shell.windowdecor.viewhost - -import android.content.Context -import android.view.Display -import android.view.SurfaceControl - -/** - * An interface for a supplier of [WindowDecorViewHost]s. - */ -interface WindowDecorViewHostSupplier<T : WindowDecorViewHost> { - /** Acquire a [WindowDecorViewHost]. */ - fun acquire(context: Context, display: Display): T - - /** - * Release a [WindowDecorViewHost] when it is no longer used. - * - * @param viewHost the [WindowDecorViewHost] to release - * @param t a transaction that may be used to remove any underlying backing [SurfaceControl] - * that are hosting this [WindowDecorViewHost]. The supplier is not expected to apply - * the transaction. It should be applied by the owner of this supplier. - */ - fun release(viewHost: T, t: SurfaceControl.Transaction) -} diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt index 717ea306eb77..ce235d445fe5 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt @@ -72,7 +72,6 @@ open class StartAppMediaProjectionWithMaxDesktopWindows { @Test open fun startMediaProjection() { - // TODO(b/366455106) - handle max task Limit mediaProjectionAppHelper.startSingleAppMediaProjection(wmHelper, targetApp) mailApp.launchViaIntent(wmHelper) simpleApp.launchViaIntent(wmHelper) diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithDisplayRotations.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithDisplayRotations.kt index 1573b58853da..f5fb4cec5535 100644 --- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithDisplayRotations.kt +++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithDisplayRotations.kt @@ -20,13 +20,12 @@ import android.app.Instrumentation import android.platform.test.annotations.Postsubmit import android.tools.NavBar import android.tools.Rotation -import android.tools.flicker.rules.ChangeDisplayOrientationRule import android.tools.device.apphelpers.CalculatorAppHelper +import android.tools.flicker.rules.ChangeDisplayOrientationRule import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation -import com.android.server.wm.flicker.helpers.DesktopModeAppHelper import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper import com.android.wm.shell.Utils import org.junit.After @@ -47,8 +46,7 @@ open class StartAppMediaProjectionWithDisplayRotations { private val initialRotation = Rotation.ROTATION_0 private val targetApp = CalculatorAppHelper(instrumentation) - private val mediaProjectionAppHelper = StartMediaProjectionAppHelper(instrumentation) - private val testApp = DesktopModeAppHelper(mediaProjectionAppHelper) + private val testApp = StartMediaProjectionAppHelper(instrumentation) @Rule @JvmField @@ -63,7 +61,7 @@ open class StartAppMediaProjectionWithDisplayRotations { @Test open fun startMediaProjectionAndRotate() { - mediaProjectionAppHelper.startSingleAppMediaProjection(wmHelper, targetApp) + testApp.startSingleAppMediaProjection(wmHelper, targetApp) wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() ChangeDisplayOrientationRule.setRotation(Rotation.ROTATION_90) diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithDisplayRotations.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithDisplayRotations.kt index e80a895c1aa6..28f3cc758c22 100644 --- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithDisplayRotations.kt +++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithDisplayRotations.kt @@ -25,7 +25,6 @@ import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation -import com.android.server.wm.flicker.helpers.DesktopModeAppHelper import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper import com.android.wm.shell.Utils import org.junit.After @@ -45,8 +44,7 @@ open class StartScreenMediaProjectionWithDisplayRotations { val device = UiDevice.getInstance(instrumentation) private val initialRotation = Rotation.ROTATION_0 - private val mediaProjectionAppHelper = StartMediaProjectionAppHelper(instrumentation) - private val testApp = DesktopModeAppHelper(mediaProjectionAppHelper) + private val testApp = StartMediaProjectionAppHelper(instrumentation) @Rule @JvmField @@ -60,7 +58,7 @@ open class StartScreenMediaProjectionWithDisplayRotations { @Test open fun startMediaProjectionAndRotate() { - mediaProjectionAppHelper.startEntireScreenMediaProjection(wmHelper) + testApp.startEntireScreenMediaProjection(wmHelper) wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() ChangeDisplayOrientationRule.setRotation(Rotation.ROTATION_90) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java index e514dc38208e..f01ed84adc74 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java @@ -39,6 +39,7 @@ import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.never; import android.app.ActivityManager.RunningTaskInfo; import android.app.TaskInfo; @@ -599,6 +600,18 @@ public class ShellTaskOrganizerTests extends ShellTestCase { } @Test + public void testRecentTasks_visibilityChanges_notFreeForm_shouldNotNotifyTaskController() { + RunningTaskInfo task1_visible = createTaskInfo(/* taskId= */ 1, WINDOWING_MODE_FULLSCREEN); + mOrganizer.onTaskAppeared(task1_visible, /* leash= */ null); + RunningTaskInfo task1_hidden = createTaskInfo(/* taskId= */ 1, WINDOWING_MODE_FULLSCREEN); + task1_hidden.isVisible = false; + + mOrganizer.onTaskInfoChanged(task1_hidden); + + verify(mRecentTasksController, never()).onTaskRunningInfoChanged(task1_hidden); + } + + @Test public void testRecentTasks_windowingModeChanges_shouldNotifyTaskController() { RunningTaskInfo task1 = createTaskInfo(/* taskId= */ 1, WINDOWING_MODE_FULLSCREEN); mOrganizer.onTaskAppeared(task1, /* leash= */ null); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt index b14f1633e8fd..628c9cdd9339 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt @@ -41,12 +41,22 @@ import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.common.TaskStackListenerImpl import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask +import com.android.wm.shell.desktopmode.persistence.Desktop +import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository import com.android.wm.shell.shared.desktopmode.DesktopModeStatus import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.Transitions import junit.framework.Assert.assertEquals import junit.framework.Assert.assertTrue import kotlin.test.assertNotNull +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.cancel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Before import org.junit.Rule @@ -73,6 +83,7 @@ import org.mockito.quality.Strictness */ @SmallTest @RunWith(AndroidTestingRunner::class) +@ExperimentalCoroutinesApi @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE, FLAG_RESPECT_ORIENTATION_CHANGE_FOR_UNRESIZEABLE) class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { @JvmField @Rule val setFlagsRule = SetFlagsRule() @@ -82,16 +93,19 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { @Mock lateinit var transitions: Transitions @Mock lateinit var resizeTransitionHandler: ToggleResizeDesktopTaskTransitionHandler @Mock lateinit var taskStackListener: TaskStackListenerImpl + @Mock lateinit var persistentRepository: DesktopPersistentRepository private lateinit var mockitoSession: StaticMockitoSession private lateinit var handler: DesktopActivityOrientationChangeHandler private lateinit var shellInit: ShellInit private lateinit var taskRepository: DesktopModeTaskRepository + private lateinit var testScope: CoroutineScope // Mock running tasks are registered here so we can get the list from mock shell task organizer. private val runningTasks = mutableListOf<RunningTaskInfo>() @Before fun setUp() { + Dispatchers.setMain(StandardTestDispatcher()) mockitoSession = mockitoSession() .strictness(Strictness.LENIENT) @@ -99,10 +113,15 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { .startMocking() doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } + testScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) shellInit = spy(ShellInit(testExecutor)) - taskRepository = DesktopModeTaskRepository() + taskRepository = + DesktopModeTaskRepository(context, shellInit, persistentRepository, testScope) whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks } whenever(transitions.startTransition(anyInt(), any(), isNull())).thenAnswer { Binder() } + whenever(runBlocking { persistentRepository.readDesktop(any(), any()) }).thenReturn( + Desktop.getDefaultInstance() + ) handler = DesktopActivityOrientationChangeHandler(context, shellInit, shellTaskOrganizer, taskStackListener, resizeTransitionHandler, taskRepository) @@ -115,6 +134,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { mockitoSession.finishMocking() runningTasks.clear() + testScope.cancel() } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt index d3404f7bd261..bc40d89009bc 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt @@ -17,27 +17,70 @@ package com.android.wm.shell.desktopmode import android.graphics.Rect +import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner +import android.util.ArraySet import android.view.Display.DEFAULT_DISPLAY import android.view.Display.INVALID_DISPLAY import androidx.test.filters.SmallTest +import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE import com.android.wm.shell.ShellTestCase import com.android.wm.shell.TestShellExecutor +import com.android.wm.shell.common.ShellExecutor +import com.android.wm.shell.desktopmode.persistence.Desktop +import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository +import com.android.wm.shell.sysui.ShellInit import com.google.common.truth.Truth.assertThat import junit.framework.Assert.fail +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.test.setMain +import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.inOrder +import org.mockito.Mockito.spy +import org.mockito.kotlin.any +import org.mockito.kotlin.never +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever @SmallTest @RunWith(AndroidTestingRunner::class) +@ExperimentalCoroutinesApi class DesktopModeTaskRepositoryTest : ShellTestCase() { private lateinit var repo: DesktopModeTaskRepository + private lateinit var shellInit: ShellInit + private lateinit var datastoreScope: CoroutineScope + + @Mock private lateinit var testExecutor: ShellExecutor + @Mock private lateinit var persistentRepository: DesktopPersistentRepository @Before fun setUp() { - repo = DesktopModeTaskRepository() + Dispatchers.setMain(StandardTestDispatcher()) + datastoreScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) + shellInit = spy(ShellInit(testExecutor)) + + repo = DesktopModeTaskRepository(context, shellInit, persistentRepository, datastoreScope) + whenever(runBlocking { persistentRepository.readDesktop(any(), any()) }).thenReturn( + Desktop.getDefaultInstance() + ) + shellInit.init() + } + + @After + fun tearDown() { + datastoreScope.cancel() } @Test @@ -455,6 +498,44 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE) + fun addOrMoveFreeformTaskToTop_noTaskExists_persistenceEnabled_addsToTop() = + runTest(StandardTestDispatcher()) { + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, 5) + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, 6) + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, 7) + + val tasks = repo.getFreeformTasksInZOrder(DEFAULT_DISPLAY) + assertThat(tasks).containsExactly(7, 6, 5).inOrder() + inOrder(persistentRepository).run { + verify(persistentRepository) + .addOrUpdateDesktop( + DEFAULT_USER_ID, + DEFAULT_DESKTOP_ID, + visibleTasks = ArraySet(), + minimizedTasks = ArraySet(), + freeformTasksInZOrder = arrayListOf(5) + ) + verify(persistentRepository) + .addOrUpdateDesktop( + DEFAULT_USER_ID, + DEFAULT_DESKTOP_ID, + visibleTasks = ArraySet(), + minimizedTasks = ArraySet(), + freeformTasksInZOrder = arrayListOf(6, 5) + ) + verify(persistentRepository) + .addOrUpdateDesktop( + DEFAULT_USER_ID, + DEFAULT_DESKTOP_ID, + visibleTasks = ArraySet(), + minimizedTasks = ArraySet(), + freeformTasksInZOrder = arrayListOf(7, 6, 5) + ) + } + } + + @Test fun addOrMoveFreeformTaskToTop_alreadyExists_movesToTop() { repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, 5) repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, 6) @@ -480,6 +561,55 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE) + fun minimizeTask_persistenceEnabled_taskIsPersistedAsMinimized() = + runTest(StandardTestDispatcher()) { + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, 5) + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, 6) + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, 7) + + repo.minimizeTask(displayId = 0, taskId = 6) + + val tasks = repo.getFreeformTasksInZOrder(DEFAULT_DISPLAY) + assertThat(tasks).containsExactly(7, 6, 5).inOrder() + assertThat(repo.isMinimizedTask(taskId = 6)).isTrue() + inOrder(persistentRepository).run { + verify(persistentRepository) + .addOrUpdateDesktop( + DEFAULT_USER_ID, + DEFAULT_DESKTOP_ID, + visibleTasks = ArraySet(), + minimizedTasks = ArraySet(), + freeformTasksInZOrder = arrayListOf(5) + ) + verify(persistentRepository) + .addOrUpdateDesktop( + DEFAULT_USER_ID, + DEFAULT_DESKTOP_ID, + visibleTasks = ArraySet(), + minimizedTasks = ArraySet(), + freeformTasksInZOrder = arrayListOf(6, 5) + ) + verify(persistentRepository) + .addOrUpdateDesktop( + DEFAULT_USER_ID, + DEFAULT_DESKTOP_ID, + visibleTasks = ArraySet(), + minimizedTasks = ArraySet(), + freeformTasksInZOrder = arrayListOf(7, 6, 5) + ) + verify(persistentRepository) + .addOrUpdateDesktop( + DEFAULT_USER_ID, + DEFAULT_DESKTOP_ID, + visibleTasks = ArraySet(), + minimizedTasks = ArraySet(arrayOf(6)), + freeformTasksInZOrder = arrayListOf(7, 6, 5) + ) + } + } + + @Test fun addOrMoveFreeformTaskToTop_taskIsUnminimized_noop() { repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, 5) repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, 6) @@ -503,6 +633,33 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE) + fun removeFreeformTask_invalidDisplay_persistenceEnabled_removesTaskFromFreeformTasks() { + runTest(StandardTestDispatcher()) { + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, taskId = 1) + + repo.removeFreeformTask(INVALID_DISPLAY, taskId = 1) + + verify(persistentRepository) + .addOrUpdateDesktop( + DEFAULT_USER_ID, + DEFAULT_DESKTOP_ID, + visibleTasks = ArraySet(), + minimizedTasks = ArraySet(), + freeformTasksInZOrder = arrayListOf(1) + ) + verify(persistentRepository) + .addOrUpdateDesktop( + DEFAULT_USER_ID, + DEFAULT_DESKTOP_ID, + visibleTasks = ArraySet(), + minimizedTasks = ArraySet(), + freeformTasksInZOrder = ArrayList() + ) + } + } + + @Test fun removeFreeformTask_validDisplay_removesTaskFromFreeformTasks() { repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, taskId = 1) @@ -513,6 +670,33 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE) + fun removeFreeformTask_validDisplay_persistenceEnabled_removesTaskFromFreeformTasks() { + runTest(StandardTestDispatcher()) { + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, taskId = 1) + + repo.removeFreeformTask(DEFAULT_DISPLAY, taskId = 1) + + verify(persistentRepository) + .addOrUpdateDesktop( + DEFAULT_USER_ID, + DEFAULT_DESKTOP_ID, + visibleTasks = ArraySet(), + minimizedTasks = ArraySet(), + freeformTasksInZOrder = arrayListOf(1) + ) + verify(persistentRepository) + .addOrUpdateDesktop( + DEFAULT_USER_ID, + DEFAULT_DESKTOP_ID, + visibleTasks = ArraySet(), + minimizedTasks = ArraySet(), + freeformTasksInZOrder = ArrayList() + ) + } + } + + @Test fun removeFreeformTask_validDisplay_differentDisplay_doesNotRemovesTask() { repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, taskId = 1) @@ -523,6 +707,33 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE) + fun removeFreeformTask_validDisplayButDifferentDisplay_persistenceEnabled_doesNotRemoveTask() { + runTest(StandardTestDispatcher()) { + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, taskId = 1) + + repo.removeFreeformTask(SECOND_DISPLAY, taskId = 1) + + verify(persistentRepository) + .addOrUpdateDesktop( + DEFAULT_USER_ID, + DEFAULT_DESKTOP_ID, + visibleTasks = ArraySet(), + minimizedTasks = ArraySet(), + freeformTasksInZOrder = arrayListOf(1) + ) + verify(persistentRepository, never()) + .addOrUpdateDesktop( + DEFAULT_USER_ID, + DEFAULT_DESKTOP_ID, + visibleTasks = ArraySet(), + minimizedTasks = ArraySet(), + freeformTasksInZOrder = ArrayList() + ) + } + } + + @Test fun removeFreeformTask_removesTaskBoundsBeforeMaximize() { val taskId = 1 repo.addActiveTask(THIRD_DISPLAY, taskId) @@ -709,5 +920,7 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { companion object { const val SECOND_DISPLAY = 1 const val THIRD_DISPLAY = 345 + private const val DEFAULT_USER_ID = 1000 + private const val DEFAULT_DESKTOP_ID = 0 } } 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 8f20841e76b3..ee545209904f 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 @@ -93,6 +93,8 @@ import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreef import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createHomeTask import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createSplitScreenTask +import com.android.wm.shell.desktopmode.persistence.Desktop +import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository import com.android.wm.shell.draganddrop.DragAndDropController import com.android.wm.shell.recents.RecentTasksController import com.android.wm.shell.recents.RecentsTransitionHandler @@ -117,6 +119,14 @@ import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue import kotlin.test.assertNotNull import kotlin.test.assertNull +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Assume.assumeTrue import org.junit.Before @@ -148,6 +158,7 @@ import org.mockito.quality.Strictness */ @SmallTest @RunWith(AndroidTestingRunner::class) +@ExperimentalCoroutinesApi @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) class DesktopTasksControllerTest : ShellTestCase() { @@ -183,6 +194,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Mock private lateinit var mockSurface: SurfaceControl @Mock private lateinit var taskbarDesktopTaskListener: TaskbarDesktopTaskListener @Mock private lateinit var mockHandler: Handler + @Mock lateinit var persistentRepository: DesktopPersistentRepository private lateinit var mockitoSession: StaticMockitoSession private lateinit var controller: DesktopTasksController @@ -190,6 +202,7 @@ class DesktopTasksControllerTest : ShellTestCase() { private lateinit var taskRepository: DesktopModeTaskRepository private lateinit var desktopTasksLimiter: DesktopTasksLimiter private lateinit var recentsTransitionStateListener: RecentsTransitionStateListener + private lateinit var testScope: CoroutineScope private val shellExecutor = TestShellExecutor() @@ -207,6 +220,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Before fun setUp() { + Dispatchers.setMain(StandardTestDispatcher()) mockitoSession = mockitoSession() .strictness(Strictness.LENIENT) @@ -214,8 +228,9 @@ class DesktopTasksControllerTest : ShellTestCase() { .startMocking() doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } + testScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) shellInit = spy(ShellInit(testExecutor)) - taskRepository = DesktopModeTaskRepository() + taskRepository = DesktopModeTaskRepository(context, shellInit, persistentRepository, testScope) desktopTasksLimiter = DesktopTasksLimiter( transitions, @@ -233,6 +248,9 @@ class DesktopTasksControllerTest : ShellTestCase() { whenever(displayLayout.getStableBounds(any())).thenAnswer { i -> (i.arguments.first() as Rect).set(STABLE_BOUNDS) } + whenever(runBlocking { persistentRepository.readDesktop(any(), any()) }).thenReturn( + Desktop.getDefaultInstance() + ) val tda = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0) tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN @@ -287,6 +305,7 @@ class DesktopTasksControllerTest : ShellTestCase() { mockitoSession.finishMocking() runningTasks.clear() + testScope.cancel() } @Test 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 61d03cac035c..045e07796cb8 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 @@ -35,13 +35,23 @@ import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_MINIMIZE_WINDOW import com.android.internal.jank.InteractionJankMonitor import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask +import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository import com.android.wm.shell.shared.desktopmode.DesktopModeStatus +import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.TransitionInfoBuilder import com.android.wm.shell.transition.Transitions import com.android.wm.shell.util.StubTransaction import com.google.common.truth.Truth.assertThat import kotlin.test.assertFailsWith +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Before import org.junit.Rule @@ -49,6 +59,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.any +import org.mockito.Mockito.spy import org.mockito.Mockito.`when` import org.mockito.kotlin.eq import org.mockito.kotlin.verify @@ -62,6 +73,7 @@ import org.mockito.quality.Strictness */ @SmallTest @RunWith(AndroidTestingRunner::class) +@ExperimentalCoroutinesApi class DesktopTasksLimiterTest : ShellTestCase() { @JvmField @@ -72,19 +84,26 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Mock lateinit var transitions: Transitions @Mock lateinit var interactionJankMonitor: InteractionJankMonitor @Mock lateinit var handler: Handler + @Mock lateinit var testExecutor: ShellExecutor + @Mock lateinit var persistentRepository: DesktopPersistentRepository private lateinit var mockitoSession: StaticMockitoSession private lateinit var desktopTasksLimiter: DesktopTasksLimiter private lateinit var desktopTaskRepo: DesktopModeTaskRepository + private lateinit var shellInit: ShellInit + private lateinit var testScope: CoroutineScope @Before fun setUp() { mockitoSession = ExtendedMockito.mockitoSession().strictness(Strictness.LENIENT) .spyStatic(DesktopModeStatus::class.java).startMocking() doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(any()) } + shellInit = spy(ShellInit(testExecutor)) + Dispatchers.setMain(StandardTestDispatcher()) + testScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) - desktopTaskRepo = DesktopModeTaskRepository() - + desktopTaskRepo = + DesktopModeTaskRepository(context, shellInit, persistentRepository, testScope) desktopTasksLimiter = DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, MAX_TASK_LIMIT, interactionJankMonitor, mContext, handler) @@ -93,6 +112,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { @After fun tearDown() { mockitoSession.finishMocking() + testScope.cancel() } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepositoryTest.kt new file mode 100644 index 000000000000..9b9703fdf6dc --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepositoryTest.kt @@ -0,0 +1,198 @@ +/* + * 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.persistence + +import android.content.Context +import android.platform.test.annotations.EnableFlags +import android.testing.AndroidTestingRunner +import android.util.ArraySet +import android.view.Display.DEFAULT_DISPLAY +import androidx.datastore.core.DataStore +import androidx.datastore.core.DataStoreFactory +import androidx.datastore.dataStoreFile +import androidx.test.core.app.ApplicationProvider +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE +import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE +import com.android.wm.shell.ShellTestCase +import com.google.common.truth.Truth.assertThat +import java.io.File +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.test.setMain +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@ExperimentalCoroutinesApi +@EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE, FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE) +class DesktopPersistentRepositoryTest : ShellTestCase() { + private val testContext: Context = InstrumentationRegistry.getInstrumentation().targetContext + private lateinit var testDatastore: DataStore<DesktopPersistentRepositories> + private lateinit var datastoreRepository: DesktopPersistentRepository + private lateinit var datastoreScope: CoroutineScope + + @Before + fun setUp() { + Dispatchers.setMain(StandardTestDispatcher()) + datastoreScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) + testDatastore = + DataStoreFactory.create( + serializer = + DesktopPersistentRepository.Companion.DesktopPersistentRepositoriesSerializer, + scope = datastoreScope) { + testContext.dataStoreFile(DESKTOP_REPOSITORY_STATES_DATASTORE_TEST_FILE) + } + datastoreRepository = DesktopPersistentRepository(testDatastore) + } + + @After + fun tearDown() { + File(ApplicationProvider.getApplicationContext<Context>().filesDir, "datastore") + .deleteRecursively() + + datastoreScope.cancel() + } + + @Test + fun readRepository_returnsCorrectDesktop() { + runTest(StandardTestDispatcher()) { + val task = createDesktopTask(1) + val desk = createDesktop(task) + val repositoryState = + DesktopRepositoryState.newBuilder().putDesktop(DEFAULT_DESKTOP_ID, desk) + val DesktopPersistentRepositories = + DesktopPersistentRepositories.newBuilder() + .putDesktopRepoByUser(DEFAULT_USER_ID, repositoryState.build()) + .build() + testDatastore.updateData { DesktopPersistentRepositories } + + val actualDesktop = datastoreRepository.readDesktop(DEFAULT_USER_ID, DEFAULT_DESKTOP_ID) + + assertThat(actualDesktop).isEqualTo(desk) + } + } + + @Test + fun addOrUpdateTask_addNewTaskToDesktop() { + runTest(StandardTestDispatcher()) { + // Create a basic repository state + val task = createDesktopTask(1) + val DesktopPersistentRepositories = createRepositoryWithOneDesk(task) + testDatastore.updateData { DesktopPersistentRepositories } + // Create a new state to be initialized + val visibleTasks = ArraySet(listOf(1, 2)) + val minimizedTasks = ArraySet<Int>() + val freeformTasksInZOrder = ArrayList(listOf(2, 1)) + + // Update with new state + datastoreRepository.addOrUpdateDesktop( + visibleTasks = visibleTasks, + minimizedTasks = minimizedTasks, + freeformTasksInZOrder = freeformTasksInZOrder) + + val actualDesktop = datastoreRepository.readDesktop(DEFAULT_USER_ID, DEFAULT_DESKTOP_ID) + assertThat(actualDesktop.tasksByTaskIdMap).hasSize(2) + assertThat(actualDesktop.getZOrderedTasks(0)).isEqualTo(2) + } + } + + @Test + fun addOrUpdateTask_changeTaskStateToMinimize_taskStateIsMinimized() { + runTest(StandardTestDispatcher()) { + val task = createDesktopTask(1) + val DesktopPersistentRepositories = createRepositoryWithOneDesk(task) + testDatastore.updateData { DesktopPersistentRepositories } + // Create a new state to be initialized + val visibleTasks = ArraySet(listOf(1)) + val minimizedTasks = ArraySet(listOf(1)) + val freeformTasksInZOrder = ArrayList(listOf(1)) + + // Update with new state + datastoreRepository.addOrUpdateDesktop( + visibleTasks = visibleTasks, + minimizedTasks = minimizedTasks, + freeformTasksInZOrder = freeformTasksInZOrder) + + val actualDesktop = datastoreRepository.readDesktop(DEFAULT_USER_ID, DEFAULT_DESKTOP_ID) + assertThat(actualDesktop.tasksByTaskIdMap[task.taskId]?.desktopTaskState) + .isEqualTo(DesktopTaskState.MINIMIZED) + } + } + + @Test + fun removeTask_previouslyAddedTaskIsRemoved() { + runTest(StandardTestDispatcher()) { + val task = createDesktopTask(1) + val DesktopPersistentRepositories = createRepositoryWithOneDesk(task) + testDatastore.updateData { DesktopPersistentRepositories } + // Create a new state to be initialized + val visibleTasks = ArraySet<Int>() + val minimizedTasks = ArraySet<Int>() + val freeformTasksInZOrder = ArrayList<Int>() + + // Update with new state + datastoreRepository.addOrUpdateDesktop( + visibleTasks = visibleTasks, + minimizedTasks = minimizedTasks, + freeformTasksInZOrder = freeformTasksInZOrder) + + val actualDesktop = datastoreRepository.readDesktop(DEFAULT_USER_ID, DEFAULT_DESKTOP_ID) + assertThat(actualDesktop.tasksByTaskIdMap).isEmpty() + assertThat(actualDesktop.zOrderedTasksList).isEmpty() + } + } + + private companion object { + const val DESKTOP_REPOSITORY_STATES_DATASTORE_TEST_FILE = "desktop_repo_test.pb" + const val DEFAULT_USER_ID = 1000 + const val DEFAULT_DESKTOP_ID = 0 + + fun createRepositoryWithOneDesk(task: DesktopTask): DesktopPersistentRepositories { + val desk = createDesktop(task) + val repositoryState = + DesktopRepositoryState.newBuilder().putDesktop(DEFAULT_DESKTOP_ID, desk) + val DesktopPersistentRepositories = + DesktopPersistentRepositories.newBuilder() + .putDesktopRepoByUser(DEFAULT_USER_ID, repositoryState.build()) + .build() + return DesktopPersistentRepositories + } + + fun createDesktop(task: DesktopTask): Desktop? = + Desktop.newBuilder() + .setDisplayId(DEFAULT_DISPLAY) + .addZOrderedTasks(task.taskId) + .putTasksByTaskId(task.taskId, task) + .build() + + fun createDesktopTask( + taskId: Int, + state: DesktopTaskState = DesktopTaskState.VISIBLE + ): DesktopTask = + DesktopTask.newBuilder().setTaskId(taskId).setDesktopTaskState(state).build() + } +} 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 ee2a41c322c9..3051714b5ae8 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 @@ -100,7 +100,6 @@ 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 import java.util.function.Supplier @@ -186,7 +185,6 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { 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 private val transactionFactory = Supplier<SurfaceControl.Transaction> { @@ -236,7 +234,6 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { mockGenericLinksParser, mockAssistContentRequester, mockMultiInstanceHelper, - mockWindowDecorViewHostSupplier, mockDesktopModeWindowDecorFactory, mockInputMonitorFactory, transactionFactory, @@ -1217,7 +1214,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { 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(), 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 a1867f3698fc..f007115c6dab 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 @@ -47,6 +47,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.mockito.kotlin.VerificationKt.times; import android.app.ActivityManager; import android.app.assist.AssistContent; @@ -106,8 +107,6 @@ 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; import kotlin.Unit; import kotlin.jvm.functions.Function0; @@ -178,10 +177,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { @Mock private WindowDecoration.SurfaceControlViewHostFactory mMockSurfaceControlViewHostFactory; @Mock - private WindowDecorViewHostSupplier mMockWindowDecorViewHostSupplier; - @Mock - private WindowDecorViewHost mMockWindowDecorViewHost; - @Mock private TypedArray mMockRoundedCornersRadiusArray; @Mock private TestTouchEventListener mMockTouchEventListener; @@ -257,9 +252,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { anyBoolean(), anyBoolean(), anyBoolean(), any(), anyInt(), anyInt(), anyInt())) .thenReturn(mMockHandleMenu); when(mMockMultiInstanceHelper.supportsMultiInstanceSplit(any())).thenReturn(false); - 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); } @@ -533,56 +525,61 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { } @Test - public void updateRelayoutParams_handle_requestsAsyncViewHostRendering() { + public void relayout_fullscreenTask_appliesTransactionImmediately() { final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); - // Make the task fullscreen so that its decoration is an App Handle. + final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); - final RelayoutParams relayoutParams = new RelayoutParams(); - DesktopModeWindowDecoration.updateRelayoutParams( - relayoutParams, - mTestableContext, - taskInfo, - /* applyStartTransactionOnDraw= */ true, - /* shouldSetTaskPositionAndCrop */ false); + spyWindowDecor.relayout(taskInfo); - // App Handles don't need to be rendered in sync with the task animation, per UX. - assertThat(relayoutParams.mAsyncViewHost).isTrue(); + verify(mMockTransaction).apply(); + verify(mMockRootSurfaceControl, never()).applyTransactionOnDraw(any()); } @Test - public void updateRelayoutParams_header_requestsSyncViewHostRendering() { + @Ignore("TODO(b/367235906): Due to MONITOR_INPUT permission error") + public void relayout_freeformTask_appliesTransactionOnDraw() { final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); - // Make the task freeform so that its decoration is an App Header. + final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); - final RelayoutParams relayoutParams = new RelayoutParams(); + // Make non-resizable to avoid dealing with input-permissions (MONITOR_INPUT) + taskInfo.isResizeable = false; - DesktopModeWindowDecoration.updateRelayoutParams( - relayoutParams, - mTestableContext, - taskInfo, - /* applyStartTransactionOnDraw= */ true, - /* shouldSetTaskPositionAndCrop */ false); + spyWindowDecor.relayout(taskInfo); - // App Headers must be rendered in sync with the task animation, so it cannot be delayed. - assertThat(relayoutParams.mAsyncViewHost).isFalse(); + verify(mMockTransaction, never()).apply(); + verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockTransaction); } @Test - public void relayout_fullscreenTask_appliesTransactionImmediately() { + public void relayout_fullscreenTask_doesNotCreateViewHostImmediately() { final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); spyWindowDecor.relayout(taskInfo); - verify(mMockTransaction).apply(); - verify(mMockRootSurfaceControl, never()).applyTransactionOnDraw(any()); + verify(mMockSurfaceControlViewHostFactory, never()).create(any(), any(), any()); + } + + @Test + public void relayout_fullscreenTask_postsViewHostCreation() { + final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); + final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); + taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + + ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class); + spyWindowDecor.relayout(taskInfo); + + // Once for view host, the other for the AppHandle input layer. + verify(mMockHandler, times(2)).post(runnableArgument.capture()); + runnableArgument.getValue().run(); + verify(mMockSurfaceControlViewHostFactory).create(any(), any(), any()); } @Test @Ignore("TODO(b/367235906): Due to MONITOR_INPUT permission error") - public void relayout_freeformTask_appliesTransactionOnDraw() { + public void relayout_freeformTask_createsViewHostImmediately() { final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); @@ -591,8 +588,38 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { spyWindowDecor.relayout(taskInfo); - verify(mMockTransaction, never()).apply(); - verify(mMockWindowDecorViewHost).updateView(any(), any(), any(), eq(mMockTransaction)); + verify(mMockSurfaceControlViewHostFactory).create(any(), any(), any()); + verify(mMockHandler, never()).post(any()); + } + + @Test + public void relayout_removesExistingHandlerCallback() { + final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); + final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); + taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class); + spyWindowDecor.relayout(taskInfo); + // Once for view host, the other for the AppHandle input layer. + verify(mMockHandler, times(2)).post(runnableArgument.capture()); + + spyWindowDecor.relayout(taskInfo); + + verify(mMockHandler).removeCallbacks(runnableArgument.getValue()); + } + + @Test + public void close_removesExistingHandlerCallback() { + final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); + final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); + taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class); + spyWindowDecor.relayout(taskInfo); + // Once for view host, the other for the AppHandle input layer. + verify(mMockHandler, times(2)).post(runnableArgument.capture()); + + spyWindowDecor.close(); + + verify(mMockHandler).removeCallbacks(runnableArgument.getValue()); } @Test @@ -623,7 +650,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { .postDelayed(mCloseMaxMenuRunnable.capture(), eq(CLOSE_MAXIMIZE_MENU_DELAY_MS)); mCloseMaxMenuRunnable.getValue().run(); - verify(menu).close(); + verify(menu).close(any()); assertFalse(decoration.isMaximizeMenuActive()); } @@ -642,7 +669,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { .postDelayed(mCloseMaxMenuRunnable.capture(), eq(CLOSE_MAXIMIZE_MENU_DELAY_MS)); mCloseMaxMenuRunnable.getValue().run(); - verify(menu).close(); + verify(menu).close(any()); assertFalse(decoration.isMaximizeMenuActive()); } @@ -1065,7 +1092,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { mMockGenericLinksParser, mMockAssistContentRequester, SurfaceControl.Builder::new, mMockTransactionSupplier, WindowContainerTransaction::new, SurfaceControl::new, new WindowManagerWrapper(mMockWindowManager), mMockSurfaceControlViewHostFactory, - mMockWindowDecorViewHostSupplier, maximizeMenuFactory, mMockHandleMenuFactory, + maximizeMenuFactory, mMockHandleMenuFactory, mMockMultiInstanceHelper, mMockCaptionHandleRepository); windowDecor.setCaptionListeners(mMockTouchEventListener, mMockTouchEventListener, mMockTouchEventListener, mMockTouchEventListener); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java index 7252b32efc6b..2e117ac9f865 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java @@ -85,8 +85,6 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import com.android.wm.shell.tests.R; import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer; -import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHost; -import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier; import org.junit.Before; import org.junit.Rule; @@ -130,10 +128,6 @@ public class WindowDecorationTests extends ShellTestCase { @Mock private SurfaceControlViewHost mMockSurfaceControlViewHost; @Mock - private WindowDecorViewHostSupplier mMockWindowDecorViewHostSupplier; - @Mock - private WindowDecorViewHost mMockWindowDecorViewHost; - @Mock private AttachedSurfaceControl mMockRootSurfaceControl; @Mock private TestView mMockView; @@ -173,9 +167,6 @@ public class WindowDecorationTests extends ShellTestCase { when(mMockSurfaceControlViewHost.getRootSurfaceControl()) .thenReturn(mMockRootSurfaceControl); when(mMockView.findViewById(anyInt())).thenReturn(mMockView); - when(mMockWindowDecorViewHostSupplier.acquire(any(), any())) - .thenReturn(mMockWindowDecorViewHost); - when(mMockWindowDecorViewHost.getSurfaceControl()).thenReturn(mock(SurfaceControl.class)); // Add status bar inset so that WindowDecoration does not think task is in immersive mode mInsetsState.getOrCreateSource(STATUS_BAR_INSET_SOURCE_ID, statusBars()).setVisible(true); @@ -239,6 +230,10 @@ public class WindowDecorationTests extends ShellTestCase { final SurfaceControl.Builder decorContainerSurfaceBuilder = createMockSurfaceControlBuilder(decorContainerSurface); mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder); + final SurfaceControl captionContainerSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder captionContainerSurfaceBuilder = + createMockSurfaceControlBuilder(captionContainerSurface); + mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder); final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder() .setDisplayId(Display.DEFAULT_DISPLAY) @@ -259,18 +254,18 @@ public class WindowDecorationTests extends ShellTestCase { verify(mMockSurfaceControlStartT).setTrustedOverlay(decorContainerSurface, true); verify(mMockSurfaceControlStartT).setWindowCrop(decorContainerSurface, 300, 100); - final SurfaceControl captionContainerSurface = mMockWindowDecorViewHost.getSurfaceControl(); - verify(mMockSurfaceControlStartT).reparent(captionContainerSurface, decorContainerSurface); + verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface); + verify(captionContainerSurfaceBuilder).setContainerLayer(); verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64); verify(mMockSurfaceControlStartT).show(captionContainerSurface); - verify(mMockWindowDecorViewHost).updateView( - same(mMockView), - argThat(lp -> lp.height == 64 - && lp.width == 300 - && (lp.flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0), - eq(taskInfo.configuration), - eq(null) /* onDrawTransaction */); + verify(mMockSurfaceControlViewHostFactory).create(any(), eq(defaultDisplay), any()); + + verify(mMockSurfaceControlViewHost) + .setView(same(mMockView), + argThat(lp -> lp.height == 64 + && lp.width == 300 + && (lp.flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0)); verify(mMockView).setTaskFocusState(true); verify(mMockWindowContainerTransaction).addInsetsSource( eq(taskInfo.token), @@ -301,6 +296,10 @@ public class WindowDecorationTests extends ShellTestCase { final SurfaceControl.Builder decorContainerSurfaceBuilder = createMockSurfaceControlBuilder(decorContainerSurface); mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder); + final SurfaceControl captionContainerSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder captionContainerSurfaceBuilder = + createMockSurfaceControlBuilder(captionContainerSurface); + mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder); final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); mMockSurfaceControlTransactions.add(t); @@ -323,7 +322,7 @@ public class WindowDecorationTests extends ShellTestCase { windowDecor.relayout(taskInfo); - verify(mMockWindowDecorViewHost, never()).release(any()); + verify(mMockSurfaceControlViewHost, never()).release(); verify(t, never()).apply(); verify(mMockWindowContainerTransaction, never()) .removeInsetsSource(eq(taskInfo.token), any(), anyInt(), anyInt()); @@ -333,8 +332,9 @@ public class WindowDecorationTests extends ShellTestCase { taskInfo.isVisible = false; windowDecor.relayout(taskInfo); - final InOrder releaseOrder = inOrder(t2, mMockWindowDecorViewHostSupplier); - releaseOrder.verify(mMockWindowDecorViewHostSupplier).release(mMockWindowDecorViewHost, t2); + final InOrder releaseOrder = inOrder(t2, mMockSurfaceControlViewHost); + releaseOrder.verify(mMockSurfaceControlViewHost).release(); + releaseOrder.verify(t2).remove(captionContainerSurface); releaseOrder.verify(t2).remove(decorContainerSurface); releaseOrder.verify(t2).apply(); // Expect to remove two insets sources, the caption insets and the mandatory gesture insets. @@ -382,8 +382,8 @@ public class WindowDecorationTests extends ShellTestCase { verify(mMockDisplayController).removeDisplayWindowListener(same(listener)); assertThat(mRelayoutResult.mRootView).isSameInstanceAs(mMockView); - verify(mMockWindowDecorViewHostSupplier).acquire(any(), eq(mockDisplay)); - verify(mMockWindowDecorViewHost).updateView(same(mMockView), any(), any(), any()); + verify(mMockSurfaceControlViewHostFactory).create(any(), eq(mockDisplay), any()); + verify(mMockSurfaceControlViewHost).setView(same(mMockView), any()); } @Test @@ -396,6 +396,10 @@ public class WindowDecorationTests extends ShellTestCase { final SurfaceControl.Builder decorContainerSurfaceBuilder = createMockSurfaceControlBuilder(decorContainerSurface); mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder); + final SurfaceControl captionContainerSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder captionContainerSurfaceBuilder = + createMockSurfaceControlBuilder(captionContainerSurface); + mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder); final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); mMockSurfaceControlTransactions.add(t); @@ -432,7 +436,8 @@ public class WindowDecorationTests extends ShellTestCase { windowDecor.mDecorWindowContext.getResources(), mRelayoutParams.mCaptionHeightId); verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, width, height); verify(mMockSurfaceControlAddWindowT).show(additionalWindowSurface); - verify(mMockSurfaceControlViewHostFactory).create(any(), eq(defaultDisplay), any()); + verify(mMockSurfaceControlViewHostFactory, Mockito.times(2)) + .create(any(), eq(defaultDisplay), any()); } @Test @@ -445,6 +450,10 @@ public class WindowDecorationTests extends ShellTestCase { final SurfaceControl.Builder decorContainerSurfaceBuilder = createMockSurfaceControlBuilder(decorContainerSurface); mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder); + final SurfaceControl captionContainerSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder captionContainerSurfaceBuilder = + createMockSurfaceControlBuilder(captionContainerSurface); + mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder); final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); mMockSurfaceControlTransactions.add(t); @@ -464,8 +473,8 @@ public class WindowDecorationTests extends ShellTestCase { windowDecor.relayout(taskInfo); - final SurfaceControl captionContainerSurface = mMockWindowDecorViewHost.getSurfaceControl(); - verify(mMockSurfaceControlStartT).reparent(captionContainerSurface, decorContainerSurface); + verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface); + verify(captionContainerSurfaceBuilder).setContainerLayer(); // Width of the captionContainerSurface should match the width of TASK_BOUNDS verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64); verify(mMockSurfaceControlStartT).show(captionContainerSurface); @@ -481,6 +490,10 @@ public class WindowDecorationTests extends ShellTestCase { final SurfaceControl.Builder decorContainerSurfaceBuilder = createMockSurfaceControlBuilder(decorContainerSurface); mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder); + final SurfaceControl captionContainerSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder captionContainerSurfaceBuilder = + createMockSurfaceControlBuilder(captionContainerSurface); + mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder); final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); mMockSurfaceControlTransactions.add(t); @@ -498,11 +511,9 @@ public class WindowDecorationTests extends ShellTestCase { taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo); - mRelayoutParams.mApplyStartTransactionOnDraw = true; - windowDecor.relayout(taskInfo); + windowDecor.relayout(taskInfo, true /* applyStartTransactionOnDraw */); - verify(mMockWindowDecorViewHost).updateView(any(), any(), any(), - eq(mMockSurfaceControlStartT)); + verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockSurfaceControlStartT); } @Test @@ -856,52 +867,37 @@ public class WindowDecorationTests extends ShellTestCase { } @Test - public void relayout_applyTransactionOnDrawIsTrue_updatesViewWithDrawTransaction() { + public void updateViewHost_applyTransactionOnDrawIsTrue_surfaceControlIsUpdated() { final TestWindowDecoration windowDecor = createWindowDecoration( - new TestRunningTaskInfoBuilder() - .setVisible(true) - .setWindowingMode(WINDOWING_MODE_FREEFORM) - .build()); + new TestRunningTaskInfoBuilder().build()); mRelayoutParams.mApplyStartTransactionOnDraw = true; mRelayoutResult.mRootView = mMockView; - windowDecor.relayout(windowDecor.mTaskInfo); + windowDecor.updateViewHost(mRelayoutParams, mMockSurfaceControlStartT, mRelayoutResult); - verify(mMockWindowDecorViewHost) - .updateView(eq(mRelayoutResult.mRootView), any(), - eq(windowDecor.mTaskInfo.configuration), eq(mMockSurfaceControlStartT)); + verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockSurfaceControlStartT); } @Test - public void relayout_applyTransactionOnDrawIsTrue_asyncViewHostRendering_throwsException() { + public void updateViewHost_nullDrawTransaction_applyTransactionOnDrawIsTrue_throwsException() { final TestWindowDecoration windowDecor = createWindowDecoration( - new TestRunningTaskInfoBuilder() - .setVisible(true) - .setWindowingMode(WINDOWING_MODE_FULLSCREEN) - .build()); + new TestRunningTaskInfoBuilder().build()); mRelayoutParams.mApplyStartTransactionOnDraw = true; - mRelayoutParams.mAsyncViewHost = true; mRelayoutResult.mRootView = mMockView; assertThrows(IllegalArgumentException.class, - () -> windowDecor.relayout(windowDecor.mTaskInfo)); + () -> windowDecor.updateViewHost( + mRelayoutParams, null /* onDrawTransaction */, mRelayoutResult)); } @Test - public void relayout_asyncViewHostRendering() { + public void updateViewHost_nullDrawTransaction_applyTransactionOnDrawIsFalse_doesNotThrow() { final TestWindowDecoration windowDecor = createWindowDecoration( - new TestRunningTaskInfoBuilder() - .setVisible(true) - .setWindowingMode(WINDOWING_MODE_FULLSCREEN) - .build()); - mRelayoutParams.mAsyncViewHost = true; + new TestRunningTaskInfoBuilder().build()); + mRelayoutParams.mApplyStartTransactionOnDraw = false; mRelayoutResult.mRootView = mMockView; - windowDecor.relayout(windowDecor.mTaskInfo); - - verify(mMockWindowDecorViewHost) - .updateViewAsync(eq(mRelayoutResult.mRootView), any(), - eq(windowDecor.mTaskInfo.configuration)); + windowDecor.updateViewHost(mRelayoutParams, null /* onDrawTransaction */, mRelayoutResult); } @Test @@ -1001,8 +997,7 @@ public class WindowDecorationTests extends ShellTestCase { new MockObjectSupplier<>(mMockSurfaceControlTransactions, () -> mock(SurfaceControl.Transaction.class)), () -> mMockWindowContainerTransaction, () -> mMockTaskSurface, - mMockSurfaceControlViewHostFactory, - mMockWindowDecorViewHostSupplier); + mMockSurfaceControlViewHostFactory); } private class MockObjectSupplier<T> implements Supplier<T> { @@ -1042,20 +1037,16 @@ public class WindowDecorationTests extends ShellTestCase { Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier, Supplier<WindowContainerTransaction> windowContainerTransactionSupplier, Supplier<SurfaceControl> surfaceControlSupplier, - SurfaceControlViewHostFactory surfaceControlViewHostFactory, - @NonNull WindowDecorViewHostSupplier windowDecorViewHostSupplier) { + SurfaceControlViewHostFactory surfaceControlViewHostFactory) { super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface, surfaceControlBuilderSupplier, surfaceControlTransactionSupplier, windowContainerTransactionSupplier, surfaceControlSupplier, - surfaceControlViewHostFactory, windowDecorViewHostSupplier); + surfaceControlViewHostFactory); } @Override void relayout(ActivityManager.RunningTaskInfo taskInfo) { - mRelayoutParams.mRunningTaskInfo = taskInfo; - mRelayoutParams.mLayoutResId = R.layout.caption_layout; - relayout(mRelayoutParams, mMockSurfaceControlStartT, mMockSurfaceControlFinishT, - mMockWindowContainerTransaction, mMockView, mRelayoutResult); + relayout(taskInfo, false /* applyStartTransactionOnDraw */); } @Override @@ -1076,6 +1067,15 @@ public class WindowDecorationTests extends ShellTestCase { return super.inflateLayout(context, layoutResId); } + void relayout(ActivityManager.RunningTaskInfo taskInfo, + boolean applyStartTransactionOnDraw) { + mRelayoutParams.mRunningTaskInfo = taskInfo; + mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw; + mRelayoutParams.mLayoutResId = R.layout.caption_layout; + relayout(mRelayoutParams, mMockSurfaceControlStartT, mMockSurfaceControlFinishT, + mMockWindowContainerTransaction, mMockView, mRelayoutResult); + } + private AdditionalViewContainer addTestViewContainer() { final Resources resources = mDecorWindowContext.getResources(); final int width = loadDimensionPixelSize(resources, mCaptionMenuWidthId); 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 deleted file mode 100644 index 1b2ce9e4df36..000000000000 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostTest.kt +++ /dev/null @@ -1,222 +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 kotlinx.coroutines.CoroutineScope -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 -import org.mockito.kotlin.spy -import org.mockito.kotlin.verify - - -/** - * Tests for [DefaultWindowDecorViewHost]. - * - * Build/Install/Run: - * atest WMShellUnitTests:DefaultWindowDecorViewHostTest - */ -@SmallTest -@TestableLooper.RunWithLooper -@RunWith(AndroidTestingRunner::class) -class DefaultWindowDecorViewHostTest : ShellTestCase() { - - @Test - fun updateView_layoutInViewHost() = runTest { - val windowDecorViewHost = createDefaultViewHost() - val view = View(context) - - windowDecorViewHost.updateView( - view = view, - attrs = WindowManager.LayoutParams(100, 100), - configuration = context.resources.configuration, - onDrawTransaction = null - ) - - 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) - @Test - fun updateView_clearsPendingAsyncJob() = runTest { - val windowDecorViewHost = createDefaultViewHost() - val asyncView = View(context) - val syncView = View(context) - val asyncAttrs = WindowManager.LayoutParams(100, 100) - val syncAttrs = WindowManager.LayoutParams(200, 200) - - windowDecorViewHost.updateViewAsync( - view = asyncView, - attrs = asyncAttrs, - configuration = context.resources.configuration, - ) - - // No view host yet, since the coroutine hasn't run. - assertThat(windowDecorViewHost.viewHost).isNull() - - windowDecorViewHost.updateView( - view = syncView, - attrs = syncAttrs, - configuration = context.resources.configuration, - onDrawTransaction = null - ) - - // Would run coroutine if it hadn't been cancelled. - advanceUntilIdle() - - 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.viewHost!!.view).isEqualTo(syncView) - assertThat(windowDecorViewHost.viewHost!!.view!!.layoutParams.width) - .isEqualTo(syncAttrs.width) - } - - @OptIn(ExperimentalCoroutinesApi::class) - @Test - fun updateViewAsync() = runTest { - val windowDecorViewHost = createDefaultViewHost() - val view = View(context) - val attrs = WindowManager.LayoutParams(100, 100) - - windowDecorViewHost.updateViewAsync( - view = view, - attrs = attrs, - configuration = context.resources.configuration, - ) - - assertThat(windowDecorViewHost.viewHost).isNull() - - advanceUntilIdle() - - assertThat(windowDecorViewHost.viewHost).isNotNull() - } - - @OptIn(ExperimentalCoroutinesApi::class) - @Test - fun updateViewAsync_clearsPendingAsyncJob() = runTest { - val windowDecorViewHost = createDefaultViewHost() - - val view = View(context) - windowDecorViewHost.updateViewAsync( - view = view, - attrs = WindowManager.LayoutParams(100, 100), - configuration = context.resources.configuration, - ) - val otherView = View(context) - windowDecorViewHost.updateViewAsync( - view = otherView, - attrs = WindowManager.LayoutParams(100, 100), - configuration = context.resources.configuration, - ) - - advanceUntilIdle() - - assertThat(windowDecorViewHost.viewHost).isNotNull() - assertThat(windowDecorViewHost.viewHost!!.view).isNotNull() - assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(otherView) - } - - @Test - fun release() = runTest { - val windowDecorViewHost = createDefaultViewHost() - - val view = View(context) - windowDecorViewHost.updateView( - view = view, - attrs = WindowManager.LayoutParams(100, 100), - configuration = context.resources.configuration, - onDrawTransaction = null - ) - - val t = mock(SurfaceControl.Transaction::class.java) - windowDecorViewHost.release(t) - - verify(windowDecorViewHost.viewHost!!).release() - verify(t).remove(windowDecorViewHost.surfaceControl) - } - - private fun CoroutineScope.createDefaultViewHost() = DefaultWindowDecorViewHost( - context = context, - mainScope = this, - display = context.display, - surfaceControlViewHostFactory = { c, d, wwm, s -> - spy(SurfaceControlViewHost(c, d, wwm, s)) - } - ) -}
\ No newline at end of file diff --git a/libs/appfunctions/Android.bp b/libs/appfunctions/Android.bp index 09e2f423c3ba..c6cee07d1946 100644 --- a/libs/appfunctions/Android.bp +++ b/libs/appfunctions/Android.bp @@ -29,3 +29,11 @@ java_sdk_library { 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/appfunctions.sidecar.xml b/libs/appfunctions/appfunctions.sidecar.xml new file mode 100644 index 000000000000..bef8b6ec7ce6 --- /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/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 589abb4d87f4..2c23864317a4 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -404,13 +404,19 @@ void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) { } } +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 @@ void RenderNode::handleForceDark(android::uirenderer::TreeInfo *info) { 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 c9045427bd42..afbbce7e27ee 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -234,6 +234,7 @@ private: 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/jni/GraphicsStatsService.cpp b/libs/hwui/jni/GraphicsStatsService.cpp index 54369b9e4384..80a8ae1d8c17 100644 --- a/libs/hwui/jni/GraphicsStatsService.cpp +++ b/libs/hwui/jni/GraphicsStatsService.cpp @@ -42,8 +42,9 @@ static jlong createDump(JNIEnv*, jobject, jint fd, jboolean isProto) { 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 @@ static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jstrin 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 @@ static void finishDumpInMemory(JNIEnv* env, jobject, jlong dumpPtr, jlong pulled 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 @@ static void saveBuffer(JNIEnv* env, jobject clazz, jstring jpath, jstring jpacka 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 @@ static void nativeDestructor(JNIEnv* env, jobject javaObject) { } // 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/protos/graphicsstats.proto b/libs/hwui/protos/graphicsstats.proto index 745393ce1a3d..a6e786c07053 100644 --- a/libs/hwui/protos/graphicsstats.proto +++ b/libs/hwui/protos/graphicsstats.proto @@ -58,6 +58,9 @@ message GraphicsStatsProto { // 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 ece59051dae7..702f2a5626f7 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 @@ static_assert(sizeof(sCurrentFileVersion) == sHeaderSize, "Header size is wrong" 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 @@ bool GraphicsStatsService::parseFromFile(const std::string& path, 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 @@ void dumpAsTextToFd(protos::GraphicsStatsProto* proto, int fd) { 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 @@ void dumpAsTextToFd(protos::GraphicsStatsProto* proto, int fd) { 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 @@ public: 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 @@ private: }; 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 @@ GraphicsStatsService::Dump* GraphicsStatsService::createDump(int outFd, DumpType 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 @@ void GraphicsStatsService::finishDumpInMemory(Dump* dump, AStatsEventList* data, // 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 4063f749f808..68c735586f4b 100644 --- a/libs/hwui/service/GraphicsStatsService.h +++ b/libs/hwui/service/GraphicsStatsService.h @@ -44,13 +44,14 @@ public: 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 c2d23e6d1101..eb164f97c9a2 100644 --- a/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp +++ b/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp @@ -62,6 +62,7 @@ TEST(GraphicsStats, findRootPath) { 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 @@ TEST(GraphicsStats, saveLoad) { 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, saveLoad) { 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 @@ TEST(GraphicsStats, merge) { 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 @@ TEST(GraphicsStats, merge) { 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/media/java/android/media/flags/editing.aconfig b/media/java/android/media/flags/editing.aconfig index bf6ec9635912..185f579df4b9 100644 --- a/media/java/android/media/flags/editing.aconfig +++ b/media/java/android/media/flags/editing.aconfig @@ -8,3 +8,10 @@ flag { description: "Add media metrics for transcoding/editing events." bug: "297487694" } + +flag { + name: "stagefrightrecorder_enable_b_frames" + namespace: "media_solutions" + description: "Enable B frames for Stagefright recorder." + bug: "341121900" +} diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java index 244292d15e81..bfc13243af68 100644 --- a/media/java/android/media/midi/MidiManager.java +++ b/media/java/android/media/midi/MidiManager.java @@ -393,6 +393,16 @@ public final class MidiManager { /** * 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/nfc/api/system-current.txt b/nfc/api/system-current.txt index 9603c0a9f7c7..d17a9b62d02d 100644 --- a/nfc/api/system-current.txt +++ b/nfc/api/system-current.txt @@ -60,7 +60,7 @@ package android.nfc { 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.NFC_SET_CONTROLLER_ALWAYS_ON) public void setControllerAlwaysOnMode(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 diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java index 28045460ef27..951702ceef0b 100644 --- a/nfc/java/android/nfc/NfcAdapter.java +++ b/nfc/java/android/nfc/NfcAdapter.java @@ -560,13 +560,13 @@ public final class NfcAdapter { public @interface TagIntentAppPreferenceResult {} /** - * Mode Type for {@link NfcOemExtension#setControllerAlwaysOn(int)}. + * Mode Type for {@link NfcOemExtension#setControllerAlwaysOnMode(int)}. * @hide */ public static final int CONTROLLER_ALWAYS_ON_MODE_DEFAULT = 1; /** - * Mode Type for {@link NfcOemExtension#setControllerAlwaysOn(int)}. + * Mode Type for {@link NfcOemExtension#setControllerAlwaysOnMode(int)}. * @hide */ public static final int CONTROLLER_ALWAYS_ON_DISABLE = 0; @@ -2323,7 +2323,7 @@ public final class NfcAdapter { * <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 a listener {@link #ControllerAlwaysOnListener} + * <p>This call is asynchronous. Register a listener {@link ControllerAlwaysOnListener} * by {@link #registerControllerAlwaysOnListener} to find out when the operation is * complete. * <p>If this returns true, then either NFCC always on state has been set based on the value, @@ -2337,7 +2337,7 @@ public final class NfcAdapter { * 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 true if feature is supported by the device and operation has bee initiated, + * @return true if feature is supported by the device and operation has been initiated, * false if the feature is not supported by the device. * @hide */ diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java index 45038d41e237..011c60b080f8 100644 --- a/nfc/java/android/nfc/NfcOemExtension.java +++ b/nfc/java/android/nfc/NfcOemExtension.java @@ -70,7 +70,7 @@ public final class NfcOemExtension { private boolean mRfDiscoveryStarted = false; /** - * Mode Type for {@link #setControllerAlwaysOn(int)}. + * Mode Type for {@link #setControllerAlwaysOnMode(int)}. * Enables the controller in default mode when NFC is disabled (existing API behavior). * works same as {@link NfcAdapter#setControllerAlwaysOn(boolean)}. * @hide @@ -80,7 +80,7 @@ public final class NfcOemExtension { public static final int ENABLE_DEFAULT = NfcAdapter.CONTROLLER_ALWAYS_ON_MODE_DEFAULT; /** - * Mode Type for {@link #setControllerAlwaysOn(int)}. + * Mode Type for {@link #setControllerAlwaysOnMode(int)}. * Enables the controller in transparent mode when NFC is disabled. * @hide */ @@ -89,7 +89,7 @@ public final class NfcOemExtension { public static final int ENABLE_TRANSPARENT = 2; /** - * Mode Type for {@link #setControllerAlwaysOn(int)}. + * Mode Type for {@link #setControllerAlwaysOnMode(int)}. * Enables the controller and initializes and enables the EE subsystem when NFC is disabled. * @hide */ @@ -98,7 +98,7 @@ public final class NfcOemExtension { public static final int ENABLE_EE = 3; /** - * Mode Type for {@link #setControllerAlwaysOn(int)}. + * Mode Type for {@link #setControllerAlwaysOnMode(int)}. * Disable the Controller Always On Mode. * works same as {@link NfcAdapter#setControllerAlwaysOn(boolean)}. * @hide @@ -108,7 +108,7 @@ public final class NfcOemExtension { public static final int DISABLE = NfcAdapter.CONTROLLER_ALWAYS_ON_DISABLE; /** - * Possible controller modes for {@link #setControllerAlwaysOn(int)}. + * Possible controller modes for {@link #setControllerAlwaysOnMode(int)}. * * @hide */ @@ -449,6 +449,9 @@ public final class NfcOemExtension { * <p>This call is asynchronous, register listener {@link NfcAdapter.ControllerAlwaysOnListener} * by {@link NfcAdapter#registerControllerAlwaysOnListener} to find out when the operation is * complete. + * <p> Note: This adds more always on modes on top of existing + * {@link NfcAdapter#setControllerAlwaysOn(boolean)} API which can be used to set the NFCC in + * only {@link #ENABLE_DEFAULT} and {@link #DISABLE} modes. * @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, @@ -456,11 +459,12 @@ public final class NfcOemExtension { * are unavailable </li> * <li> if the feature is unavailable @see NfcAdapter#isNfcControllerAlwaysOnSupported() </li> * @hide + * @see NfcAdapter#setControllerAlwaysOn(boolean) */ @SystemApi @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) - public void setControllerAlwaysOn(@ControllerMode int mode) { + public void setControllerAlwaysOnMode(@ControllerMode int mode) { if (!NfcAdapter.sHasNfcFeature && !NfcAdapter.sHasCeFeature) { throw new UnsupportedOperationException(); } diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp index baeff7e6c006..1661dfb2a86b 100644 --- a/packages/SettingsLib/SettingsTheme/Android.bp +++ b/packages/SettingsLib/SettingsTheme/Android.bp @@ -15,7 +15,10 @@ android_library { "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 000000000000..309dbdf1ea96 --- /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_chevron.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_chevron.xml new file mode 100644 index 000000000000..16ca18ae2200 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_chevron.xml @@ -0,0 +1,28 @@ +<?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="18dp" + android:height="18dp" + android:viewportWidth="960" + android:viewportHeight="960" + android:tint="@color/settingslib_materialColorOnSurfaceVariant" + android:autoMirrored="true"> + <path + android:fillColor="@android:color/white" + android:pathData="M321,880L250,809L579,480L250,151L321,80L721,480L321,880Z"/> +</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 000000000000..e6df8a416922 --- /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 000000000000..342729d7ee5a --- /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 f4766ee7b0a9..543b237373fb 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 40eafc224d31..6d2cd1a51620 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 f4766ee7b0a9..bcdbf1d19545 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 40eafc224d31..d4b658c384e6 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 000000000000..2475dfd90e6e --- /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 000000000000..f5017a5ae368 --- /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 000000000000..4cbdfd5b7c36 --- /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 000000000000..e3e689b4838c --- /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/layout-v35/settingslib_expressive_two_target_divider.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_two_target_divider.xml new file mode 100644 index 000000000000..3f751812ee40 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_two_target_divider.xml @@ -0,0 +1,39 @@ +<?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/two_target_divider" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="start|center_vertical" + android:orientation="horizontal" + android:paddingStart="?android:attr/listPreferredItemPaddingEnd" + android:paddingLeft="?android:attr/listPreferredItemPaddingEnd" + android:paddingVertical="@dimen/settingslib_expressive_space_extrasmall7"> + + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingEnd="@dimen/settingslib_expressive_space_extrasmall6" + android:src="@drawable/settingslib_expressive_icon_chevron"/> + + <View + android:layout_width="1dp" + android:layout_height="40dp" + android:background="?android:attr/listDivider" /> +</LinearLayout>
\ No newline at end of file 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 000000000000..2320aab8f459 --- /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 000000000000..04ae80e72401 --- /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 000000000000..3c69027c2080 --- /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 000000000000..fea8739ab37d --- /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 000000000000..41fe2250f0ad --- /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/Spa/build.gradle.kts b/packages/SettingsLib/Spa/build.gradle.kts index 3011ce05c3a5..b69912a3fd36 100644 --- a/packages/SettingsLib/Spa/build.gradle.kts +++ b/packages/SettingsLib/Spa/build.gradle.kts @@ -29,7 +29,7 @@ val androidTop: String = File(rootDir, "../../../../..").canonicalPath allprojects { extra["androidTop"] = androidTop - extra["jetpackComposeVersion"] = "1.7.0-rc01" + extra["jetpackComposeVersion"] = "1.7.0" } subprojects { diff --git a/packages/SettingsLib/Spa/gallery/res/values/strings.xml b/packages/SettingsLib/Spa/gallery/res/values/strings.xml index 18a6db035070..f942fd0662a5 100644 --- a/packages/SettingsLib/Spa/gallery/res/values/strings.xml +++ b/packages/SettingsLib/Spa/gallery/res/values/strings.xml @@ -26,6 +26,8 @@ <string name="single_line_summary_preference_summary" translatable="false">A very long summary to show case a preference which only shows a single line summary.</string> <!-- Footer text with two links. [DO NOT TRANSLATE] --> <string name="footer_with_two_links" translatable="false">Annotated string with <a href="https://www.android.com/">link 1</a> and <a href="https://source.android.com/">link 2</a>.</string> + <!-- TopIntroPreference preview text. [DO NOT TRANSLATE] --> + <string name="label_with_two_links" translatable="false"><a href="https://www.android.com/">Label</a></string> <!-- Sample title --> <string name="sample_title" translatable="false">Lorem ipsum</string> diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt index 83d657ef380d..7139f5b468ca 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt @@ -42,12 +42,15 @@ import com.android.settingslib.spa.gallery.page.LoadingBarPageProvider import com.android.settingslib.spa.gallery.page.ProgressBarPageProvider import com.android.settingslib.spa.gallery.scaffold.NonScrollablePagerPageProvider import com.android.settingslib.spa.gallery.page.SliderPageProvider +import com.android.settingslib.spa.gallery.preference.IntroPreferencePageProvider import com.android.settingslib.spa.gallery.preference.ListPreferencePageProvider import com.android.settingslib.spa.gallery.preference.MainSwitchPreferencePageProvider import com.android.settingslib.spa.gallery.preference.PreferenceMainPageProvider import com.android.settingslib.spa.gallery.preference.PreferencePageProvider import com.android.settingslib.spa.gallery.preference.SwitchPreferencePageProvider +import com.android.settingslib.spa.gallery.preference.TopIntroPreferencePageProvider import com.android.settingslib.spa.gallery.preference.TwoTargetSwitchPreferencePageProvider +import com.android.settingslib.spa.gallery.preference.ZeroStatePreferencePageProvider import com.android.settingslib.spa.gallery.scaffold.PagerMainPageProvider import com.android.settingslib.spa.gallery.scaffold.SearchScaffoldPageProvider import com.android.settingslib.spa.gallery.scaffold.SuwScaffoldPageProvider @@ -82,6 +85,7 @@ class GallerySpaEnvironment(context: Context) : SpaEnvironment(context) { MainSwitchPreferencePageProvider, ListPreferencePageProvider, TwoTargetSwitchPreferencePageProvider, + ZeroStatePreferencePageProvider, ArgumentPageProvider, SliderPageProvider, SpinnerPageProvider, @@ -109,6 +113,8 @@ class GallerySpaEnvironment(context: Context) : SpaEnvironment(context) { SuwScaffoldPageProvider, BannerPageProvider, CopyablePageProvider, + IntroPreferencePageProvider, + TopIntroPreferencePageProvider, ), rootPages = listOf( HomePageProvider.createSettingsPage(), diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPageProvider.kt index 1051549aa0cf..89b10ee2cb84 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPageProvider.kt @@ -33,10 +33,10 @@ import com.android.settingslib.spa.framework.common.SettingsPageProvider import com.android.settingslib.spa.framework.common.createSettingsPage import com.android.settingslib.spa.framework.compose.navigator import com.android.settingslib.spa.framework.theme.SettingsTheme -import com.android.settingslib.spa.widget.preference.SliderPreference -import com.android.settingslib.spa.widget.preference.SliderPreferenceModel import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spa.widget.preference.SliderPreference +import com.android.settingslib.spa.widget.preference.SliderPreferenceModel private const val TITLE = "Sample Slider" @@ -49,24 +49,30 @@ object SliderPageProvider : SettingsPageProvider { entryList.add( SettingsEntryBuilder.create("Simple Slider", owner) .setUiLayoutFn { - SliderPreference(object : SliderPreferenceModel { - override val title = "Simple Slider" - override val initValue = 40 - }) - }.build() + SliderPreference( + object : SliderPreferenceModel { + override val title = "Simple Slider" + override val initValue = 40 + } + ) + } + .build() ) entryList.add( SettingsEntryBuilder.create("Slider with icon", owner) .setUiLayoutFn { - SliderPreference(object : SliderPreferenceModel { - override val title = "Slider with icon" - override val initValue = 30 - override val onValueChangeFinished = { - println("onValueChangeFinished") + SliderPreference( + object : SliderPreferenceModel { + override val title = "Slider with icon" + override val initValue = 30 + override val onValueChangeFinished = { + println("onValueChangeFinished") + } + override val iconStart = Icons.Outlined.AccessAlarm } - override val icon = Icons.Outlined.AccessAlarm - }) - }.build() + ) + } + .build() ) entryList.add( SettingsEntryBuilder.create("Slider with changeable icon", owner) @@ -74,43 +80,52 @@ object SliderPageProvider : SettingsPageProvider { val initValue = 0 var icon by remember { mutableStateOf(Icons.Outlined.MusicOff) } var sliderPosition by remember { mutableStateOf(initValue) } - SliderPreference(object : SliderPreferenceModel { - override val title = "Slider with changeable icon" - override val initValue = initValue - override val onValueChange = { it: Int -> - sliderPosition = it - icon = if (it > 0) Icons.Outlined.MusicNote else Icons.Outlined.MusicOff - } - override val onValueChangeFinished = { - println("onValueChangeFinished: the value is $sliderPosition") + SliderPreference( + object : SliderPreferenceModel { + override val title = "Slider with changeable icon" + override val initValue = initValue + override val onValueChange = { it: Int -> + sliderPosition = it + icon = + if (it > 0) Icons.Outlined.MusicNote + else Icons.Outlined.MusicOff + } + override val onValueChangeFinished = { + println("onValueChangeFinished: the value is $sliderPosition") + } + override val iconEnd = icon } - override val icon = icon - }) - }.build() + ) + } + .build() ) entryList.add( SettingsEntryBuilder.create("Slider with steps", owner) .setUiLayoutFn { - SliderPreference(object : SliderPreferenceModel { - override val title = "Slider with steps" - override val initValue = 2 - override val valueRange = 1..5 - override val showSteps = true - }) - }.build() + SliderPreference( + object : SliderPreferenceModel { + override val title = "Slider with steps" + override val initValue = 2 + override val valueRange = 1..5 + override val showSteps = true + } + ) + } + .build() ) return entryList } fun buildInjectEntry(): SettingsEntryBuilder { - return SettingsEntryBuilder.createInject(owner) - .setUiLayoutFn { - Preference(object : PreferenceModel { + return SettingsEntryBuilder.createInject(owner).setUiLayoutFn { + Preference( + object : PreferenceModel { override val title = TITLE override val onClick = navigator(name) - }) - } + } + ) + } } override fun getTitle(arguments: Bundle?): String { @@ -121,7 +136,5 @@ object SliderPageProvider : SettingsPageProvider { @Preview(showBackground = true) @Composable private fun SliderPagePreview() { - SettingsTheme { - SliderPageProvider.Page(null) - } + SettingsTheme { SliderPageProvider.Page(null) } } diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/IntroPreferencePageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/IntroPreferencePageProvider.kt new file mode 100644 index 000000000000..603fceed9900 --- /dev/null +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/IntroPreferencePageProvider.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.spa.gallery.preference + +import android.os.Bundle +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.AirplanemodeActive +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.android.settingslib.spa.framework.common.SettingsEntry +import com.android.settingslib.spa.framework.common.SettingsEntryBuilder +import com.android.settingslib.spa.framework.common.SettingsPageProvider +import com.android.settingslib.spa.framework.common.createSettingsPage +import com.android.settingslib.spa.framework.compose.navigator +import com.android.settingslib.spa.widget.preference.IntroPreference +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel + +private const val TITLE = "Sample IntroPreference" + +object IntroPreferencePageProvider : SettingsPageProvider { + override val name = "IntroPreference" + private val owner = createSettingsPage() + + override fun buildEntry(arguments: Bundle?): List<SettingsEntry> { + val entryList = mutableListOf<SettingsEntry>() + entryList.add( + SettingsEntryBuilder.create("IntroPreference", owner) + .setUiLayoutFn { SampleIntroPreference() } + .build() + ) + + return entryList + } + + fun buildInjectEntry(): SettingsEntryBuilder { + return SettingsEntryBuilder.createInject(owner).setUiLayoutFn { + Preference( + object : PreferenceModel { + override val title = TITLE + override val onClick = navigator(name) + } + ) + } + } + + override fun getTitle(arguments: Bundle?): String { + return TITLE + } +} + +@Composable +private fun SampleIntroPreference() { + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + IntroPreference( + title = "Preferred network type", + descriptions = listOf("Description"), + imageVector = Icons.Outlined.AirplanemodeActive, + ) + } +} diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMainPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMainPageProvider.kt index ce9678bab684..1626b025e2f7 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMainPageProvider.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMainPageProvider.kt @@ -39,6 +39,9 @@ object PreferenceMainPageProvider : SettingsPageProvider { ListPreferencePageProvider.buildInjectEntry().setLink(fromPage = owner).build(), TwoTargetSwitchPreferencePageProvider.buildInjectEntry() .setLink(fromPage = owner).build(), + ZeroStatePreferencePageProvider.buildInjectEntry().setLink(fromPage = owner).build(), + IntroPreferencePageProvider.buildInjectEntry().setLink(fromPage = owner).build(), + TopIntroPreferencePageProvider.buildInjectEntry().setLink(fromPage = owner).build(), ) } diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TopIntroPreferencePageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TopIntroPreferencePageProvider.kt new file mode 100644 index 000000000000..b251266e0574 --- /dev/null +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TopIntroPreferencePageProvider.kt @@ -0,0 +1,83 @@ +/* + * 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.spa.gallery.preference + +import android.os.Bundle +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.android.settingslib.spa.gallery.R +import com.android.settingslib.spa.framework.common.SettingsEntry +import com.android.settingslib.spa.framework.common.SettingsEntryBuilder +import com.android.settingslib.spa.framework.common.SettingsPageProvider +import com.android.settingslib.spa.framework.common.createSettingsPage +import com.android.settingslib.spa.framework.compose.navigator +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spa.widget.preference.TopIntroPreference +import com.android.settingslib.spa.widget.preference.TopIntroPreferenceModel + +private const val TITLE = "Sample TopIntroPreference" + +object TopIntroPreferencePageProvider : SettingsPageProvider { + override val name = "TopIntroPreference" + private val owner = createSettingsPage() + + override fun buildEntry(arguments: Bundle?): List<SettingsEntry> { + val entryList = mutableListOf<SettingsEntry>() + entryList.add( + SettingsEntryBuilder.create("TopIntroPreference", owner) + .setUiLayoutFn { SampleTopIntroPreference() } + .build() + ) + + return entryList + } + + fun buildInjectEntry(): SettingsEntryBuilder { + return SettingsEntryBuilder.createInject(owner).setUiLayoutFn { + Preference( + object : PreferenceModel { + override val title = TITLE + override val onClick = navigator(name) + } + ) + } + } + + override fun getTitle(arguments: Bundle?): String { + return TITLE + } +} + +@Composable +private fun SampleTopIntroPreference() { + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + TopIntroPreference( + object : TopIntroPreferenceModel { + override val text = + "Additional text needed for the page. This can sit on the right side of the screen in 2 column.\n" + + "Example collapsed text area that you will not see until you expand this block." + override val expandText = "Expand" + override val collapseText = "Collapse" + override val labelText = R.string.label_with_two_links + } + ) + } +} diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/ZeroStatePreferencePageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/ZeroStatePreferencePageProvider.kt new file mode 100644 index 000000000000..4a9c5c8fad4f --- /dev/null +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/ZeroStatePreferencePageProvider.kt @@ -0,0 +1,92 @@ +/* + * 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.spa.gallery.preference + +import android.os.Bundle +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.History +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.android.settingslib.spa.framework.common.SettingsEntry +import com.android.settingslib.spa.framework.common.SettingsEntryBuilder +import com.android.settingslib.spa.framework.common.SettingsPageProvider +import com.android.settingslib.spa.framework.common.createSettingsPage +import com.android.settingslib.spa.framework.compose.navigator +import com.android.settingslib.spa.framework.theme.SettingsTheme +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spa.widget.preference.ZeroStatePreference + +private const val TITLE = "Sample ZeroStatePreference" + +object ZeroStatePreferencePageProvider : SettingsPageProvider { + override val name = "ZeroStatePreference" + private val owner = createSettingsPage() + + override fun buildEntry(arguments: Bundle?): List<SettingsEntry> { + val entryList = mutableListOf<SettingsEntry>() + entryList.add( + SettingsEntryBuilder.create("ZeroStatePreference", owner) + .setUiLayoutFn { + SampleZeroStatePreference() + }.build() + ) + + return entryList + } + + fun buildInjectEntry(): SettingsEntryBuilder { + return SettingsEntryBuilder.createInject(owner) + .setUiLayoutFn { + Preference(object : PreferenceModel { + override val title = TITLE + override val onClick = navigator(name) + }) + } + } + + override fun getTitle(arguments: Bundle?): String { + return TITLE + } +} + +@Composable +private fun SampleZeroStatePreference() { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + ZeroStatePreference( + Icons.Filled.History, + "No recent search history", + "Description" + ) + } +} + + +@Preview(showBackground = true) +@Composable +private fun SwitchPreferencePagePreview() { + SettingsTheme { + ZeroStatePreferencePageProvider.Page(null) + } +} diff --git a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/SliderPreferenceScreenshotTest.kt b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/SliderPreferenceScreenshotTest.kt index 3a96a7090d9b..ca36e5bb77d5 100644 --- a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/SliderPreferenceScreenshotTest.kt +++ b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/preference/SliderPreferenceScreenshotTest.kt @@ -60,7 +60,7 @@ class SliderPreferenceScreenshotTest(emulationSpec: DeviceEmulationSpec) { override val onValueChangeFinished = { println("onValueChangeFinished") } - override val icon = Icons.Outlined.AccessAlarm + override val iconStart = Icons.Outlined.AccessAlarm }) SliderPreference(object : SliderPreferenceModel { diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts index f0c2ea6f5353..790aa9ff8d3f 100644 --- a/packages/SettingsLib/Spa/spa/build.gradle.kts +++ b/packages/SettingsLib/Spa/spa/build.gradle.kts @@ -54,15 +54,16 @@ android { dependencies { api(project(":SettingsLibColor")) api("androidx.appcompat:appcompat:1.7.0") - api("androidx.compose.material3:material3:1.3.0-rc01") + api("androidx.compose.material3:material3:1.3.0") api("androidx.compose.material:material-icons-extended:$jetpackComposeVersion") api("androidx.compose.runtime:runtime-livedata:$jetpackComposeVersion") api("androidx.compose.ui:ui-tooling-preview:$jetpackComposeVersion") api("androidx.lifecycle:lifecycle-livedata-ktx") api("androidx.lifecycle:lifecycle-runtime-compose") - api("androidx.navigation:navigation-compose:2.8.0-rc01") + api("androidx.navigation:navigation-compose:2.8.1") api("com.github.PhilJay:MPAndroidChart:v3.1.0-alpha") api("com.google.android.material:material:1.11.0") + api("androidx.graphics:graphics-shapes-android:1.0.1") debugApi("androidx.compose.ui:ui-tooling:$jetpackComposeVersion") implementation("com.airbnb.android:lottie-compose:6.4.0") diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt index 1f3e24254027..f8c791aab0d0 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt @@ -21,7 +21,9 @@ import androidx.compose.ui.unit.dp object SettingsDimension { val paddingTiny = 2.dp - val paddingSmall = 4.dp + val paddingExtraSmall = 4.dp + val paddingSmall = if (isSpaExpressiveEnabled) 8.dp else 4.dp + val paddingExtraSmall5 = 10.dp val paddingLarge = 16.dp val paddingExtraLarge = 24.dp @@ -56,6 +58,7 @@ object SettingsDimension { val itemDividerHeight = 32.dp val iconLarge = 48.dp + val introIconSize = 40.dp /** The size when app icon is displayed in list. */ val appIconItemSize = 32.dp diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt index 15def728d8b3..f948d5163177 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt @@ -21,6 +21,7 @@ import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import com.android.settingslib.spa.framework.util.SystemProperties /** * The Material 3 Theme for Settings. @@ -41,4 +42,5 @@ fun SettingsTheme(content: @Composable () -> Unit) { } } -const val isSpaExpressiveEnabled = false
\ No newline at end of file +val isSpaExpressiveEnabled + by lazy { SystemProperties.getBoolean("is_expressive_design_enabled", false) } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/SystemProperties.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/SystemProperties.kt new file mode 100644 index 000000000000..ed4936bbf8c9 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/SystemProperties.kt @@ -0,0 +1,35 @@ +/* + * 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.spa.framework.util + +import android.annotation.SuppressLint +import android.util.Log + +@SuppressLint("PrivateApi") +object SystemProperties { + private const val TAG = "SystemProperties" + + fun getBoolean(key: String, default: Boolean): Boolean = try { + val systemProperties = Class.forName("android.os.SystemProperties") + systemProperties + .getMethod("getBoolean", String::class.java, Boolean::class.java) + .invoke(systemProperties, key, default) as Boolean + } catch (e: Exception) { + Log.e(TAG, "getBoolean: $key", e) + default + } +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/button/ActionButtons.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/button/ActionButtons.kt index 70d353da496c..7e1df1694b10 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/button/ActionButtons.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/button/ActionButtons.kt @@ -18,6 +18,7 @@ package com.android.settingslib.spa.widget.button import androidx.compose.foundation.background import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize @@ -25,11 +26,14 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxHeight +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.width +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.Launch import androidx.compose.material.icons.outlined.Delete import androidx.compose.material.icons.outlined.WarningAmber import androidx.compose.material3.ButtonDefaults @@ -51,7 +55,7 @@ import com.android.settingslib.spa.framework.theme.SettingsDimension import com.android.settingslib.spa.framework.theme.SettingsShape import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.spa.framework.theme.divider -import androidx.compose.material.icons.automirrored.outlined.Launch +import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled data class ActionButton( val text: String, @@ -62,48 +66,64 @@ data class ActionButton( @Composable fun ActionButtons(actionButtons: List<ActionButton>) { - Row( - Modifier - .padding(SettingsDimension.buttonPadding) - .clip(SettingsShape.CornerExtraLarge) - .height(IntrinsicSize.Min) - ) { - for ((index, actionButton) in actionButtons.withIndex()) { - if (index > 0) ButtonDivider() - ActionButton(actionButton) + if (isSpaExpressiveEnabled) { + Row( + horizontalArrangement = Arrangement.SpaceAround, + modifier = Modifier + .padding(SettingsDimension.buttonPadding) + .height(IntrinsicSize.Min) + .fillMaxWidth() + ) { + for (actionButton in actionButtons) { + ActionButton(actionButton) + } + } + } else { + Row( + Modifier + .padding(SettingsDimension.buttonPadding) + .clip(SettingsShape.CornerExtraLarge) + .height(IntrinsicSize.Min) + ) { + for ((index, actionButton) in actionButtons.withIndex()) { + if (index > 0) ButtonDivider() + ActionButton(actionButton) + } } } } @Composable private fun RowScope.ActionButton(actionButton: ActionButton) { - FilledTonalButton( - onClick = actionButton.onClick, - modifier = Modifier - .weight(1f) - .fillMaxHeight(), - enabled = actionButton.enabled, - // Because buttons could appear, disappear or change positions, reset the interaction source - // to prevent highlight the wrong button. - interactionSource = remember(actionButton) { MutableInteractionSource() }, - shape = RectangleShape, - colors = ButtonDefaults.filledTonalButtonColors( - containerColor = MaterialTheme.colorScheme.surface, - contentColor = MaterialTheme.colorScheme.primary, - disabledContainerColor = MaterialTheme.colorScheme.surface, - ), - contentPadding = PaddingValues(horizontal = 4.dp, vertical = 20.dp), - ) { + if (isSpaExpressiveEnabled) { Column(horizontalAlignment = Alignment.CenterHorizontally) { - Icon( - imageVector = actionButton.imageVector, - contentDescription = null, - modifier = Modifier.size(SettingsDimension.itemIconSize), - ) + FilledTonalButton( + onClick = actionButton.onClick, + modifier = Modifier + .weight(1f) + .fillMaxHeight() + .clip(RoundedCornerShape(100.dp)), + enabled = actionButton.enabled, + // Because buttons could appear, disappear or change positions, reset the interaction source + // to prevent highlight the wrong button. + interactionSource = remember(actionButton) { MutableInteractionSource() }, + shape = RectangleShape, + colors = ButtonDefaults.filledTonalButtonColors( + containerColor = MaterialTheme.colorScheme.primaryContainer, + contentColor = MaterialTheme.colorScheme.onPrimary, + disabledContainerColor = MaterialTheme.colorScheme.surface, + ), + contentPadding = PaddingValues(horizontal = 24.dp, vertical = 16.dp), + ) { + Icon( + imageVector = actionButton.imageVector, + contentDescription = null, + modifier = Modifier.size(SettingsDimension.itemIconSize), + ) + } Box( modifier = Modifier - .padding(top = 4.dp) - .fillMaxHeight(), + .padding(top = 6.dp), contentAlignment = Alignment.Center, ) { Text( @@ -113,6 +133,44 @@ private fun RowScope.ActionButton(actionButton: ActionButton) { ) } } + } else { + FilledTonalButton( + onClick = actionButton.onClick, + modifier = Modifier + .weight(1f) + .fillMaxHeight(), + enabled = actionButton.enabled, + // Because buttons could appear, disappear or change positions, reset the interaction source + // to prevent highlight the wrong button. + interactionSource = remember(actionButton) { MutableInteractionSource() }, + shape = RectangleShape, + colors = ButtonDefaults.filledTonalButtonColors( + containerColor = MaterialTheme.colorScheme.surface, + contentColor = MaterialTheme.colorScheme.primary, + disabledContainerColor = MaterialTheme.colorScheme.surface, + ), + contentPadding = PaddingValues(horizontal = 4.dp, vertical = 20.dp), + ) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Icon( + imageVector = actionButton.imageVector, + contentDescription = null, + modifier = Modifier.size(SettingsDimension.itemIconSize), + ) + Box( + modifier = Modifier + .padding(top = 4.dp) + .fillMaxHeight(), + contentAlignment = Alignment.Center, + ) { + Text( + text = actionButton.text, + textAlign = TextAlign.Center, + style = MaterialTheme.typography.labelMedium, + ) + } + } + } } } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/IntroPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/IntroPreference.kt new file mode 100644 index 000000000000..22a57554eeaf --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/IntroPreference.kt @@ -0,0 +1,145 @@ +/* + * 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.spa.widget.preference + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.AirplanemodeActive +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import com.android.settingslib.spa.framework.theme.SettingsDimension + +@Composable +fun IntroPreference( + title: String, + descriptions: List<String>? = null, + imageVector: ImageVector? = null, +) { + IntroPreference(title = title, descriptions = descriptions, icon = { IntroIcon(imageVector) }) +} + +@Composable +fun IntroAppPreference( + title: String, + descriptions: List<String>? = null, + appIcon: @Composable (() -> Unit), +) { + IntroPreference(title = title, descriptions = descriptions, icon = { IntroAppIcon(appIcon) }) +} + +@Composable +internal fun IntroPreference( + title: String, + descriptions: List<String>?, + icon: @Composable (() -> Unit), +) { + Column( + modifier = + Modifier.fillMaxWidth() + .padding( + horizontal = SettingsDimension.paddingExtraLarge, + vertical = SettingsDimension.paddingLarge, + ), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + icon() + IntroTitle(title) + IntroDescription(descriptions) + } +} + +@Composable +private fun IntroIcon(imageVector: ImageVector?) { + if (imageVector != null) { + Box( + modifier = + Modifier.size(SettingsDimension.itemIconContainerSize) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.secondaryContainer), + contentAlignment = Alignment.Center, + ) { + Icon( + imageVector = imageVector, + contentDescription = null, + modifier = Modifier.size(SettingsDimension.introIconSize), + tint = MaterialTheme.colorScheme.onSecondary, + ) + } + } +} + +@Composable +private fun IntroAppIcon(appIcon: @Composable () -> Unit) { + Box( + modifier = Modifier.size(SettingsDimension.itemIconContainerSize).clip(CircleShape), + contentAlignment = Alignment.Center, + ) { + appIcon() + } +} + +@Composable +private fun IntroTitle(title: String) { + Box(modifier = Modifier.padding(top = SettingsDimension.paddingLarge)) { + Text( + text = title, + textAlign = TextAlign.Center, + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.onSurface, + ) + } +} + +@Composable +private fun IntroDescription(descriptions: List<String>?) { + if (descriptions != null) { + for (description in descriptions) { + if (description.isEmpty()) continue + Text( + text = description, + textAlign = TextAlign.Center, + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = SettingsDimension.paddingExtraSmall), + ) + } + } +} + +@Preview +@Composable +private fun IntroPreferencePreview() { + IntroPreference( + title = "Preferred network type", + descriptions = listOf("Description", "Version"), + imageVector = Icons.Outlined.AirplanemodeActive, + ) +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SliderPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SliderPreference.kt index 7bca38fdb48f..b2a3aac88902 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SliderPreference.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SliderPreference.kt @@ -16,6 +16,10 @@ package com.android.settingslib.spa.widget.preference +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.AccessAlarm import androidx.compose.material.icons.outlined.MusicNote @@ -27,30 +31,25 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.android.settingslib.spa.framework.theme.SettingsDimension import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.spa.framework.util.EntryHighlight import com.android.settingslib.spa.widget.ui.SettingsSlider -/** - * The widget model for [SliderPreference] widget. - */ +/** The widget model for [SliderPreference] widget. */ interface SliderPreferenceModel { - /** - * The title of this [SliderPreference]. - */ + /** The title of this [SliderPreference]. */ val title: String - /** - * The initial position of the [SliderPreference]. - */ + /** The initial position of the [SliderPreference]. */ val initValue: Int - /** - * The value range for this [SliderPreference]. - */ + /** The value range for this [SliderPreference]. */ val valueRange: IntRange get() = 0..100 @@ -69,15 +68,23 @@ interface SliderPreferenceModel { get() = null /** - * The icon image for [SliderPreference]. If not specified, the slider hides the icon by default. + * The start icon image for [SliderPreference]. If not specified, the slider hides the icon by + * default. */ - val icon: ImageVector? + val iconStart: ImageVector? get() = null /** - * Indicates whether to show step marks. If show step marks, when user finish sliding, - * the slider will automatically jump to the nearest step mark. Otherwise, the slider hides - * the step marks by default. + * The end icon image for [SliderPreference]. If not specified, the slider hides the icon by + * default. + */ + val iconEnd: ImageVector? + get() = null + + /** + * Indicates whether to show step marks. If show step marks, when user finish sliding, the + * slider will automatically jump to the nearest step mark. Otherwise, the slider hides the step + * marks by default. * * The step is fixed to 1. */ @@ -99,7 +106,8 @@ fun SliderPreference(model: SliderPreferenceModel) { valueRange = model.valueRange, onValueChange = model.onValueChange, onValueChangeFinished = model.onValueChangeFinished, - icon = model.icon, + iconStart = model.iconStart, + iconEnd = model.iconEnd, showSteps = model.showSteps, ) } @@ -113,27 +121,45 @@ internal fun SliderPreference( valueRange: IntRange = 0..100, onValueChange: ((value: Int) -> Unit)? = null, onValueChangeFinished: (() -> Unit)? = null, - icon: ImageVector? = null, + iconStart: ImageVector? = null, + iconEnd: ImageVector? = null, showSteps: Boolean = false, ) { + BaseLayout( title = title, subTitle = { - SettingsSlider( - initValue, - modifier, - valueRange, - onValueChange, - onValueChangeFinished, - showSteps - ) + Row(verticalAlignment = Alignment.CenterVertically) { + if (iconStart != null) { + SliderIcon(icon = iconStart) + Spacer(Modifier.padding(SettingsDimension.paddingSmall)) + } + Box(Modifier.weight(1f)) { + SettingsSlider( + initValue, + modifier, + valueRange, + onValueChange, + onValueChangeFinished, + showSteps, + ) + } + if (iconEnd != null) { + Spacer(Modifier.padding(SettingsDimension.paddingSmall)) + SliderIcon(icon = iconEnd) + } + } }, - icon = if (icon != null) ({ - Icon(imageVector = icon, contentDescription = null) - }) else null, ) } +@Composable +fun SliderIcon(icon: ImageVector) { + Box(modifier = Modifier.padding(8.dp), contentAlignment = Alignment.Center) { + Icon(imageVector = icon, contentDescription = null) + } +} + @Preview @Composable private fun SliderPreferencePreview() { @@ -147,7 +173,7 @@ private fun SliderPreferencePreview() { onValueChangeFinished = { println("onValueChangeFinished: the value is $sliderPosition") }, - icon = Icons.Outlined.AccessAlarm, + iconStart = Icons.Outlined.AccessAlarm, ) } } @@ -163,20 +189,30 @@ private fun SliderPreferenceIconChangePreview() { onValueChange = { it: Int -> icon = if (it > 0) Icons.Outlined.MusicNote else Icons.Outlined.MusicOff }, - icon = icon, + iconEnd = icon, ) } } @Preview @Composable -private fun SliderPreferenceStepsPreview() { +private fun SliderPreferenceTwoIconPreview() { SettingsTheme { + val iconStart by remember { mutableStateOf(Icons.Outlined.MusicNote) } + val iconEnd by remember { mutableStateOf(Icons.Outlined.MusicOff) } SliderPreference( - title = "Display Text", - initValue = 2, - valueRange = 1..5, - showSteps = true, + title = "Media Volume", + initValue = 40, + iconStart = iconStart, + iconEnd = iconEnd, ) } } + +@Preview +@Composable +private fun SliderPreferenceStepsPreview() { + SettingsTheme { + SliderPreference(title = "Display Text", initValue = 2, valueRange = 1..5, showSteps = true) + } +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TopIntroPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TopIntroPreference.kt new file mode 100644 index 000000000000..7e619591c8a9 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TopIntroPreference.kt @@ -0,0 +1,152 @@ +/* + * 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.spa.widget.preference + +import androidx.annotation.StringRes +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.KeyboardArrowDown +import androidx.compose.material.icons.filled.KeyboardArrowUp +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.tooling.preview.Preview +import com.android.settingslib.spa.framework.theme.SettingsDimension +import com.android.settingslib.spa.framework.theme.toMediumWeight +import com.android.settingslib.spa.framework.util.annotatedStringResource + +/** The widget model for [TopIntroPreference] widget. */ +interface TopIntroPreferenceModel { + /** The content of this [TopIntroPreference]. */ + val text: String + + /** The text clicked to expand this [TopIntroPreference]. */ + val expandText: String + + /** The text clicked to collapse this [TopIntroPreference]. */ + val collapseText: String + + /** The text clicked to open other resources. Should be a resource Id. */ + val labelText: Int? +} + +@Composable +fun TopIntroPreference(model: TopIntroPreferenceModel) { + var expanded by remember { mutableStateOf(false) } + Column(Modifier.background(MaterialTheme.colorScheme.surfaceContainer)) { + // TopIntroPreference content. + Column( + modifier = + Modifier.padding( + horizontal = SettingsDimension.paddingExtraLarge, + vertical = SettingsDimension.paddingSmall, + ) + .animateContentSize() + ) { + Text( + text = model.text, + style = MaterialTheme.typography.bodyLarge, + maxLines = if (expanded) MAX_LINE else MIN_LINE, + ) + if (expanded) TopIntroAnnotatedText(model.labelText) + } + + // TopIntroPreference collapse bar. + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = + Modifier.fillMaxWidth() + .clickable(onClick = { expanded = !expanded }) + .padding( + top = SettingsDimension.paddingSmall, + bottom = SettingsDimension.paddingLarge, + start = SettingsDimension.paddingExtraLarge, + end = SettingsDimension.paddingExtraLarge, + ), + ) { + Icon( + imageVector = + if (expanded) Icons.Filled.KeyboardArrowUp else Icons.Filled.KeyboardArrowDown, + contentDescription = null, + modifier = + Modifier.size(SettingsDimension.itemIconSize) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.surfaceContainerHighest), + ) + Text( + text = if (expanded) model.collapseText else model.expandText, + modifier = Modifier.padding(start = SettingsDimension.paddingSmall), + style = MaterialTheme.typography.bodyLarge.toMediumWeight(), + color = MaterialTheme.colorScheme.onSurface, + ) + } + } +} + +@Composable +private fun TopIntroAnnotatedText(@StringRes id: Int?) { + if (id != null) { + Box( + Modifier.padding( + top = SettingsDimension.paddingExtraSmall5, + bottom = SettingsDimension.paddingExtraSmall5, + end = SettingsDimension.paddingLarge, + ) + ) { + Text( + text = annotatedStringResource(id), + style = MaterialTheme.typography.bodyLarge.toMediumWeight(), + color = MaterialTheme.colorScheme.primary, + ) + } + } +} + +@Preview +@Composable +private fun TopIntroPreferencePreview() { + TopIntroPreference( + object : TopIntroPreferenceModel { + override val text = + "Additional text needed for the page. This can sit on the right side of the screen in 2 column.\n" + + "Example collapsed text area that you will not see until you expand this block." + override val expandText = "Expand" + override val collapseText = "Collapse" + override val labelText = androidx.appcompat.R.string.abc_prepend_shortcut_label + } + ) +} + +const val MIN_LINE = 2 +const val MAX_LINE = 10 diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ZeroStatePreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ZeroStatePreference.kt new file mode 100644 index 000000000000..3f2e7723c585 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ZeroStatePreference.kt @@ -0,0 +1,132 @@ +/* + * 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.spa.widget.preference + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.History +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Matrix +import androidx.compose.ui.graphics.Outline +import androidx.compose.ui.graphics.Path +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.graphics.asComposePath +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp +import androidx.graphics.shapes.CornerRounding +import androidx.graphics.shapes.RoundedPolygon +import androidx.graphics.shapes.star +import androidx.graphics.shapes.toPath + +@Composable +fun ZeroStatePreference(icon: ImageVector, text: String? = null, description: String? = null) { + val zeroStateShape = remember { + RoundedPolygon.star( + numVerticesPerRadius = 6, + innerRadius = 0.75f, + rounding = CornerRounding(0.3f) + ) + } + val clip = remember(zeroStateShape) { + RoundedPolygonShape(polygon = zeroStateShape) + } + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Box( + modifier = Modifier + .clip(clip) + .background(MaterialTheme.colorScheme.primary) + .size(160.dp) + ) { + Icon( + imageVector = icon, + modifier = Modifier + .align(Alignment.Center) + .size(72.dp), + tint = MaterialTheme.colorScheme.onPrimary, + contentDescription = null, + ) + } + if (text != null) { + Text( + text = text, + textAlign = TextAlign.Center, + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = 24.dp), + ) + } + if (description != null) { + Box { + Text( + text = description, + textAlign = TextAlign.Center, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + } + } +} + +@Preview +@Composable +private fun ZeroStatePreferencePreview() { + ZeroStatePreference( + Icons.Filled.History, + "No recent search history", + "Description" + ) +} + +class RoundedPolygonShape( + private val polygon: RoundedPolygon, + private var matrix: Matrix = Matrix() +) : Shape { + private var path = Path() + override fun createOutline( + size: Size, + layoutDirection: LayoutDirection, + density: Density + ): Outline { + path.rewind() + path = polygon.toPath().asComposePath() + + matrix.reset() + matrix.scale(size.width / 2f, size.height / 2f) + matrix.translate(1f, 1f) + matrix.rotateZ(30.0f) + + path.transform(matrix) + return Outline.Generic(path) + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/Spa/tests/res/values/strings.xml b/packages/SettingsLib/Spa/tests/res/values/strings.xml index fb8f878230d5..346f69bb7a42 100644 --- a/packages/SettingsLib/Spa/tests/res/values/strings.xml +++ b/packages/SettingsLib/Spa/tests/res/values/strings.xml @@ -28,5 +28,7 @@ <string name="test_annotated_string_resource">Annotated string with <b>bold</b> and <a href="https://www.android.com/">link</a>.</string> + <string name="test_top_intro_preference_label"><a href="https://www.android.com/">Label</a></string> + <string name="test_link"><a href="https://www.android.com/">link</a></string> </resources> diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/SystemPropertiesTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/SystemPropertiesTest.kt new file mode 100644 index 000000000000..0827fa9e0ae0 --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/SystemPropertiesTest.kt @@ -0,0 +1,30 @@ +/* + * 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.spa.framework.util + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SystemPropertiesTest { + + @Test + fun getBoolean_noCrash() { + SystemProperties.getBoolean("is_expressive_design_enabled", false) + } +} diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/IntroPreferenceTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/IntroPreferenceTest.kt new file mode 100644 index 000000000000..5d801451adcb --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/IntroPreferenceTest.kt @@ -0,0 +1,51 @@ +/* + * 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.spa.widget.preference + +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertIsNotDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class IntroPreferenceTest { + @get:Rule val composeTestRule = createComposeRule() + + @Test + fun title_displayed() { + composeTestRule.setContent { IntroPreference(title = TITLE) } + + composeTestRule.onNodeWithText(TITLE).assertIsDisplayed() + } + + @Test + fun description_displayed() { + composeTestRule.setContent { IntroPreference(title = TITLE, descriptions = DESCRIPTION) } + + composeTestRule.onNodeWithText(DESCRIPTION.component1()).assertIsDisplayed() + composeTestRule.onNodeWithText(DESCRIPTION.component2()).assertIsNotDisplayed() + } + + private companion object { + const val TITLE = "Title" + val DESCRIPTION = listOf("Description", "") + } +} diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/TopIntroPreferenceTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/TopIntroPreferenceTest.kt new file mode 100644 index 000000000000..62a71d4763b3 --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/TopIntroPreferenceTest.kt @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.spa.widget.preference + +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settingslib.spa.test.R +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class TopIntroPreferenceTest { + @get:Rule val composeTestRule = createComposeRule() + + @Test + fun content_collapsed_displayed() { + composeTestRule.setContent { + TopIntroPreference( + object : TopIntroPreferenceModel { + override val text = TEXT + override val expandText = EXPAND_TEXT + override val collapseText = COLLAPSE_TEXT + override val labelText = R.string.test_top_intro_preference_label + } + ) + } + + composeTestRule.onNodeWithText(TEXT).assertIsDisplayed() + composeTestRule.onNodeWithText(EXPAND_TEXT).assertIsDisplayed() + } + + @Test + fun content_expended_displayed() { + composeTestRule.setContent { + TopIntroPreference( + object : TopIntroPreferenceModel { + override val text = TEXT + override val expandText = EXPAND_TEXT + override val collapseText = COLLAPSE_TEXT + override val labelText = R.string.test_top_intro_preference_label + } + ) + } + + composeTestRule.onNodeWithText(TEXT).assertIsDisplayed() + composeTestRule.onNodeWithText(EXPAND_TEXT).assertIsDisplayed().performClick() + composeTestRule.onNodeWithText(COLLAPSE_TEXT).assertIsDisplayed() + composeTestRule.onNodeWithText(LABEL_TEXT).assertIsDisplayed() + } + + private companion object { + const val TEXT = "Text" + const val EXPAND_TEXT = "Expand" + const val COLLAPSE_TEXT = "Collapse" + const val LABEL_TEXT = "Label" + } +} diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/ZeroStatePreferenceTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/ZeroStatePreferenceTest.kt new file mode 100644 index 000000000000..99ac27c36e46 --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/ZeroStatePreferenceTest.kt @@ -0,0 +1,56 @@ +/* + * 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.spa.widget.preference + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.History +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class ZeroStatePreferenceTest { + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun title_displayed() { + composeTestRule.setContent { + ZeroStatePreference(Icons.Filled.History, TITLE) + } + + composeTestRule.onNodeWithText(TITLE).assertIsDisplayed() + } + + @Test + fun description_displayed() { + composeTestRule.setContent { + ZeroStatePreference(Icons.Filled.History, TITLE, DESCRIPTION) + } + + composeTestRule.onNodeWithText(DESCRIPTION).assertIsDisplayed() + } + + private companion object { + const val TITLE = "Title" + const val DESCRIPTION = "Description" + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/TwoTargetPreference/res/layout-v35/settingslib_expressive_preference_two_target.xml b/packages/SettingsLib/TwoTargetPreference/res/layout-v35/settingslib_expressive_preference_two_target.xml new file mode 100644 index 000000000000..4347ef29037d --- /dev/null +++ b/packages/SettingsLib/TwoTargetPreference/res/layout-v35/settingslib_expressive_preference_two_target.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:background="?android:attr/selectableItemBackground" + android:paddingStart="?android:attr/listPreferredItemPaddingStart" + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" + android:clipToPadding="false"> + + <include layout="@layout/settingslib_expressive_preference_icon_frame"/> + + <include layout="@layout/settingslib_expressive_preference_text_frame" /> + + <include layout="@layout/settingslib_expressive_two_target_divider" /> + + <!-- 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:minWidth="@dimen/two_target_min_width" + android:gravity="center" + android:orientation="vertical" /> + +</LinearLayout> diff --git a/packages/SettingsLib/TwoTargetPreference/src/com/android/settingslib/widget/TwoTargetPreference.java b/packages/SettingsLib/TwoTargetPreference/src/com/android/settingslib/widget/TwoTargetPreference.java index b125f716fe52..58ff0ce1932a 100644 --- a/packages/SettingsLib/TwoTargetPreference/src/com/android/settingslib/widget/TwoTargetPreference.java +++ b/packages/SettingsLib/TwoTargetPreference/src/com/android/settingslib/widget/TwoTargetPreference.java @@ -72,7 +72,10 @@ public class TwoTargetPreference extends Preference { } private void init(Context context) { - setLayoutResource(R.layout.preference_two_target); + int resID = SettingsThemeHelper.isExpressiveTheme(context) + ? R.layout.settingslib_expressive_preference_two_target + : R.layout.preference_two_target; + setLayoutResource(resID); mSmallIconSize = context.getResources().getDimensionPixelSize( R.dimen.two_target_pref_small_icon_size); mMediumIconSize = context.getResources().getDimensionPixelSize( 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 000000000000..209dea515802 --- /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-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index 0c9ed5cef34f..66644cb796c4 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ይህ ኮምፒውተር (ውስጣዊ)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"ማይክሮፎን (ውስጣዊ)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"ባለገመድ የራስ ላይ ማዳመጫ"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"የጆሮ ማዳመጫ"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB ድምፅ ማውጫ"</string> <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> diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index 46e4c76f4dfa..e241c8a9a5a3 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"هذا الكمبيوتر (داخلي)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"ميكروفون (داخلي)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"سماعات رأس سلكية"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"سماعات رأس"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"مكبّر صوت USB"</string> <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> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index 82cd91c8d1b8..4e734b9cf094 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"এই কম্পিউটাৰ (অভ্যন্তৰীণ)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"মাইক্ৰ’ফ’ন (অভ্যন্তৰীণ)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"তাঁৰযুক্ত হেডফ’ন"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"হেডফ’ন"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB স্পীকাৰ"</string> <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> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index 5da1c69ef1c7..fdd969d81a8f 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ovaj računar (interno)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (interni)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Žičane slušalice"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Slušalice"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB zvučnik"</string> <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> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index e782aa1b074d..e7b97236a246 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -376,7 +376,7 @@ <string name="strict_mode_summary" msgid="1838248687233554654">"মুখ্য থ্রেডে অ্যাপগুলির দীর্ঘ কার্যকলাপের ক্ষেত্রে স্ক্রিন ফ্ল্যাশ করে"</string> <string name="pointer_location" msgid="7516929526199520173">"পয়েন্টারের লোকেশন"</string> <string name="pointer_location_summary" msgid="957120116989798464">"স্ক্রিন ওভারলে বর্তমান স্পর্শ ডেটা দেখাচ্ছে"</string> - <string name="show_touches" msgid="8437666942161289025">"আলতো চাপ দেখান"</string> + <string name="show_touches" msgid="8437666942161289025">"ট্যাপ দেখান"</string> <string name="show_touches_summary" msgid="3692861665994502193">"আলতো চাপ দিলে ভিজ্যুয়াল প্রতিক্রিয়া দেখান"</string> <string name="show_key_presses" msgid="6360141722735900214">"প্রেস করা কী দেখুন"</string> <string name="show_key_presses_summary" msgid="725387457373015024">"ফিজিক্যাল কী প্রেস করা হলে ভিজুয়াল ফিডব্যাক দেখুন"</string> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index bddced568bb3..e8d4a7c807cc 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ovo računalo (interno)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (interni)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Žičane slušalice"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Slušalice"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB zvučnik"</string> <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> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 89f8f5af1b4b..d75e3142a8f9 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Aquest ordinador (intern)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Micròfon (intern)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Auriculars amb cable"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Auriculars"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Altaveu USB"</string> <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> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index ac46bb606d25..9ba5b50982bf 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -586,8 +586,7 @@ <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">"Dock-Lautsprecher"</string> <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externes Gerät"</string> <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Verbundenes Gerät"</string> @@ -694,10 +693,8 @@ <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) --> - <skip /> + <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Mikrofonanschluss"</string> + <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"USB‑Mikrofon"</string> <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"An"</string> <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Aus"</string> <string name="carrier_network_change_mode" msgid="4257621815706644026">"Mobilfunknetzwerk wird gewechselt"</string> diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml index 961f0e7d16fd..d4e01ded8f59 100644 --- a/packages/SettingsLib/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/res/values-en-rAU/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"This computer (internal)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microphone (internal)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Wired headphones"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Headphone"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB speaker"</string> <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> diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml index 6c2f45efdb89..602a0ed5c835 100644 --- a/packages/SettingsLib/res/values-en-rCA/strings.xml +++ b/packages/SettingsLib/res/values-en-rCA/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"This computer (internal)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microphone (internal)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Wired headphone"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Headphone"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB speaker"</string> <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> diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml index 961f0e7d16fd..d4e01ded8f59 100644 --- a/packages/SettingsLib/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/res/values-en-rGB/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"This computer (internal)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microphone (internal)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Wired headphones"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Headphone"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB speaker"</string> <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> diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml index 961f0e7d16fd..d4e01ded8f59 100644 --- a/packages/SettingsLib/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/res/values-en-rIN/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"This computer (internal)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microphone (internal)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Wired headphones"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Headphone"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB speaker"</string> <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> diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml index a9ed4a4c1be0..0731b72b4b25 100644 --- a/packages/SettingsLib/res/values-en-rXC/strings.xml +++ b/packages/SettingsLib/res/values-en-rXC/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"This computer (internal)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microphone (internal)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Wired headphone"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Headphone"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB speaker"</string> <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> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index 8fcb49ce9a07..b0d360d582f6 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -586,8 +586,7 @@ <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">"Bocina de la estación de carga"</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> @@ -694,10 +693,8 @@ <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) --> - <skip /> + <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Conector 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">"Activar"</string> <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivar"</string> <string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambio de proveedor de red"</string> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index db9a744f5021..3dc0e8573a95 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"این رایانه (داخلی)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"میکروفون (داخلی)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"هدفون سیمی"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"هدفون"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"بلندگوی USB"</string> <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> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index 1f09856f3415..0df9489dc60e 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -586,8 +586,7 @@ <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">"Micro (interne)"</string> <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Haut-parleur station d\'accueil"</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> @@ -694,10 +693,8 @@ <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) --> - <skip /> + <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Connecteur micro"</string> + <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Micro USB"</string> <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Allumé"</string> <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Éteint"</string> <string name="carrier_network_change_mode" msgid="4257621815706644026">"Modification du réseau de l\'opérateur"</string> diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml index 0455dffdb6c5..aa768f879928 100644 --- a/packages/SettingsLib/res/values-gu/strings.xml +++ b/packages/SettingsLib/res/values-gu/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"આ કમ્પ્યૂટર (આંતરિક)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"માઇક્રોફોન (આંતરિક)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"વાયરવાળો હૅડફોન"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"હૅડફોન"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB સ્પીકર"</string> <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> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index 6f0fde341502..b8e55b50ff03 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"इस कंप्यूटर पर (इंटरनल)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"माइक्रोफ़ोन (इंटरनल)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"तार वाला हेडफ़ोन"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"हेडफ़ोन"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"यूएसबी स्पीकर"</string> <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> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index 2045fe77e372..45ac8c24bcaa 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ovo računalo (interno)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (ugrađeni)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Žičane slušalice"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Slušalice"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB zvučnik"</string> <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> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index 60c6391c8c1d..1436c1733ebd 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -586,8 +586,7 @@ <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">"Microfono (interno)"</string> <string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Base con altoparlante"</string> <string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo esterno"</string> <string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo connesso"</string> @@ -694,10 +693,8 @@ <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) --> - <skip /> + <string name="media_transfer_wired_device_mic_name" msgid="7417067197803840965">"Jack per microfono"</string> + <string name="media_transfer_usb_device_mic_name" msgid="9189914846215516322">"Microfono 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">"Cambio della rete dell\'operatore"</string> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index bc8dee828235..185c6c964a5b 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"このパソコン(内蔵)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"マイク(内蔵)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"有線ヘッドフォン"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"ヘッドフォン"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB スピーカー"</string> <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> diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml index a6151f3d6003..9532c3a153a9 100644 --- a/packages/SettingsLib/res/values-ka/strings.xml +++ b/packages/SettingsLib/res/values-ka/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ეს კომპიუტერი (შიდა)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"მიკროფონი (შიდა)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"სადენიანი ყურსასმენი"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"ყურსასმენი"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB დინამიკი"</string> <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> diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml index 933dee798cfc..43807a018083 100644 --- a/packages/SettingsLib/res/values-km/strings.xml +++ b/packages/SettingsLib/res/values-km/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"កុំព្យូទ័រនេះ (ខាងក្នុង)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"មីក្រូហ្វូន (ខាងក្នុង)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"កាសមានខ្សែ"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"កាស"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"ឧបករណ៍បំពងសំឡេង USB"</string> <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> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index a8eb6072a853..ea9ff6c5b06b 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Овој компјуер (внатрешен)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (внатрешен)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Жичени слушалки"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Слушалка"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB-звучник"</string> <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> diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml index 753aa3297179..7af53aad667f 100644 --- a/packages/SettingsLib/res/values-ml/strings.xml +++ b/packages/SettingsLib/res/values-ml/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ഈ കമ്പ്യൂട്ടർ (ഇന്റേണൽ)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"മൈക്രോഫോൺ (ഇന്റേണൽ)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"വയേർഡ് ഹെഡ്ഫോൺ"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"ഹെഡ്ഫോൺ"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB സ്പീക്കർ"</string> <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> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index 483936ae8351..581545d609b9 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"हा काँप्युटर (अंतर्गत)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"मायक्रोफोन (अंतर्गत)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"वायर्ड हेडफोन"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"हेडफोन"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB स्पीकर"</string> <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> diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml index dbe745dc8c3c..7990e0443acf 100644 --- a/packages/SettingsLib/res/values-ms/strings.xml +++ b/packages/SettingsLib/res/values-ms/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Komputer ini (dalaman)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (dalaman)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Fon kepala berwayar"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Fon kepala"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Pembesar suara USB"</string> <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> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index 09240f096703..916aba97cdf3 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"यो कम्प्युटर (आन्तरिक)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"माइक्रोफोन (आन्तरिक)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"तारयुक्त हेडफोन"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"हेडफोन"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB स्पिकर"</string> <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> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index 0117acff9d48..78dfd35ed855 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Deze computer (intern)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microfoon (intern)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Bedrade koptelefoon"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Koptelefoon"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB-speaker"</string> <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> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index 7e90b78ec1c5..bb8fe2e40bfe 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ten komputer (wewnętrzny)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (wewnętrzny)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Słuchawki przewodowe"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Słuchawki"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Głośnik USB"</string> <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> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index e10ad0719917..7f5bb0fa55dc 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Este computador (interno)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microfone (interno)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Fones de ouvido com fio"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Fone de ouvido"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Alto-falante USB"</string> <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> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index e10ad0719917..7f5bb0fa55dc 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Este computador (interno)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Microfone (interno)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Fones de ouvido com fio"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Fone de ouvido"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Alto-falante USB"</string> <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> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 009e071e4536..1cdef05d8b18 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Встроенный динамик компьютера"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (встроенный)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Проводные наушники"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Наушники"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB-колонка"</string> <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> diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml index 27154f62c28d..980f9c884358 100644 --- a/packages/SettingsLib/res/values-si/strings.xml +++ b/packages/SettingsLib/res/values-si/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"මෙම පරිගණකය (අභ්යන්තර)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"මයික්රෆෝනය (අභ්යන්තර)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"රැහැන්ගත හෙඩ්ෆෝන්"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"හෙඩ්ෆෝන්"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB ස්පීකරය"</string> <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> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index 4ca5c489c491..2ee12418c38a 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Ta računalnik (notranji)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikrofon (notranji)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Žične slušalke"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Slušalke"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"Zvočnik USB"</string> <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> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index cc7c69dbc957..34ccdaf0f19e 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Овај рачунар (интерно)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Микрофон (интерни)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Жичане слушалице"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Слушалице"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB звучник"</string> <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> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index 5fb829ddfaa9..56d0a7d5014b 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"ఈ కంప్యూటర్ (ఇంటర్నల్)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"మైక్రోఫోన్ (అంతర్గతం)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"వైర్ ఉన్న హెడ్ఫోన్"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"హెడ్ఫోన్"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB స్పీకర్"</string> <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> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index aa23a44fe1fb..28a0d64b5c75 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"คอมพิวเตอร์เครื่องนี้ (ภายใน)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"ไมโครโฟน (ภายใน)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"หูฟังแบบใช้สาย"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"หูฟัง"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"ลำโพง USB"</string> <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> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index 5a1d4d79831d..926ce8f65406 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"Sa computer na ito (internal)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"Mikropono (internal)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Wired na headphone"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"Headphone"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB speaker"</string> <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> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index 2de4c097775c..3ccbcf2d4205 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -287,8 +287,8 @@ <string name="oem_unlock_enable_summary" msgid="5857388174390953829">"Дозволити розблокування завантажувача"</string> <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"Дозволити виробникові розблоковувати пристрій?"</string> <string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"ЗАСТЕРЕЖЕННЯ. Функції захисту пристрою не працюватимуть, поки ввімкнено це налаштування."</string> - <string name="mock_location_app" msgid="6269380172542248304">"Вибрати додаток для фіктивних місцезнаходжень"</string> - <string name="mock_location_app_not_set" msgid="6972032787262831155">"Додаток для фіктивних місцезнаходжень не вибрано"</string> + <string name="mock_location_app" msgid="6269380172542248304">"Вибрати додаток для фіктивних місцеположень"</string> + <string name="mock_location_app_not_set" msgid="6972032787262831155">"Додаток для фіктивних місцеположень не вибрано"</string> <string name="mock_location_app_set" msgid="4706722469342913843">"Додаток для фіктивних місцезнаходжень: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="6829757985772659599">"Мережі"</string> <string name="wifi_display_certification" msgid="1805579519992520381">"Сертифікація бездрот. екрана"</string> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index e2fbfab708c5..2157f63325f1 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -582,8 +582,7 @@ <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 /> + <string name="media_transfer_this_device_name_desktop" msgid="7912386128141470452">"یہ کمپیوٹر (داخلی)"</string> <!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) --> <skip /> <string name="media_transfer_internal_mic" msgid="797333824290228595">"مائیکروفون (داخلی)"</string> @@ -687,12 +686,9 @@ <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> - <!-- 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 /> + <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"تار والا ہیڈ فون"</string> + <string name="media_transfer_headphone_name" msgid="1131962659136578852">"ہیڈ فون"</string> + <string name="media_transfer_usb_speaker_name" msgid="4736537022543593896">"USB اسپیکر"</string> <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> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index 533a53fc69cc..736a30d0d169 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -100,7 +100,7 @@ <string name="bluetooth_active_battery_level_untethered_right" msgid="7407517998880370179">"使用中。右側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> 電量。"</string> <string name="bluetooth_battery_level" msgid="2893696778200201555">"電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> - <string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"左側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>,右側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> 電量。"</string> + <string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"左:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>,右:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> 電量。"</string> <string name="bluetooth_battery_level_untethered_left" msgid="5725764679536058365">"左側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> 電量"</string> <string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"右側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> 電量。"</string> <string name="tv_bluetooth_battery_level_untethered_left" msgid="337629670583744410">"左耳機:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java b/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java index ff00fb3282b1..c634216c2589 100644 --- a/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java @@ -33,6 +33,8 @@ import android.text.TextUtils; import android.text.format.DateFormat; import android.util.Log; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import java.io.BufferedReader; @@ -153,13 +155,19 @@ public class DeviceInfoUtils { return null; } - public static String getSecurityPatch() { + /** Returns security patch in default locale. */ + public static @Nullable String getSecurityPatch() { + return getSecurityPatch(Locale.getDefault()); + } + + /** Returns security patch in given locale. */ + public static @Nullable String getSecurityPatch(@NonNull Locale locale) { String patch = Build.VERSION.SECURITY_PATCH; if (!"".equals(patch)) { try { SimpleDateFormat template = new SimpleDateFormat("yyyy-MM-dd"); Date patchDate = template.parse(patch); - String format = DateFormat.getBestDateTimePattern(Locale.getDefault(), "dMMMMyyyy"); + String format = DateFormat.getBestDateTimePattern(locale, "dMMMMyyyy"); patch = DateFormat.format(format, patchDate).toString(); } catch (ParseException e) { // broken parse; fall through and use the raw string diff --git a/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java index e41126f03c60..2475c8e9dfd1 100644 --- a/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java @@ -31,6 +31,8 @@ import androidx.preference.PreferenceViewHolder; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.core.instrumentation.SettingsJankMonitor; +import com.android.settingslib.widget.SettingsThemeHelper; +import com.android.settingslib.widget.theme.R; /** * A custom preference that provides inline switch toggle. It has a mandatory field for title, and @@ -62,7 +64,9 @@ public class PrimarySwitchPreference extends RestrictedPreference { @Override protected int getSecondTargetResId() { - return androidx.preference.R.layout.preference_widget_switch_compat; + return SettingsThemeHelper.isExpressiveTheme(getContext()) + ? R.layout.settingslib_expressive_preference_switch + : androidx.preference.R.layout.preference_widget_switch_compat; } @Override diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java index 9dd2dbb41295..dae69e64934c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java @@ -132,8 +132,7 @@ public class InputMediaDevice extends MediaDevice { @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/notification/data/repository/FakeZenModeRepository.kt b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt index c686708a3c18..43d79466d6ca 100644 --- a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt +++ b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt @@ -74,6 +74,10 @@ class FakeZenModeRepository : ZenModeRepository { mutableModesFlow.value = mutableModesFlow.value.filter { it.id != id } } + fun replaceMode(modeId: String, mode: ZenMode) { + mutableModesFlow.value = (mutableModesFlow.value.filter { it.id != modeId }) + mode + } + fun getMode(id: String): ZenMode? { return mutableModesFlow.value.find { it.id == id } } 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 bc1ea6c42fa3..088d554326e7 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 @@ package com.android.settingslib.media; 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 @@ public class InputMediaDeviceTest { 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/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index f64c3059e3a4..749ad0a993b3 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -967,7 +967,7 @@ public class SettingsProvider extends ContentProvider { for (int i = 0; i < nameCount; i++) { String name = names.get(i); Setting setting = settingsState.getSettingLocked(name); - pw.print("_id:"); pw.print(toDumpString(setting.getId())); + pw.print("_id:"); pw.print(toDumpString(String.valueOf(setting.getId()))); pw.print(" name:"); pw.print(toDumpString(name)); if (setting.getPackageName() != null) { pw.print(" pkg:"); pw.print(setting.getPackageName()); @@ -2785,7 +2785,7 @@ public class SettingsProvider extends ContentProvider { switch (column) { case Settings.NameValueTable._ID -> { - values[i] = setting.getId(); + values[i] = String.valueOf(setting.getId()); } case Settings.NameValueTable.NAME -> { values[i] = setting.getName(); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index 452edd924a26..3c634f067a0d 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -517,6 +517,7 @@ final class SettingsState { } String namespace = name.substring(0, slashIdx); + namespace = namespace.intern(); // Many configs have the same namespace. String fullFlagName = name.substring(slashIdx + 1); boolean isLocal = false; @@ -566,7 +567,7 @@ final class SettingsState { } try { localCounter = Integer.parseInt(markerSetting.value); - } catch(NumberFormatException e) { + } catch (NumberFormatException e) { // reset local counter markerSetting.value = "0"; } @@ -1363,7 +1364,10 @@ final class SettingsState { } try { - if (writeSingleSetting(mVersion, serializer, setting.getId(), + if (writeSingleSetting( + mVersion, + serializer, + Long.toString(setting.getId()), setting.getName(), setting.getValue(), setting.getDefaultValue(), setting.getPackageName(), @@ -1632,7 +1636,7 @@ final class SettingsState { TypedXmlPullParser parser = Xml.resolvePullParser(in); parseStateLocked(parser); return true; - } catch (XmlPullParserException | IOException e) { + } catch (XmlPullParserException | IOException | NumberFormatException e) { Slog.e(LOG_TAG, "parse settings xml failed", e); return false; } finally { @@ -1652,7 +1656,7 @@ final class SettingsState { } private void parseStateLocked(TypedXmlPullParser parser) - throws IOException, XmlPullParserException { + throws IOException, XmlPullParserException, NumberFormatException { final int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT @@ -1708,7 +1712,7 @@ final class SettingsState { @GuardedBy("mLock") private void parseSettingsLocked(TypedXmlPullParser parser) - throws IOException, XmlPullParserException { + throws IOException, XmlPullParserException, NumberFormatException { mVersion = parser.getAttributeInt(null, ATTR_VERSION); @@ -1776,7 +1780,7 @@ final class SettingsState { } } mSettings.put(name, new Setting(name, value, defaultValue, packageName, tag, - fromSystem, id, isPreservedInRestore)); + fromSystem, Long.valueOf(id), isPreservedInRestore)); if (DEBUG_PERSISTENCE) { Slog.i(LOG_TAG, "[RESTORED] " + name + "=" + value); @@ -1866,7 +1870,7 @@ final class SettingsState { private String value; private String defaultValue; private String packageName; - private String id; + private long id; private String tag; // Whether the default is set by the system private boolean defaultFromSystem; @@ -1898,30 +1902,27 @@ final class SettingsState { } public Setting(String name, String value, String defaultValue, - String packageName, String tag, boolean fromSystem, String id) { + String packageName, String tag, boolean fromSystem, long id) { this(name, value, defaultValue, packageName, tag, fromSystem, id, /* isOverrideableByRestore */ false); } Setting(String name, String value, String defaultValue, - String packageName, String tag, boolean fromSystem, String id, + String packageName, String tag, boolean fromSystem, long id, boolean isValuePreservedInRestore) { - mNextId = Math.max(mNextId, Long.parseLong(id) + 1); - if (NULL_VALUE.equals(value)) { - value = null; - } + mNextId = Math.max(mNextId, id + 1); init(name, value, tag, defaultValue, packageName, fromSystem, id, isValuePreservedInRestore); } private void init(String name, String value, String tag, String defaultValue, - String packageName, boolean fromSystem, String id, + String packageName, boolean fromSystem, long id, boolean isValuePreservedInRestore) { this.name = name; - this.value = value; + this.value = internValue(value); this.tag = tag; - this.defaultValue = defaultValue; - this.packageName = packageName; + this.defaultValue = internValue(defaultValue); + this.packageName = TextUtils.safeIntern(packageName); this.id = id; this.defaultFromSystem = fromSystem; this.isValuePreservedInRestore = isValuePreservedInRestore; @@ -1959,7 +1960,7 @@ final class SettingsState { return isValuePreservedInRestore; } - public String getId() { + public long getId() { return id; } @@ -1992,9 +1993,6 @@ final class SettingsState { private boolean update(String value, boolean setDefault, String packageName, String tag, boolean forceNonSystemPackage, boolean overrideableByRestore, boolean resetToDefault) { - if (NULL_VALUE.equals(value)) { - value = null; - } final boolean callerSystem = !forceNonSystemPackage && !isNull() && (isCalledFromSystem(packageName) || isSystemPackage(mContext, packageName)); @@ -2039,7 +2037,7 @@ final class SettingsState { } init(name, value, tag, defaultValue, packageName, defaultFromSystem, - String.valueOf(mNextId++), isPreserved); + mNextId++, isPreserved); return true; } @@ -2051,6 +2049,32 @@ final class SettingsState { + " defaultFromSystem=" + defaultFromSystem + "}"; } + /** + * Interns a string if it's a common setting value. + * Otherwise returns the given string. + */ + static String internValue(String str) { + if (str == null) { + return null; + } + switch (str) { + case "true": + return "true"; + case "false": + return "false"; + case "0": + return "0"; + case "1": + return "1"; + case "": + return ""; + case "null": + return null; // explicit null has special handling + default: + return str; + } + } + private boolean shouldPreserveSetting(boolean overrideableByRestore, boolean resetToDefault, String packageName, String value) { if (resetToDefault) { diff --git a/packages/SystemUI/TEST_OWNERS b/packages/SystemUI/TEST_OWNERS new file mode 100644 index 000000000000..eadc86e386cb --- /dev/null +++ b/packages/SystemUI/TEST_OWNERS @@ -0,0 +1,5 @@ +# Test maintainers for system UI +# usernames listed here are able to approve changes to sysui unit tests, +# for restructuring and test maintenance only + +saff@google.com diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index c49ffb49a1da..f8383d94b1ab 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -149,16 +149,6 @@ flag { } flag { - name: "modes_dialog_single_rows" - namespace: "systemui" - description: "[Experiment] Display one entry per grid row in the Modes Dialog." - bug: "366034002" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "pss_app_selector_recents_split_screen" namespace: "systemui" description: "Allows recent apps selected for partial screenshare to be launched in split screen mode" @@ -599,6 +589,16 @@ flag { } flag { + name: "clipboard_use_description_mimetype" + namespace: "systemui" + description: "Read item mimetype from description rather than checking URI" + bug: "357197236" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "screenshot_action_dismiss_system_windows" namespace: "systemui" description: "Dismiss existing system windows when starting action from screenshot UI" 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 907c39d842ce..f5d01d70e077 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 @@ private class AnimatedDialog( } 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 fc4cf1d1e21e..859fc4e09bb2 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 @@ class TransitionAnimator( 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) - - if (moveBackgroundLayerWhenAppVisibilityChanges && controller.isLaunching) { - openingWindowSyncViewOverlay?.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) + } } } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt index aaf49ff00aca..9444664885c8 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt @@ -42,8 +42,9 @@ fun Modifier.burnInAware( isClock: Boolean = false, ): Modifier { val translationYState = remember { mutableStateOf(0F) } - val copiedParams = params.copy(translationY = { translationYState.value }) - val burnIn = viewModel.movement(copiedParams) + viewModel.updateBurnInParams(params.copy(translationY = { translationYState.value })) + + val burnIn = viewModel.movement val translationX by burnIn.map { it.translationX.toFloat() }.collectAsStateWithLifecycle(initialValue = 0f) val translationY by @@ -51,12 +52,7 @@ fun Modifier.burnInAware( translationYState.value = translationY val scaleViewModel by burnIn - .map { - BurnInScaleViewModel( - scale = it.scale, - scaleClockOnly = it.scaleClockOnly, - ) - } + .map { BurnInScaleViewModel(scale = it.scale, scaleClockOnly = it.scaleClockOnly) } .collectAsStateWithLifecycle(initialValue = BurnInScaleViewModel()) return this.graphicsLayer { @@ -72,8 +68,6 @@ fun Modifier.burnInAware( /** Reports the "top" coordinate of the modified composable to the given [consumer]. */ @Composable -fun Modifier.onTopPlacementChanged( - consumer: (Float) -> Unit, -): Modifier { +fun Modifier.onTopPlacementChanged(consumer: (Float) -> Unit): Modifier { return onPlaced { coordinates -> consumer(coordinates.boundsInWindow().top) } } 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 f4d9e820ad8f..3d8ca1e96a09 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 @@ -22,7 +22,9 @@ import android.widget.FrameLayout import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.layout.approachLayout import androidx.compose.ui.layout.layout @@ -31,8 +33,12 @@ import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.viewinterop.AndroidView import com.android.compose.animation.scene.MovableElementKey import com.android.compose.animation.scene.SceneScope +import com.android.compose.windowsizeclass.LocalWindowSizeClass +import com.android.internal.R.attr.layout +import com.android.systemui.media.controls.ui.composable.MediaCarouselStateLoader.stateForMediaCarouselContent import com.android.systemui.media.controls.ui.controller.MediaCarouselController import com.android.systemui.media.controls.ui.view.MediaHost +import com.android.systemui.media.controls.ui.view.MediaHostState import com.android.systemui.res.R import com.android.systemui.util.animation.MeasurementInput @@ -53,12 +59,20 @@ fun SceneScope.MediaCarousel( modifier: Modifier = Modifier, carouselController: MediaCarouselController, offsetProvider: (() -> IntOffset)? = null, + usingCollapsedLandscapeMedia: Boolean = false, ) { if (!isVisible || carouselController.isLockedAndHidden()) { return } - val mediaHeight = dimensionResource(R.dimen.qs_media_session_height_expanded) + val carouselState = remember { { stateForMediaCarouselContent() } } + val isCollapsed = usingCollapsedLandscapeMedia && isLandscape() + val mediaHeight = + if (isCollapsed && mediaHost.expansion == MediaHostState.COLLAPSED) { + dimensionResource(R.dimen.qs_media_session_height_collapsed) + } else { + dimensionResource(R.dimen.qs_media_session_height_expanded) + } MovableElement( key = MediaCarousel.Elements.Content, @@ -95,6 +109,7 @@ fun SceneScope.MediaCarousel( } }, factory = { context -> + MediaCarouselStateLoader.loadCarouselState(carouselController, carouselState()) FrameLayout(context).apply { layoutParams = FrameLayout.LayoutParams( @@ -103,7 +118,10 @@ fun SceneScope.MediaCarousel( ) } }, - update = { it.setView(carouselController.mediaFrame) }, + update = { + MediaCarouselStateLoader.loadCarouselState(carouselController, carouselState()) + it.setView(carouselController.mediaFrame) + }, onRelease = { it.removeAllViews() }, ) } @@ -117,3 +135,8 @@ private fun ViewGroup.setView(view: View) { (view.parent as? ViewGroup)?.removeView(view) addView(view) } + +@Composable +fun SceneScope.isLandscape(): Boolean { + return LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Compact +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarouselStateLoader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarouselStateLoader.kt new file mode 100644 index 000000000000..4a0136c40c14 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarouselStateLoader.kt @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.media.controls.ui.composable + +import com.android.compose.animation.scene.ContentKey +import com.android.compose.animation.scene.SceneKey +import com.android.compose.animation.scene.SceneScope +import com.android.compose.animation.scene.content.state.TransitionState +import com.android.systemui.media.controls.ui.controller.MediaCarouselController +import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager +import com.android.systemui.media.controls.ui.controller.MediaLocation +import com.android.systemui.scene.shared.model.Overlays +import com.android.systemui.scene.shared.model.Scenes +import kotlin.math.min + +object MediaCarouselStateLoader { + + /** Sets current state for media carousel. */ + fun loadCarouselState(carouselController: MediaCarouselController, state: State) { + if (state is State.Gone) return + + carouselController.setCurrentState( + state.startLocation, + state.endLocation, + state.transitionProgress, + immediately = true, + ) + } + + /** Returns the corresponding media location for the given [scene] */ + @MediaLocation + private fun getMediaLocation(scene: SceneKey): Int { + return when (scene) { + Scenes.QuickSettings -> MediaHierarchyManager.LOCATION_QS + Scenes.Shade -> MediaHierarchyManager.LOCATION_QQS + Scenes.Lockscreen -> MediaHierarchyManager.LOCATION_LOCKSCREEN + Scenes.Communal -> MediaHierarchyManager.LOCATION_COMMUNAL_HUB + else -> MediaHierarchyManager.LOCATION_UNKNOWN + } + } + + /** Returns the corresponding media location for the given [content] */ + @MediaLocation + private fun getMediaLocation(content: ContentKey): Int { + return when (content) { + Overlays.QuickSettingsShade -> MediaHierarchyManager.LOCATION_QS + Overlays.NotificationsShade -> MediaHierarchyManager.LOCATION_QQS + else -> MediaHierarchyManager.LOCATION_UNKNOWN + } + } + + /** State for media carousel. */ + sealed interface State { + val transitionProgress: Float + // TODO b/368368388: implement media squishiness + val squishFraction: () -> Float + @MediaLocation val startLocation: Int + @MediaLocation val endLocation: Int + + /** State when media carousel is not visible on screen. */ + data object Gone : State { + override val transitionProgress: Float = 1.0F + override val squishFraction: () -> Float = { 1.0F } + override val endLocation: Int = MediaHierarchyManager.LOCATION_UNKNOWN + override val startLocation: Int = MediaHierarchyManager.LOCATION_UNKNOWN + } + + /** State when media carousel is moving from one media location to another */ + data class InProgress( + override val transitionProgress: Float, + override val startLocation: Int, + override val endLocation: Int, + ) : State { + override val squishFraction = { 1.0F } + } + + /** State when media carousel reached the end location. */ + data class Idle(override val endLocation: Int) : State { + override val transitionProgress = 1.0F + override val startLocation = MediaHierarchyManager.LOCATION_UNKNOWN + override val squishFraction = { 1.0F } + } + } + + /** Returns the state of media carousel */ + fun SceneScope.stateForMediaCarouselContent(): State { + return when (val transitionState = layoutState.transitionState) { + is TransitionState.Idle -> { + if (MediaContentPicker.contents.contains(transitionState.currentScene)) { + State.Idle(getMediaLocation(transitionState.currentScene)) + } else { + State.Gone + } + } + is TransitionState.Transition.ChangeScene -> + with(transitionState) { + if ( + MediaContentPicker.contents.contains(toScene) && + MediaContentPicker.contents.contains(fromScene) + ) { + State.InProgress( + min(progress, 1.0F), + getMediaLocation(fromScene), + getMediaLocation(toScene), + ) + } else if (MediaContentPicker.contents.contains(toScene)) { + State.InProgress( + transitionProgress = 1.0F, + startLocation = MediaHierarchyManager.LOCATION_UNKNOWN, + getMediaLocation(toScene), + ) + } else { + State.Gone + } + } + is TransitionState.Transition.OverlayTransition -> + with(transitionState) { + if ( + MediaContentPicker.contents.contains(toContent) && + MediaContentPicker.contents.contains(fromContent) + ) { + State.InProgress( + min(progress, 1.0F), + getMediaLocation(fromContent), + getMediaLocation(toContent), + ) + } else if (MediaContentPicker.contents.contains(toContent)) { + State.InProgress( + transitionProgress = 1.0F, + startLocation = MediaHierarchyManager.LOCATION_UNKNOWN, + getMediaLocation(toContent), + ) + } else { + State.Gone + } + } + } + } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt index 1b99a9644575..fe4a65b8bbd0 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt @@ -130,8 +130,8 @@ object Notifications { fun SceneScope.HeadsUpNotificationSpace( stackScrollView: NotificationScrollView, viewModel: NotificationsPlaceholderViewModel, + useHunBounds: () -> Boolean = { true }, modifier: Modifier = Modifier, - isPeekFromBottom: Boolean = false, ) { Box( modifier = @@ -141,17 +141,25 @@ fun SceneScope.HeadsUpNotificationSpace( .notificationHeadsUpHeight(stackScrollView) .debugBackground(viewModel, DEBUG_HUN_COLOR) .onGloballyPositioned { coordinates: LayoutCoordinates -> - val positionInWindow = coordinates.positionInWindow() - val boundsInWindow = coordinates.boundsInWindow() - debugLog(viewModel) { - "HUNS onGloballyPositioned:" + - " size=${coordinates.size}" + - " bounds=$boundsInWindow" + // This element is sometimes opted out of the shared element system, so there + // can be multiple instances of it during a transition. Thus we need to + // determine which instance should feed its bounds to NSSL to avoid providing + // conflicting values + val useBounds = useHunBounds() + if (useBounds) { + val positionInWindow = coordinates.positionInWindow() + val boundsInWindow = coordinates.boundsInWindow() + debugLog(viewModel) { + "HUNS onGloballyPositioned:" + + " size=${coordinates.size}" + + " bounds=$boundsInWindow" + } + // Note: boundsInWindow doesn't scroll off the screen, so use + // positionInWindow + // for top bound, which can scroll off screen while snoozing + stackScrollView.setHeadsUpTop(positionInWindow.y) + stackScrollView.setHeadsUpBottom(boundsInWindow.bottom) } - // Note: boundsInWindow doesn't scroll off the screen, so use positionInWindow - // for top bound, which can scroll off screen while snoozing - stackScrollView.setHeadsUpTop(positionInWindow.y) - stackScrollView.setHeadsUpBottom(boundsInWindow.bottom) } ) } 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 d91958adaa1b..630497998c3e 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 @@ -48,7 +48,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect @@ -85,6 +84,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.media.controls.ui.composable.MediaCarousel +import com.android.systemui.media.controls.ui.composable.isLandscape import com.android.systemui.media.controls.ui.controller.MediaCarouselController import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.media.dagger.MediaModule @@ -288,9 +288,7 @@ private fun SceneScope.QuickSettingsScene( // ############# Media ############### val isMediaVisible by viewModel.isMediaVisible.collectAsStateWithLifecycle() - val mediaInRow = - isMediaVisible && - LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Compact + val mediaInRow = isMediaVisible && isLandscape() val mediaOffset by animateSceneDpAsState(value = InQS, key = MediaLandscapeTopOffset, canOverflow = false) @@ -416,11 +414,11 @@ private fun SceneScope.QuickSettingsScene( HeadsUpNotificationSpace( stackScrollView = notificationStackScrollView, viewModel = notificationsPlaceholderViewModel, + useHunBounds = { shouldUseQuickSettingsHunBounds(layoutState.transitionState) }, modifier = Modifier.align(Alignment.BottomCenter) .navigationBarsPadding() .padding(horizontal = shadeHorizontalPadding), - isPeekFromBottom = true, ) NotificationScrollingStack( shadeSession = shadeSession, @@ -446,3 +444,7 @@ private fun SceneScope.QuickSettingsScene( ) } } + +private fun shouldUseQuickSettingsHunBounds(state: TransitionState): Boolean { + return state is TransitionState.Idle && state.currentScene == Scenes.QuickSettings +} 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 8e6cb3fe9fb9..54497f621c73 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 @@ -124,8 +124,9 @@ fun SceneScope.ShadeBody(viewModel: QuickSettingsContainerViewModel) { } } +/** Column containing Brightness and QS tiles. */ @Composable -private fun SceneScope.QuickSettingsLayout( +fun SceneScope.QuickSettingsLayout( viewModel: QuickSettingsContainerViewModel, modifier: Modifier = Modifier, ) { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt index f64d0ed31287..58fbf430b20c 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt @@ -77,6 +77,10 @@ val SceneContainerTransitions = transitions { } from(Scenes.Lockscreen, to = Scenes.QuickSettings) { lockscreenToQuickSettingsTransition() } from(Scenes.Lockscreen, to = Scenes.Gone) { lockscreenToGoneTransition() } + from(Scenes.QuickSettings, to = Scenes.Shade) { + reversed { shadeToQuickSettingsTransition() } + sharedElement(Notifications.Elements.HeadsUpNotificationPlaceholder, enabled = false) + } from(Scenes.Shade, to = Scenes.QuickSettings) { shadeToQuickSettingsTransition() } // Overlay transitions 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 6c4edf49fd83..4162891c0e0b 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 @@ private fun Modifier.panelPadding(): Modifier { /** 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/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt index 8a59e204eb23..7f2ee2a8351a 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt @@ -43,7 +43,6 @@ import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect @@ -78,7 +77,6 @@ import com.android.compose.animation.scene.animateSceneFloatAsState import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.modifiers.padding import com.android.compose.modifiers.thenIf -import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.systemui.battery.BatteryMeterViewController import com.android.systemui.common.ui.compose.windowinsets.CutoutLocation import com.android.systemui.common.ui.compose.windowinsets.LocalDisplayCutout @@ -89,6 +87,7 @@ import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.media.controls.ui.composable.MediaCarousel import com.android.systemui.media.controls.ui.composable.MediaContentPicker +import com.android.systemui.media.controls.ui.composable.isLandscape import com.android.systemui.media.controls.ui.composable.shouldElevateMedia import com.android.systemui.media.controls.ui.controller.MediaCarouselController import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager @@ -197,6 +196,8 @@ constructor( qsMediaHost = qsMediaHost, modifier = modifier, shadeSession = shadeSession, + usingCollapsedLandscapeMedia = + Utils.useCollapsedMediaInLandscape(LocalContext.current.resources), ) init { @@ -223,6 +224,7 @@ private fun SceneScope.ShadeScene( qsMediaHost: MediaHost, modifier: Modifier = Modifier, shadeSession: SaveableSession, + usingCollapsedLandscapeMedia: Boolean, ) { val view = LocalView.current LaunchedEffect(Unit) { @@ -245,6 +247,7 @@ private fun SceneScope.ShadeScene( mediaHost = qqsMediaHost, modifier = modifier, shadeSession = shadeSession, + usingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia, ) is ShadeMode.Split -> SplitShade( @@ -275,14 +278,11 @@ private fun SceneScope.SingleShade( mediaHost: MediaHost, modifier: Modifier = Modifier, shadeSession: SaveableSession, + usingCollapsedLandscapeMedia: Boolean, ) { val cutoutLocation = LocalDisplayCutout.current.location val cutoutInsets = WindowInsets.Companion.displayCutout - val isLandscape = LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Compact - val usingCollapsedLandscapeMedia = - Utils.useCollapsedMediaInLandscape(LocalContext.current.resources) - val isExpanded = !usingCollapsedLandscapeMedia || !isLandscape - mediaHost.expansion = if (isExpanded) EXPANDED else COLLAPSED + mediaHost.expansion = if (usingCollapsedLandscapeMedia && isLandscape()) COLLAPSED else EXPANDED var maxNotifScrimTop by remember { mutableIntStateOf(0) } val tileSquishiness by @@ -298,7 +298,7 @@ private fun SceneScope.SingleShade( layoutState.isTransitioningBetween(Scenes.Gone, Scenes.Shade) || layoutState.isTransitioningBetween(Scenes.Lockscreen, Scenes.Shade) // Media is visible and we are in landscape on a small height screen - val mediaInRow = isMediaVisible && isLandscape + val mediaInRow = isMediaVisible && isLandscape() val mediaOffset by animateSceneDpAsState(value = InQQS, key = MediaLandscapeTopOffset, canOverflow = false) @@ -380,6 +380,7 @@ private fun SceneScope.SingleShade( mediaOffsetProvider = mediaOffsetProvider, carouselController = mediaCarouselController, modifier = Modifier.layoutId(SingleShadeMeasurePolicy.LayoutId.Media), + usingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia, ) NotificationScrollingStack( @@ -636,6 +637,7 @@ private fun SceneScope.ShadeMediaCarousel( carouselController: MediaCarouselController, mediaOffsetProvider: ShadeMediaOffsetProvider, modifier: Modifier = Modifier, + usingCollapsedLandscapeMedia: Boolean = false, ) { MediaCarousel( modifier = modifier.fillMaxWidth(), @@ -648,5 +650,6 @@ private fun SceneScope.ShadeMediaCarousel( } else { { mediaOffsetProvider.offset } }, + usingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia, ) } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java index 6ee8ffd91ab0..6ee8ffd91ab0 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java diff --git a/packages/SystemUI/tests/src/com/android/keyguard/BouncerKeyguardMessageAreaTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/BouncerKeyguardMessageAreaTest.kt index 049d77a7a454..049d77a7a454 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/BouncerKeyguardMessageAreaTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/BouncerKeyguardMessageAreaTest.kt diff --git a/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt index bb2340aafbb5..bb2340aafbb5 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt diff --git a/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/EmergencyButtonControllerTest.kt index c42e25b20e0d..c42e25b20e0d 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/EmergencyButtonControllerTest.kt diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardBiometricLockoutLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardBiometricLockoutLoggerTest.kt index d170e4840842..d170e4840842 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardBiometricLockoutLoggerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardBiometricLockoutLoggerTest.kt diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java index 2bb9e68a357a..2bb9e68a357a 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java index 892375d002c1..892375d002c1 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerWithCoroutinesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardClockSwitchControllerWithCoroutinesTest.kt index c2c0f5713d9b..c2c0f5713d9b 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerWithCoroutinesTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardClockSwitchControllerWithCoroutinesTest.kt diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardClockSwitchTest.java index 0bf9d12a09d5..0bf9d12a09d5 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardClockSwitchTest.java diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.java index dd58ea7db2bc..dd58ea7db2bc 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.java diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java index bd811814eb24..bd811814eb24 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java index 312e62d0b624..94d3b2ccc9e5 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -62,7 +62,9 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.res.R; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.user.data.source.UserRecord; +import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.settings.GlobalSettings; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Rule; @@ -96,6 +98,7 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { private FalsingA11yDelegate mFalsingA11yDelegate; private KeyguardSecurityContainer mKeyguardSecurityContainer; + private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); @Before public void setup() { @@ -106,6 +109,7 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { mSecurityViewFlipper = new KeyguardSecurityViewFlipper(getContext()); mSecurityViewFlipper.setId(View.generateViewId()); mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext()); + mKeyguardSecurityContainer.setBackgroundExecutor(mExecutor); mKeyguardSecurityContainer.setRight(VIEW_WIDTH); mKeyguardSecurityContainer.setLeft(0); mKeyguardSecurityContainer.setTop(0); @@ -342,7 +346,7 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { @Test public void testTwoOrMoreUsersDoesAllowDropDown() { - // GIVEN one user has been setup + // GIVEN two users have been setup ArrayList<UserRecord> records = buildUserRecords(2); when(mUserSwitcherController.getCurrentUserRecord()).thenReturn(records.get(0)); when(mUserSwitcherController.getUsers()).thenReturn(records); @@ -350,7 +354,7 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { // WHEN UserSwitcherViewMode is initialized setupUserSwitcher(); - // THEN the UserSwitcher anchor should not be clickable + // THEN the UserSwitcher anchor should be clickable ViewGroup anchor = mKeyguardSecurityContainer.findViewById(R.id.user_switcher_anchor); assertThat(anchor.isClickable()).isTrue(); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSliceViewTest.java index d96518abc007..d96518abc007 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSliceViewTest.java diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusAreaViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardStatusAreaViewTest.kt index 64e499674d9f..64e499674d9f 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusAreaViewTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardStatusAreaViewTest.kt diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java index 2b4fc5bd5cc5..2b4fc5bd5cc5 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerWithCoroutinesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardStatusViewControllerWithCoroutinesTest.kt index c29439d89753..c29439d89753 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerWithCoroutinesTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardStatusViewControllerWithCoroutinesTest.kt diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardStatusViewTest.kt index 16d2f0205c84..16d2f0205c84 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardStatusViewTest.kt diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt index 2e41246a62a1..2e41246a62a1 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUserSwitcherAnchorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardUserSwitcherAnchorTest.kt index e7b4262419ce..e7b4262419ce 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUserSwitcherAnchorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardUserSwitcherAnchorTest.kt diff --git a/packages/SystemUI/tests/src/com/android/keyguard/NumPadAnimatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/NumPadAnimatorTest.kt index 18976e135e9c..18976e135e9c 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/NumPadAnimatorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/NumPadAnimatorTest.kt diff --git a/packages/SystemUI/tests/src/com/android/keyguard/PinShapeHintingViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/PinShapeHintingViewTest.kt index d8f2b1016657..d8f2b1016657 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/PinShapeHintingViewTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/PinShapeHintingViewTest.kt diff --git a/packages/SystemUI/tests/src/com/android/keyguard/PinShapeNonHintingViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/PinShapeNonHintingViewTest.kt index 447cf65ba293..447cf65ba293 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/PinShapeNonHintingViewTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/PinShapeNonHintingViewTest.kt diff --git a/packages/SystemUI/tests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt index c7d11ef16100..c7d11ef16100 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt diff --git a/packages/SystemUI/tests/src/com/android/keyguard/TestScopeProvider.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/TestScopeProvider.kt index 6c35734c6eb4..6c35734c6eb4 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/TestScopeProvider.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/TestScopeProvider.kt diff --git a/packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt index 5247a89896d1..5247a89896d1 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt index cbad133ba4f0..8c7cd619a158 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt @@ -114,14 +114,15 @@ class BackActionInteractorTest : SysuiTestCase() { private val backActionInteractor: BackActionInteractor by lazy { BackActionInteractor( - testScope.backgroundScope, - statusBarStateController, - statusBarKeyguardViewManager, - shadeController, - notificationShadeWindowController, - windowRootViewVisibilityInteractor - ) - .apply { this.setup(qsController, shadeBackActionInteractor) } + testScope.backgroundScope, + statusBarStateController, + statusBarKeyguardViewManager, + shadeController, + notificationShadeWindowController, + windowRootViewVisibilityInteractor, + shadeBackActionInteractor, + qsController, + ) } private val powerInteractor = PowerInteractorFactory.create().powerInteractor diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt index 4bc71fd6d363..75a77cf781d2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt @@ -27,17 +27,6 @@ import android.hardware.face.FaceSensorProperties import android.hardware.face.FaceSensorPropertiesInternal import android.hardware.fingerprint.FingerprintSensorProperties import android.hardware.fingerprint.FingerprintSensorPropertiesInternal -import com.android.keyguard.keyguardUpdateMonitor -import com.android.systemui.SysuiTestableContext -import com.android.systemui.biometrics.data.repository.biometricStatusRepository -import com.android.systemui.biometrics.shared.model.AuthenticationReason -import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository -import com.android.systemui.kosmos.Kosmos -import com.android.systemui.res.R -import com.android.systemui.util.mockito.whenever -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.TestScope -import kotlinx.coroutines.test.runCurrent /** Create [FingerprintSensorPropertiesInternal] for a test. */ internal fun fingerprintSensorPropertiesInternal( @@ -156,67 +145,3 @@ internal fun promptInfo( info.negativeButtonText = negativeButton return info } - -@OptIn(ExperimentalCoroutinesApi::class) -internal fun TestScope.updateSfpsIndicatorRequests( - kosmos: Kosmos, - mContext: SysuiTestableContext, - primaryBouncerRequest: Boolean? = null, - alternateBouncerRequest: Boolean? = null, - biometricPromptRequest: Boolean? = null, - // TODO(b/365182034): update when rest to unlock feature is implemented - // progressBarShowing: Boolean? = null -) { - biometricPromptRequest?.let { hasBiometricPromptRequest -> - if (hasBiometricPromptRequest) { - kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( - AuthenticationReason.BiometricPromptAuthentication - ) - } else { - kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( - AuthenticationReason.NotRunning - ) - } - } - - primaryBouncerRequest?.let { hasPrimaryBouncerRequest -> - updatePrimaryBouncer( - kosmos, - mContext, - isShowing = hasPrimaryBouncerRequest, - isAnimatingAway = false, - fpsDetectionRunning = true, - isUnlockingWithFpAllowed = true - ) - } - - alternateBouncerRequest?.let { hasAlternateBouncerRequest -> - kosmos.keyguardBouncerRepository.setAlternateVisible(hasAlternateBouncerRequest) - } - - // TODO(b/365182034): set progress bar visibility when rest to unlock feature is implemented - - runCurrent() -} - -internal fun updatePrimaryBouncer( - kosmos: Kosmos, - mContext: SysuiTestableContext, - isShowing: Boolean, - isAnimatingAway: Boolean, - fpsDetectionRunning: Boolean, - isUnlockingWithFpAllowed: Boolean, -) { - kosmos.keyguardBouncerRepository.setPrimaryShow(isShowing) - kosmos.keyguardBouncerRepository.setPrimaryStartingToHide(false) - val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null - kosmos.keyguardBouncerRepository.setPrimaryStartDisappearAnimation( - primaryStartDisappearAnimation - ) - - whenever(kosmos.keyguardUpdateMonitor.isFingerprintDetectionRunning) - .thenReturn(fpsDetectionRunning) - whenever(kosmos.keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed) - .thenReturn(isUnlockingWithFpAllowed) - mContext.orCreateTestableResources.addOverride(R.bool.config_show_sidefps_hint_on_bouncer, true) -} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt deleted file mode 100644 index 298b54a5be5a..000000000000 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt +++ /dev/null @@ -1,174 +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.biometrics.domain.interactor - -import android.testing.TestableLooper -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase -import com.android.systemui.biometrics.data.repository.biometricStatusRepository -import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository -import com.android.systemui.biometrics.shared.model.AuthenticationReason -import com.android.systemui.biometrics.shared.model.FingerprintSensorType -import com.android.systemui.biometrics.shared.model.SensorStrength -import com.android.systemui.biometrics.updateSfpsIndicatorRequests -import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.display.data.repository.displayRepository -import com.android.systemui.display.data.repository.displayStateRepository -import com.android.systemui.kosmos.testScope -import com.android.systemui.testKosmos -import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.TestScope -import kotlinx.coroutines.test.runCurrent -import kotlinx.coroutines.test.runTest -import org.junit.Ignore -import org.junit.Test -import org.junit.runner.RunWith - -@OptIn(ExperimentalCoroutinesApi::class) -@SmallTest -@RunWith(AndroidJUnit4::class) -@TestableLooper.RunWithLooper(setAsMainLooper = true) -class SideFpsOverlayInteractorTest : SysuiTestCase() { - private val kosmos = testKosmos() - private val underTest = kosmos.sideFpsOverlayInteractor - - @Test - fun verifyIsShowingFalse_whenInRearDisplayMode() { - kosmos.testScope.runTest { - val isShowing by collectLastValue(underTest.isShowing) - setupTestConfiguration(isInRearDisplayMode = true) - - updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = true) - runCurrent() - - assertThat(isShowing).isFalse() - } - } - - @Test - fun verifyIsShowingUpdates_onPrimaryBouncerShowAndHide() { - kosmos.testScope.runTest { - val isShowing by collectLastValue(underTest.isShowing) - setupTestConfiguration(isInRearDisplayMode = false) - - // Show primary bouncer - updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = true) - runCurrent() - - assertThat(isShowing).isTrue() - - // Hide primary bouncer - updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = false) - runCurrent() - - assertThat(isShowing).isFalse() - } - } - - @Test - fun verifyIsShowingUpdates_onAlternateBouncerShowAndHide() { - kosmos.testScope.runTest { - val isShowing by collectLastValue(underTest.isShowing) - setupTestConfiguration(isInRearDisplayMode = false) - - updateSfpsIndicatorRequests(kosmos, mContext, alternateBouncerRequest = true) - runCurrent() - - assertThat(isShowing).isTrue() - - // Hide alternate bouncer - updateSfpsIndicatorRequests(kosmos, mContext, alternateBouncerRequest = false) - runCurrent() - - assertThat(isShowing).isFalse() - } - } - - @Test - fun verifyIsShowingUpdates_onSystemServerAuthenticationStartedAndStopped() { - kosmos.testScope.runTest { - val isShowing by collectLastValue(underTest.isShowing) - setupTestConfiguration(isInRearDisplayMode = false) - - updateSfpsIndicatorRequests(kosmos, mContext, biometricPromptRequest = true) - runCurrent() - - assertThat(isShowing).isTrue() - - // System server authentication stopped - updateSfpsIndicatorRequests(kosmos, mContext, biometricPromptRequest = false) - runCurrent() - - assertThat(isShowing).isFalse() - } - } - - // On progress bar shown - hide indicator - // On progress bar hidden - show indicator - // TODO(b/365182034): update + enable when rest to unlock feature is implemented - @Ignore("b/365182034") - @Test - fun verifyIsShowingUpdates_onProgressBarInteraction() { - kosmos.testScope.runTest { - val isShowing by collectLastValue(underTest.isShowing) - setupTestConfiguration(isInRearDisplayMode = false) - - updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = true) - runCurrent() - - assertThat(isShowing).isTrue() - - // updateSfpsIndicatorRequests( - // kosmos, mContext, primaryBouncerRequest = true, progressBarShowing = - // true - // ) - runCurrent() - - assertThat(isShowing).isFalse() - - // Set progress bar invisible - // updateSfpsIndicatorRequests( - // kosmos, mContext, primaryBouncerRequest = true, progressBarShowing = - // false - // ) - runCurrent() - - // Verify indicator shown - assertThat(isShowing).isTrue() - } - } - - private suspend fun TestScope.setupTestConfiguration(isInRearDisplayMode: Boolean) { - kosmos.fingerprintPropertyRepository.setProperties( - sensorId = 1, - strength = SensorStrength.STRONG, - sensorType = FingerprintSensorType.POWER_BUTTON, - sensorLocations = emptyMap() - ) - - kosmos.displayStateRepository.setIsInRearDisplayMode(isInRearDisplayMode) - kosmos.displayRepository.emitDisplayChangeEvent(0) - runCurrent() - - kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( - AuthenticationReason.NotRunning - ) - // TODO(b/365182034): set progress bar visibility once rest to unlock feature is implemented - } -} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt index 2eea6681ecca..7fa165c19f60 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt @@ -16,48 +16,64 @@ package com.android.systemui.biometrics.ui.binder +import android.animation.Animator +import android.graphics.Rect +import android.hardware.biometrics.SensorLocationInternal +import android.hardware.display.DisplayManager +import android.hardware.display.DisplayManagerGlobal import android.testing.TestableLooper +import android.view.Display +import android.view.DisplayInfo import android.view.LayoutInflater import android.view.View +import android.view.ViewPropertyAnimator +import android.view.WindowInsets import android.view.WindowManager +import android.view.WindowMetrics import android.view.layoutInflater import android.view.windowManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.airbnb.lottie.LottieAnimationView +import com.android.keyguard.keyguardUpdateMonitor import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider +import com.android.systemui.biometrics.data.repository.biometricStatusRepository import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository +import com.android.systemui.biometrics.shared.model.AuthenticationReason import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.SensorStrength -import com.android.systemui.biometrics.updateSfpsIndicatorRequests +import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository import com.android.systemui.display.data.repository.displayRepository import com.android.systemui.display.data.repository.displayStateRepository +import com.android.systemui.keyguard.ui.viewmodel.sideFpsProgressBarViewModel import com.android.systemui.kosmos.testScope import com.android.systemui.res.R import com.android.systemui.testKosmos import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.whenever import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor -import org.mockito.Captor import org.mockito.Mock +import org.mockito.Mockito import org.mockito.Mockito.any import org.mockito.Mockito.inOrder import org.mockito.Mockito.mock import org.mockito.Mockito.never +import org.mockito.Mockito.spy import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule -import org.mockito.kotlin.firstValue +import org.mockito.kotlin.argumentCaptor @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @@ -67,25 +83,84 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() { private val kosmos = testKosmos() @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule() + @Mock private lateinit var displayManager: DisplayManager + @Mock + private lateinit var fingerprintInteractiveToAuthProvider: FingerprintInteractiveToAuthProvider @Mock private lateinit var layoutInflater: LayoutInflater @Mock private lateinit var sideFpsView: View - @Captor private lateinit var viewCaptor: ArgumentCaptor<View> + + private val contextDisplayInfo = DisplayInfo() + + private var displayWidth: Int = 0 + private var displayHeight: Int = 0 + private var boundsWidth: Int = 0 + private var boundsHeight: Int = 0 + + private lateinit var deviceConfig: DeviceConfig + private lateinit var sensorLocation: SensorLocationInternal + + enum class DeviceConfig { + X_ALIGNED, + Y_ALIGNED, + } @Before fun setup() { allowTestableLooperAsMainThread() // repeatWhenAttached requires the main thread + + mContext = spy(mContext) + + val resources = mContext.resources + whenever(mContext.display) + .thenReturn( + Display(mock(DisplayManagerGlobal::class.java), 1, contextDisplayInfo, resources) + ) + kosmos.layoutInflater = layoutInflater + + whenever(fingerprintInteractiveToAuthProvider.enabledForCurrentUser) + .thenReturn(MutableStateFlow(false)) + + context.addMockSystemService(DisplayManager::class.java, displayManager) context.addMockSystemService(WindowManager::class.java, kosmos.windowManager) + `when`(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sideFpsView) `when`(sideFpsView.requireViewById<LottieAnimationView>(eq(R.id.sidefps_animation))) .thenReturn(mock(LottieAnimationView::class.java)) + with(mock(ViewPropertyAnimator::class.java)) { + `when`(sideFpsView.animate()).thenReturn(this) + `when`(alpha(Mockito.anyFloat())).thenReturn(this) + `when`(setStartDelay(Mockito.anyLong())).thenReturn(this) + `when`(setDuration(Mockito.anyLong())).thenReturn(this) + `when`(setListener(any())).thenAnswer { + (it.arguments[0] as Animator.AnimatorListener).onAnimationEnd( + mock(Animator::class.java) + ) + this + } + } } @Test fun verifyIndicatorNotAdded_whenInRearDisplayMode() { kosmos.testScope.runTest { - setupTestConfiguration(isInRearDisplayMode = true) - updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = true) + setupTestConfiguration( + DeviceConfig.X_ALIGNED, + rotation = DisplayRotation.ROTATION_0, + isInRearDisplayMode = true + ) + kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( + AuthenticationReason.NotRunning + ) + kosmos.sideFpsProgressBarViewModel.setVisible(false) + updatePrimaryBouncer( + isShowing = true, + isAnimatingAway = false, + fpsDetectionRunning = true, + isUnlockingWithFpAllowed = true + ) + runCurrent() + verify(kosmos.windowManager, never()).addView(any(), any()) } } @@ -93,14 +168,33 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() { @Test fun verifyIndicatorShowAndHide_onPrimaryBouncerShowAndHide() { kosmos.testScope.runTest { - setupTestConfiguration(isInRearDisplayMode = false) - updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = true) + setupTestConfiguration( + DeviceConfig.X_ALIGNED, + rotation = DisplayRotation.ROTATION_0, + isInRearDisplayMode = false + ) + kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( + AuthenticationReason.NotRunning + ) + kosmos.sideFpsProgressBarViewModel.setVisible(false) + // Show primary bouncer + updatePrimaryBouncer( + isShowing = true, + isAnimatingAway = false, + fpsDetectionRunning = true, + isUnlockingWithFpAllowed = true + ) runCurrent() verify(kosmos.windowManager).addView(any(), any()) // Hide primary bouncer - updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = false) + updatePrimaryBouncer( + isShowing = false, + isAnimatingAway = false, + fpsDetectionRunning = true, + isUnlockingWithFpAllowed = true + ) runCurrent() verify(kosmos.windowManager).removeView(any()) @@ -110,19 +204,30 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() { @Test fun verifyIndicatorShowAndHide_onAlternateBouncerShowAndHide() { kosmos.testScope.runTest { - setupTestConfiguration(isInRearDisplayMode = false) - updateSfpsIndicatorRequests(kosmos, mContext, alternateBouncerRequest = true) + setupTestConfiguration( + DeviceConfig.X_ALIGNED, + rotation = DisplayRotation.ROTATION_0, + isInRearDisplayMode = false + ) + kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( + AuthenticationReason.NotRunning + ) + kosmos.sideFpsProgressBarViewModel.setVisible(false) + // Show alternate bouncer + kosmos.keyguardBouncerRepository.setAlternateVisible(true) runCurrent() verify(kosmos.windowManager).addView(any(), any()) + var viewCaptor = argumentCaptor<View>() verify(kosmos.windowManager).addView(viewCaptor.capture(), any()) verify(viewCaptor.firstValue) .announceForAccessibility( mContext.getText(R.string.accessibility_side_fingerprint_indicator_label) ) - updateSfpsIndicatorRequests(kosmos, mContext, alternateBouncerRequest = false) + // Hide alternate bouncer + kosmos.keyguardBouncerRepository.setAlternateVisible(false) runCurrent() verify(kosmos.windowManager).removeView(any()) @@ -132,14 +237,30 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() { @Test fun verifyIndicatorShownAndHidden_onSystemServerAuthenticationStartedAndStopped() { kosmos.testScope.runTest { - setupTestConfiguration(isInRearDisplayMode = false) - updateSfpsIndicatorRequests(kosmos, mContext, biometricPromptRequest = true) + setupTestConfiguration( + DeviceConfig.X_ALIGNED, + rotation = DisplayRotation.ROTATION_0, + isInRearDisplayMode = false + ) + kosmos.sideFpsProgressBarViewModel.setVisible(false) + updatePrimaryBouncer( + isShowing = false, + isAnimatingAway = false, + fpsDetectionRunning = true, + isUnlockingWithFpAllowed = true + ) + // System server authentication started + kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( + AuthenticationReason.BiometricPromptAuthentication + ) runCurrent() verify(kosmos.windowManager).addView(any(), any()) // System server authentication stopped - updateSfpsIndicatorRequests(kosmos, mContext, biometricPromptRequest = false) + kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( + AuthenticationReason.NotRunning + ) runCurrent() verify(kosmos.windowManager).removeView(any()) @@ -148,35 +269,45 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() { // On progress bar shown - hide indicator // On progress bar hidden - show indicator - // TODO(b/365182034): update + enable when rest to unlock feature is implemented - @Ignore("b/365182034") @Test fun verifyIndicatorProgressBarInteraction() { kosmos.testScope.runTest { // Pre-auth conditions - setupTestConfiguration(isInRearDisplayMode = false) - updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = true) + setupTestConfiguration( + DeviceConfig.X_ALIGNED, + rotation = DisplayRotation.ROTATION_0, + isInRearDisplayMode = false + ) + kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( + AuthenticationReason.NotRunning + ) + kosmos.sideFpsProgressBarViewModel.setVisible(false) + + // Show primary bouncer + updatePrimaryBouncer( + isShowing = true, + isAnimatingAway = false, + fpsDetectionRunning = true, + isUnlockingWithFpAllowed = true + ) runCurrent() val inOrder = inOrder(kosmos.windowManager) + // Verify indicator shown inOrder.verify(kosmos.windowManager).addView(any(), any()) // Set progress bar visible - // updateSfpsIndicatorRequests( - // kosmos, mContext, primaryBouncerRequest = true, progressBarShowing = - // true - // ) + kosmos.sideFpsProgressBarViewModel.setVisible(true) + runCurrent() // Verify indicator hidden inOrder.verify(kosmos.windowManager).removeView(any()) // Set progress bar invisible - // updateSfpsIndicatorRequests( - // kosmos, mContext, primaryBouncerRequest = true, progressBarShowing = - // false - // ) + kosmos.sideFpsProgressBarViewModel.setVisible(false) + runCurrent() // Verify indicator shown @@ -184,18 +315,78 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() { } } - private suspend fun TestScope.setupTestConfiguration(isInRearDisplayMode: Boolean) { + private fun updatePrimaryBouncer( + isShowing: Boolean, + isAnimatingAway: Boolean, + fpsDetectionRunning: Boolean, + isUnlockingWithFpAllowed: Boolean, + ) { + kosmos.keyguardBouncerRepository.setPrimaryShow(isShowing) + kosmos.keyguardBouncerRepository.setPrimaryStartingToHide(false) + val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null + kosmos.keyguardBouncerRepository.setPrimaryStartDisappearAnimation( + primaryStartDisappearAnimation + ) + + whenever(kosmos.keyguardUpdateMonitor.isFingerprintDetectionRunning) + .thenReturn(fpsDetectionRunning) + whenever(kosmos.keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed) + .thenReturn(isUnlockingWithFpAllowed) + mContext.orCreateTestableResources.addOverride( + R.bool.config_show_sidefps_hint_on_bouncer, + true + ) + } + + private suspend fun TestScope.setupTestConfiguration( + deviceConfig: DeviceConfig, + rotation: DisplayRotation = DisplayRotation.ROTATION_0, + isInRearDisplayMode: Boolean, + ) { + this@SideFpsOverlayViewBinderTest.deviceConfig = deviceConfig + + when (deviceConfig) { + DeviceConfig.X_ALIGNED -> { + displayWidth = 3000 + displayHeight = 1500 + boundsWidth = 200 + boundsHeight = 100 + sensorLocation = SensorLocationInternal("", 2500, 0, boundsWidth / 2) + } + DeviceConfig.Y_ALIGNED -> { + displayWidth = 2500 + displayHeight = 2000 + boundsWidth = 100 + boundsHeight = 200 + sensorLocation = SensorLocationInternal("", displayWidth, 300, boundsHeight / 2) + } + } + + whenever(kosmos.windowManager.maximumWindowMetrics) + .thenReturn( + WindowMetrics( + Rect(0, 0, displayWidth, displayHeight), + mock(WindowInsets::class.java), + ) + ) + + contextDisplayInfo.uniqueId = DISPLAY_ID + kosmos.fingerprintPropertyRepository.setProperties( sensorId = 1, strength = SensorStrength.STRONG, sensorType = FingerprintSensorType.POWER_BUTTON, - sensorLocations = emptyMap() + sensorLocations = mapOf(DISPLAY_ID to sensorLocation) ) kosmos.displayStateRepository.setIsInRearDisplayMode(isInRearDisplayMode) - kosmos.displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_0) + kosmos.displayStateRepository.setCurrentRotation(rotation) kosmos.displayRepository.emitDisplayChangeEvent(0) kosmos.sideFpsOverlayViewBinder.start() runCurrent() } + + companion object { + private const val DISPLAY_ID = "displayId" + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt index 27b1371deb12..0db7b62b8ef1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt @@ -30,19 +30,23 @@ import android.view.windowManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.airbnb.lottie.model.KeyPath +import com.android.keyguard.keyguardUpdateMonitor import com.android.settingslib.Utils import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider +import com.android.systemui.biometrics.data.repository.biometricStatusRepository import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository import com.android.systemui.biometrics.domain.interactor.displayStateInteractor +import com.android.systemui.biometrics.shared.model.AuthenticationReason import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.LottieCallback import com.android.systemui.biometrics.shared.model.SensorStrength -import com.android.systemui.biometrics.updateSfpsIndicatorRequests +import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository import com.android.systemui.coroutines.collectLastValue import com.android.systemui.display.data.repository.displayRepository import com.android.systemui.display.data.repository.displayStateRepository +import com.android.systemui.keyguard.ui.viewmodel.sideFpsProgressBarViewModel import com.android.systemui.kosmos.testScope import com.android.systemui.res.R import com.android.systemui.testKosmos @@ -280,7 +284,17 @@ class SideFpsOverlayViewModelTest : SysuiTestCase() { kosmos.testScope.runTest { val lottieCallbacks by collectLastValue(kosmos.sideFpsOverlayViewModel.lottieCallbacks) - updateSfpsIndicatorRequests(kosmos, mContext, primaryBouncerRequest = true) + kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( + AuthenticationReason.NotRunning + ) + kosmos.sideFpsProgressBarViewModel.setVisible(false) + + updatePrimaryBouncer( + isShowing = true, + isAnimatingAway = false, + fpsDetectionRunning = true, + isUnlockingWithFpAllowed = true + ) runCurrent() assertThat(lottieCallbacks) @@ -298,7 +312,17 @@ class SideFpsOverlayViewModelTest : SysuiTestCase() { val lottieCallbacks by collectLastValue(kosmos.sideFpsOverlayViewModel.lottieCallbacks) setDarkMode(true) - updateSfpsIndicatorRequests(kosmos, mContext, biometricPromptRequest = true) + kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( + AuthenticationReason.BiometricPromptAuthentication + ) + kosmos.sideFpsProgressBarViewModel.setVisible(false) + + updatePrimaryBouncer( + isShowing = false, + isAnimatingAway = false, + fpsDetectionRunning = true, + isUnlockingWithFpAllowed = true + ) runCurrent() assertThat(lottieCallbacks) @@ -314,7 +338,17 @@ class SideFpsOverlayViewModelTest : SysuiTestCase() { val lottieCallbacks by collectLastValue(kosmos.sideFpsOverlayViewModel.lottieCallbacks) setDarkMode(false) - updateSfpsIndicatorRequests(kosmos, mContext, biometricPromptRequest = true) + kosmos.biometricStatusRepository.setFingerprintAuthenticationReason( + AuthenticationReason.BiometricPromptAuthentication + ) + kosmos.sideFpsProgressBarViewModel.setVisible(false) + + updatePrimaryBouncer( + isShowing = false, + isAnimatingAway = false, + fpsDetectionRunning = true, + isUnlockingWithFpAllowed = true + ) runCurrent() assertThat(lottieCallbacks) @@ -337,6 +371,29 @@ class SideFpsOverlayViewModelTest : SysuiTestCase() { mContext.resources.configuration.uiMode = uiMode } + private fun updatePrimaryBouncer( + isShowing: Boolean, + isAnimatingAway: Boolean, + fpsDetectionRunning: Boolean, + isUnlockingWithFpAllowed: Boolean, + ) { + kosmos.keyguardBouncerRepository.setPrimaryShow(isShowing) + kosmos.keyguardBouncerRepository.setPrimaryStartingToHide(false) + val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null + kosmos.keyguardBouncerRepository.setPrimaryStartDisappearAnimation( + primaryStartDisappearAnimation + ) + + whenever(kosmos.keyguardUpdateMonitor.isFingerprintDetectionRunning) + .thenReturn(fpsDetectionRunning) + whenever(kosmos.keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed) + .thenReturn(isUnlockingWithFpAllowed) + mContext.orCreateTestableResources.addOverride( + R.bool.config_show_sidefps_hint_on_bouncer, + true + ) + } + private suspend fun TestScope.setupTestConfiguration( deviceConfig: DeviceConfig, rotation: DisplayRotation = DisplayRotation.ROTATION_0, 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 492543f215b7..af3ddfca14b6 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 @@ class PasswordBouncerViewModelTest : SysuiTestCase() { .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 @@ class PasswordBouncerViewModelTest : SysuiTestCase() { 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 @@ class PasswordBouncerViewModelTest : SysuiTestCase() { 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 @@ class PasswordBouncerViewModelTest : SysuiTestCase() { subtypes = List(auxiliarySubtypes + nonAuxiliarySubtypes) { InputMethodModel.Subtype(subtypeId = it, isAuxiliary = it < auxiliarySubtypes) - } + }, ) } @@ -383,9 +415,6 @@ class PasswordBouncerViewModelTest : SysuiTestCase() { 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/communal/domain/interactor/CommunalSceneTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractorTest.kt index 2ba4bf930f3f..e25c1a71a5a6 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractorTest.kt @@ -34,8 +34,6 @@ import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository import com.android.systemui.keyguard.data.repository.realKeyguardTransitionRepository -import com.android.systemui.keyguard.shared.model.DozeStateModel -import com.android.systemui.keyguard.shared.model.DozeTransitionModel import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB @@ -50,8 +48,6 @@ import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING import com.android.systemui.keyguard.shared.model.TransitionState.STARTED import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testScope -import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest -import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlin.time.Duration.Companion.seconds @@ -220,15 +216,11 @@ class CommunalSceneTransitionInteractorTest : SysuiTestCase() { @Test fun transition_from_hub_end_in_dream() = testScope.runTest { - // Device is dreaming and not dozing. - kosmos.powerInteractor.setAwakeForTest() - kosmos.fakeKeyguardRepository.setDozeTransitionModel( - DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) - ) + // Device is dreaming and occluded. kosmos.fakeKeyguardRepository.setKeyguardOccluded(true) kosmos.fakeKeyguardRepository.setDreaming(true) kosmos.fakeKeyguardRepository.setDreamingWithOverlay(true) - advanceTimeBy(600L) + runCurrent() sceneTransitions.value = hubToBlank @@ -663,7 +655,7 @@ class CommunalSceneTransitionInteractorTest : SysuiTestCase() { from = LOCKSCREEN, to = OCCLUDED, animator = null, - modeOnCanceled = TransitionModeOnCanceled.RESET + modeOnCanceled = TransitionModeOnCanceled.RESET, ) ) @@ -750,7 +742,7 @@ class CommunalSceneTransitionInteractorTest : SysuiTestCase() { from = LOCKSCREEN, to = OCCLUDED, animator = null, - modeOnCanceled = TransitionModeOnCanceled.RESET + modeOnCanceled = TransitionModeOnCanceled.RESET, ) ) @@ -852,8 +844,8 @@ class CommunalSceneTransitionInteractorTest : SysuiTestCase() { to = ALTERNATE_BOUNCER, animator = null, ownerName = "external", - modeOnCanceled = TransitionModeOnCanceled.RESET - ), + modeOnCanceled = TransitionModeOnCanceled.RESET, + ) ) val allSteps by collectValues(keyguardTransitionRepository.transitions) 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 b3ffc7159f7c..d6734e85ed77 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 @@ package com.android.systemui.communal.domain.interactor 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.KeyguardState 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.Test 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 @@ class WidgetTrampolineInteractorTest : SysuiTestCase() { } @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 @@ class WidgetTrampolineInteractorTest : SysuiTestCase() { ownerName = "test", ), ), - testScope + testScope, ) runCurrent() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartableTest.kt index 9da68853a5aa..52ed23122fde 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartableTest.kt @@ -19,11 +19,13 @@ package com.android.systemui.inputdevice.tutorial import android.content.Context import android.content.Intent import android.os.UserHandle +import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.broadcastDispatcher import com.android.systemui.inputdevice.tutorial.ui.TutorialNotificationCoordinator +import com.android.systemui.shared.Flags import com.android.systemui.testKosmos import org.junit.Test import org.junit.runner.RunWith @@ -43,16 +45,17 @@ class KeyboardTouchpadTutorialCoreStartableTest : SysuiTestCase() { KeyboardTouchpadTutorialCoreStartable( { mock<TutorialNotificationCoordinator>() }, broadcastDispatcher, - context + context, ) @Test + @EnableFlags(Flags.FLAG_NEW_TOUCHPAD_GESTURES_TUTORIAL) fun registersBroadcastReceiverStartingActivityAsSystemUser() { underTest.start() broadcastDispatcher.sendIntentToMatchingReceiversOnly( context, - Intent("com.android.systemui.action.KEYBOARD_TOUCHPAD_TUTORIAL") + Intent("com.android.systemui.action.KEYBOARD_TOUCHPAD_TUTORIAL"), ) verify(context).startActivityAsUser(any(), eq(UserHandle.SYSTEM)) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt index bd6cffff6162..93754fd7e778 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.doze.DozeMachine import com.android.systemui.doze.DozeTransitionCallback import com.android.systemui.doze.DozeTransitionListener import com.android.systemui.dreams.DreamOverlayCallbackController +import com.android.systemui.flags.DisableSceneContainer import com.android.systemui.keyguard.shared.model.BiometricUnlockMode import com.android.systemui.keyguard.shared.model.BiometricUnlockSource import com.android.systemui.keyguard.shared.model.DozeStateModel @@ -288,6 +289,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() { } @Test + @DisableSceneContainer fun dozeAmount() = testScope.runTest { val values = mutableListOf<Float>() 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 fac931273ac7..ff0a4a16fe2a 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 @@ -26,8 +26,10 @@ import com.android.compose.animation.scene.ObservableTransitionState import com.android.systemui.Flags.FLAG_COMMUNAL_HUB import com.android.systemui.Flags.FLAG_COMMUNAL_SCENE_KTF_REFACTOR import com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR +import com.android.systemui.Flags.FLAG_SCENE_CONTAINER import com.android.systemui.SysuiTestCase import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository +import com.android.systemui.communal.data.repository.communalSceneRepository import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository import com.android.systemui.communal.domain.interactor.setCommunalAvailable import com.android.systemui.communal.shared.model.CommunalScenes @@ -50,10 +52,12 @@ import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.se import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos +import com.google.common.truth.Truth import junit.framework.Assert.assertEquals import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before @@ -219,6 +223,28 @@ class FromDozingTransitionInteractorTest(flags: FlagsParameterization?) : SysuiT } @Test + @DisableFlags(FLAG_KEYGUARD_WM_STATE_REFACTOR, FLAG_SCENE_CONTAINER) + @EnableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR) + fun testTransitionToGlanceableHub_onWakeup_ifAvailable() = + testScope.runTest { + // Hub is available. + whenever(kosmos.dreamManager.canStartDreaming(anyBoolean())).thenReturn(true) + kosmos.setCommunalAvailable(true) + runCurrent() + + // Device turns on. + powerInteractor.setAwakeForTest() + advanceTimeBy(50L) + runCurrent() + + // We transition to the hub when waking up. + Truth.assertThat(kosmos.communalSceneRepository.currentScene.value) + .isEqualTo(CommunalScenes.Communal) + // No transitions are directly started by this interactor. + assertThat(transitionRepository).noTransitionsStarted() + } + + @Test @EnableFlags(FLAG_KEYGUARD_WM_STATE_REFACTOR) fun testTransitionToOccluded_onWakeup_whenOccludingActivityOnTop() = testScope.runTest { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt index 638c957c9fa7..a08fbbf75805 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt @@ -16,12 +16,19 @@ package com.android.systemui.keyguard.domain.interactor +import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags -import androidx.test.ext.junit.runners.AndroidJUnit4 +import android.platform.test.flag.junit.FlagsParameterization +import android.service.dream.dreamManager import androidx.test.filters.SmallTest import com.android.systemui.Flags +import com.android.systemui.Flags.FLAG_COMMUNAL_SCENE_KTF_REFACTOR import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository +import com.android.systemui.communal.data.repository.communalSceneRepository +import com.android.systemui.communal.domain.interactor.setCommunalAvailable +import com.android.systemui.communal.shared.model.CommunalScenes +import com.android.systemui.flags.andSceneContainer import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository @@ -36,6 +43,7 @@ import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInterac import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest @@ -43,26 +51,52 @@ import org.junit.Before import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mockito.anyBoolean import org.mockito.Mockito.reset import org.mockito.Mockito.spy +import org.mockito.kotlin.whenever +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(AndroidJUnit4::class) -class FromDreamingTransitionInteractorTest : SysuiTestCase() { +@RunWith(ParameterizedAndroidJunit4::class) +class FromDreamingTransitionInteractorTest(flags: FlagsParameterization?) : SysuiTestCase() { + companion object { + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return FlagsParameterization.allCombinationsOf(FLAG_COMMUNAL_SCENE_KTF_REFACTOR) + .andSceneContainer() + } + } + + init { + mSetFlagsRule.setFlagsParameterization(flags!!) + } + private val kosmos = testKosmos().apply { this.fakeKeyguardTransitionRepository = spy(FakeKeyguardTransitionRepository()) } private val testScope = kosmos.testScope - private val underTest = kosmos.fromDreamingTransitionInteractor + private val underTest by lazy { kosmos.fromDreamingTransitionInteractor } private val powerInteractor = kosmos.powerInteractor private val transitionRepository = kosmos.fakeKeyguardTransitionRepository @Before fun setup() { + runBlocking { + transitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.DREAMING, + testScope, + ) + reset(transitionRepository) + kosmos.setCommunalAvailable(true) + } underTest.start() } @@ -86,10 +120,7 @@ class FromDreamingTransitionInteractorTest : SysuiTestCase() { runCurrent() assertThat(transitionRepository) - .startedTransition( - from = KeyguardState.DREAMING, - to = KeyguardState.OCCLUDED, - ) + .startedTransition(from = KeyguardState.DREAMING, to = KeyguardState.OCCLUDED) } @Test @@ -126,7 +157,7 @@ class FromDreamingTransitionInteractorTest : SysuiTestCase() { transitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, to = KeyguardState.DREAMING, - testScope + testScope, ) kosmos.fakeKeyguardRepository.setBiometricUnlockState(BiometricUnlockMode.NONE) @@ -139,10 +170,7 @@ class FromDreamingTransitionInteractorTest : SysuiTestCase() { advanceTimeBy(60L) assertThat(transitionRepository) - .startedTransition( - from = KeyguardState.DREAMING, - to = KeyguardState.LOCKSCREEN, - ) + .startedTransition(from = KeyguardState.DREAMING, to = KeyguardState.LOCKSCREEN) } @Test @@ -164,4 +192,25 @@ class FromDreamingTransitionInteractorTest : SysuiTestCase() { to = KeyguardState.ALTERNATE_BOUNCER, ) } + + @Test + @EnableFlags(FLAG_COMMUNAL_SCENE_KTF_REFACTOR) + @DisableFlags(Flags.FLAG_SCENE_CONTAINER) + fun testTransitionToGlanceableHubOnWake() = + testScope.runTest { + whenever(kosmos.dreamManager.canStartDreaming(anyBoolean())).thenReturn(true) + kosmos.setCommunalAvailable(true) + runCurrent() + + // Device wakes up. + powerInteractor.setAwakeForTest() + advanceTimeBy(150L) + runCurrent() + + // We transition to the hub when waking up. + assertThat(kosmos.communalSceneRepository.currentScene.value) + .isEqualTo(CommunalScenes.Communal) + // No transitions are directly started by this interactor. + assertThat(transitionRepository).noTransitionsStarted() + } } 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 41cc953cd1c2..ba689179c33d 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 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() { powerInteractor = kosmos.powerInteractor, alternateBouncerInteractor = kosmos.alternateBouncerInteractor, shadeInteractor = { kosmos.shadeInteractor }, + keyguardInteractor = { kosmos.keyguardInteractor }, ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt index b843fd508616..3fb3eead6469 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt @@ -29,15 +29,21 @@ import com.android.systemui.common.ui.data.repository.fakeConfigurationRepositor import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.flags.EnableSceneContainer -import com.android.systemui.keyguard.data.repository.fakeCommandQueue import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.data.repository.keyguardRepository import com.android.systemui.keyguard.shared.model.CameraLaunchType import com.android.systemui.keyguard.shared.model.DozeStateModel import com.android.systemui.keyguard.shared.model.DozeTransitionModel import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.KeyguardState.AOD +import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING +import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED +import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING +import com.android.systemui.keyguard.shared.model.TransitionState.STARTED import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testScope import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest @@ -67,12 +73,11 @@ class KeyguardInteractorTest : SysuiTestCase() { private val testScope = kosmos.testScope private val repository by lazy { kosmos.fakeKeyguardRepository } private val sceneInteractor by lazy { kosmos.sceneInteractor } - private val fromGoneTransitionInteractor by lazy { kosmos.fromGoneTransitionInteractor } - private val commandQueue by lazy { kosmos.fakeCommandQueue } private val configRepository by lazy { kosmos.fakeConfigurationRepository } private val bouncerRepository by lazy { kosmos.keyguardBouncerRepository } private val shadeRepository by lazy { kosmos.shadeRepository } private val powerInteractor by lazy { kosmos.powerInteractor } + private val keyguardRepository by lazy { kosmos.keyguardRepository } private val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository } private val transitionState: MutableStateFlow<ObservableTransitionState> = @@ -178,8 +183,8 @@ class KeyguardInteractorTest : SysuiTestCase() { assertThat(dismissAlpha).isEqualTo(1f) keyguardTransitionRepository.sendTransitionSteps( - from = KeyguardState.AOD, - to = KeyguardState.LOCKSCREEN, + from = AOD, + to = LOCKSCREEN, testScope, ) @@ -204,8 +209,8 @@ class KeyguardInteractorTest : SysuiTestCase() { assertThat(dismissAlpha.size).isEqualTo(1) keyguardTransitionRepository.sendTransitionSteps( - from = KeyguardState.AOD, - to = KeyguardState.LOCKSCREEN, + from = AOD, + to = LOCKSCREEN, testScope, ) @@ -266,13 +271,13 @@ class KeyguardInteractorTest : SysuiTestCase() { keyguardTransitionRepository.sendTransitionSteps( listOf( TransitionStep( - from = KeyguardState.AOD, + from = AOD, to = KeyguardState.GONE, value = 0f, - transitionState = TransitionState.STARTED, + transitionState = STARTED, ), TransitionStep( - from = KeyguardState.AOD, + from = AOD, to = KeyguardState.GONE, value = 0.1f, transitionState = TransitionState.RUNNING, @@ -302,7 +307,7 @@ class KeyguardInteractorTest : SysuiTestCase() { shadeRepository.setLegacyShadeExpansion(0f) keyguardTransitionRepository.sendTransitionSteps( - from = KeyguardState.AOD, + from = AOD, to = KeyguardState.GONE, testScope, ) @@ -324,8 +329,8 @@ class KeyguardInteractorTest : SysuiTestCase() { shadeRepository.setLegacyShadeExpansion(0f) keyguardTransitionRepository.sendTransitionSteps( - from = KeyguardState.AOD, - to = KeyguardState.LOCKSCREEN, + from = AOD, + to = LOCKSCREEN, testScope, ) @@ -346,8 +351,8 @@ class KeyguardInteractorTest : SysuiTestCase() { shadeRepository.setLegacyShadeExpansion(1f) keyguardTransitionRepository.sendTransitionSteps( - from = KeyguardState.AOD, - to = KeyguardState.LOCKSCREEN, + from = AOD, + to = LOCKSCREEN, testScope, ) @@ -370,13 +375,13 @@ class KeyguardInteractorTest : SysuiTestCase() { keyguardTransitionRepository.sendTransitionSteps( listOf( TransitionStep( - from = KeyguardState.AOD, + from = AOD, to = KeyguardState.GONE, value = 0f, - transitionState = TransitionState.STARTED, + transitionState = STARTED, ), TransitionStep( - from = KeyguardState.AOD, + from = AOD, to = KeyguardState.GONE, value = 0.1f, transitionState = TransitionState.RUNNING, @@ -468,4 +473,63 @@ class KeyguardInteractorTest : SysuiTestCase() { runCurrent() assertThat(isAnimate).isFalse() } + + @Test + @EnableSceneContainer + fun dozeAmount_updatedByAodTransitionWhenAodEnabled() = + testScope.runTest { + val dozeAmount by collectLastValue(underTest.dozeAmount) + + keyguardRepository.setAodAvailable(true) + + sendTransitionStep(TransitionStep(to = AOD, value = 0f, transitionState = STARTED)) + assertThat(dozeAmount).isEqualTo(0f) + + sendTransitionStep(TransitionStep(to = AOD, value = 0.5f, transitionState = RUNNING)) + assertThat(dozeAmount).isEqualTo(0.5f) + + sendTransitionStep(TransitionStep(to = AOD, value = 1f, transitionState = FINISHED)) + assertThat(dozeAmount).isEqualTo(1f) + + sendTransitionStep(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED)) + assertThat(dozeAmount).isEqualTo(1f) + + sendTransitionStep(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING)) + assertThat(dozeAmount).isEqualTo(0.5f) + + sendTransitionStep(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED)) + assertThat(dozeAmount).isEqualTo(0f) + } + + @Test + @EnableSceneContainer + fun dozeAmount_updatedByDozeTransitionWhenAodDisabled() = + testScope.runTest { + val dozeAmount by collectLastValue(underTest.dozeAmount) + + keyguardRepository.setAodAvailable(false) + + sendTransitionStep(TransitionStep(to = DOZING, value = 0f, transitionState = STARTED)) + assertThat(dozeAmount).isEqualTo(0f) + + sendTransitionStep(TransitionStep(to = DOZING, value = 0.5f, transitionState = RUNNING)) + assertThat(dozeAmount).isEqualTo(0.5f) + + sendTransitionStep(TransitionStep(to = DOZING, value = 1f, transitionState = FINISHED)) + assertThat(dozeAmount).isEqualTo(1f) + + sendTransitionStep(TransitionStep(DOZING, LOCKSCREEN, 0f, STARTED)) + assertThat(dozeAmount).isEqualTo(1f) + + sendTransitionStep(TransitionStep(DOZING, LOCKSCREEN, 0.5f, RUNNING)) + assertThat(dozeAmount).isEqualTo(0.5f) + + sendTransitionStep(TransitionStep(DOZING, LOCKSCREEN, 1f, FINISHED)) + assertThat(dozeAmount).isEqualTo(0f) + } + + private suspend fun sendTransitionStep(step: TransitionStep) { + keyguardTransitionRepository.sendTransitionStep(step) + testScope.runCurrent() + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractorTest.kt new file mode 100644 index 000000000000..2558d583b001 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractorTest.kt @@ -0,0 +1,139 @@ +/* + * 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.platform.test.annotations.EnableFlags +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.internal.policy.IKeyguardDismissCallback +import com.android.internal.policy.IKeyguardStateCallback +import com.android.keyguard.trustManager +import com.android.systemui.Flags +import com.android.systemui.SysuiTestCase +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.dismissCallbackRegistry +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.kosmos.testScope +import com.android.systemui.statusbar.domain.interactor.keyguardStateCallbackInteractor +import com.android.systemui.testKosmos +import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.util.time.fakeSystemClock +import kotlin.test.Test +import kotlinx.coroutines.test.currentTime +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mockito +import org.mockito.Mockito.anyBoolean +import org.mockito.Mockito.anyInt +import org.mockito.kotlin.atLeast +import org.mockito.kotlin.atLeastOnce +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify + +@SmallTest +@RunWith(AndroidJUnit4::class) +class KeyguardStateCallbackInteractorTest : SysuiTestCase() { + + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + + private lateinit var underTest: KeyguardStateCallbackInteractor + private lateinit var callback: IKeyguardStateCallback + private lateinit var systemClock: FakeSystemClock + + @Before + fun setUp() { + systemClock = kosmos.fakeSystemClock + systemClock.setCurrentTimeMillis(testScope.currentTime) + + underTest = kosmos.keyguardStateCallbackInteractor + underTest.start() + + callback = mock<IKeyguardStateCallback>() + } + + @Test + fun test_addCallback_passesInitialValues() = + testScope.runTest { + underTest.addCallback(callback) + + verify(callback).onShowingStateChanged(anyBoolean(), anyInt()) + verify(callback).onInputRestrictedStateChanged(anyBoolean()) + verify(callback).onTrustedChanged(anyBoolean()) + verify(callback).onSimSecureStateChanged(anyBoolean()) + } + + @Test + @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) + fun test_lockscreenVisibility_notifyDismissSucceeded_ifNotVisible() = + testScope.runTest { + underTest.addCallback(callback) + + val dismissCallback = mock<IKeyguardDismissCallback>() + kosmos.dismissCallbackRegistry.addCallback(dismissCallback) + runCurrent() + + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.GONE, + testScope = testScope, + ) + + systemClock.advanceTime(1) // Required for DismissCallbackRegistry's bgExecutor + verify(dismissCallback).onDismissSucceeded() + + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.GONE, + to = KeyguardState.LOCKSCREEN, + testScope = testScope, + ) + + Mockito.verifyNoMoreInteractions(dismissCallback) + } + + @Test + @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) + fun test_lockscreenVisibility_reportsKeyguardShowingChanged() = + testScope.runTest { + underTest.addCallback(callback) + + Mockito.clearInvocations(callback) + Mockito.clearInvocations(kosmos.trustManager) + + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.GONE, + testScope = testScope, + ) + runCurrent() + + verify(callback, atLeastOnce()).onShowingStateChanged(eq(false), anyInt()) + verify(kosmos.trustManager, atLeastOnce()).reportKeyguardShowingChanged() + + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.GONE, + to = KeyguardState.LOCKSCREEN, + testScope = testScope, + ) + + verify(callback, atLeastOnce()).onShowingStateChanged(eq(true), anyInt()) + verify(kosmos.trustManager, atLeast(2)).reportKeyguardShowingChanged() + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt index 77106aec2fb4..a617484d7d94 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt @@ -1465,10 +1465,8 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest // WHEN the keyguard is occluded and device wakes up and is no longer dreaming keyguardRepository.setDreaming(false) - testScheduler.advanceTimeBy(150) // The dreaming signal is debounced. - runCurrent() keyguardRepository.setKeyguardOccluded(true) - powerInteractor.setAwakeForTest() + testScheduler.advanceTimeBy(150) // The dreaming and occluded signals are debounced. runCurrent() // THEN a transition to OCCLUDED should occur @@ -2059,12 +2057,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest fun glanceableHubToOccluded_communalKtfRefactor() = testScope.runTest { // GIVEN device is not dreaming - powerInteractor.setAwakeForTest() keyguardRepository.setDreaming(false) - keyguardRepository.setDozeTransitionModel( - DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) - ) - advanceTimeBy(600.milliseconds) // GIVEN a prior transition has run to GLANCEABLE_HUB communalSceneInteractor.changeScene(CommunalScenes.Communal, "test") @@ -2073,6 +2066,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest // WHEN the keyguard is occluded keyguardRepository.setKeyguardOccluded(true) + advanceTimeBy(200.milliseconds) runCurrent() assertThat(transitionRepository) @@ -2218,6 +2212,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest advanceTimeBy(10.milliseconds) keyguardRepository.setKeyguardOccluded(true) advanceTimeBy(200.milliseconds) + runCurrent() assertThat(transitionRepository) .startedTransition( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt index f31eb7f50405..309e3a8be14a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt @@ -27,11 +27,18 @@ import com.android.systemui.doze.util.BurnInHelperWrapper import com.android.systemui.flags.andSceneContainer import com.android.systemui.keyguard.data.repository.FakeCommandQueue import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING import com.android.systemui.keyguard.shared.model.StatusBarState +import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED +import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING +import com.android.systemui.keyguard.shared.model.TransitionState.STARTED +import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testScope import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest import com.android.systemui.power.domain.interactor.PowerInteractorFactory +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.shade.data.repository.fakeShadeRepository import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.domain.interactor.shadeLockscreenInteractor @@ -62,6 +69,7 @@ class UdfpsKeyguardInteractorTest(flags: FlagsParameterization) : SysuiTestCase( val kosmos = testKosmos() val testScope = kosmos.testScope val keyguardRepository = kosmos.fakeKeyguardRepository + val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository } val shadeRepository = kosmos.fakeShadeRepository val shadeTestUtil by lazy { kosmos.shadeTestUtil } @@ -132,8 +140,15 @@ class UdfpsKeyguardInteractorTest(flags: FlagsParameterization) : SysuiTestCase( assertThat(burnInOffsets?.x).isEqualTo(0) // WHEN we're in the middle of the doze amount change - keyguardRepository.setDozeAmount(.50f) - runCurrent() + if (SceneContainerFlag.isEnabled) { + sendTransitionSteps( + TransitionStep(to = DOZING, value = 0.0f, transitionState = STARTED), + TransitionStep(to = DOZING, value = 0.5f, transitionState = RUNNING), + ) + } else { + keyguardRepository.setDozeAmount(.50f) + runCurrent() + } // THEN burn in is updated (between 0 and the full offset) assertThat(burnInOffsets?.progress).isGreaterThan(0f) @@ -144,8 +159,14 @@ class UdfpsKeyguardInteractorTest(flags: FlagsParameterization) : SysuiTestCase( assertThat(burnInOffsets?.x).isLessThan(burnInXOffset) // WHEN we're fully dozing - keyguardRepository.setDozeAmount(1f) - runCurrent() + if (SceneContainerFlag.isEnabled) { + sendTransitionSteps( + TransitionStep(to = DOZING, value = 1.0f, transitionState = FINISHED) + ) + } else { + keyguardRepository.setDozeAmount(1f) + runCurrent() + } // THEN burn in offsets are updated to final current values (for the given time) assertThat(burnInOffsets?.progress).isEqualTo(burnInProgress) @@ -217,7 +238,9 @@ class UdfpsKeyguardInteractorTest(flags: FlagsParameterization) : SysuiTestCase( } private fun setAwake() { - keyguardRepository.setDozeAmount(0f) + if (!SceneContainerFlag.isEnabled) { + keyguardRepository.setDozeAmount(0f) + } keyguardRepository.dozeTimeTick() bouncerRepository.setAlternateVisible(false) @@ -225,4 +248,11 @@ class UdfpsKeyguardInteractorTest(flags: FlagsParameterization) : SysuiTestCase( bouncerRepository.setPrimaryShow(false) powerInteractor.setAwakeForTest() } + + private suspend fun sendTransitionSteps(vararg steps: TransitionStep) { + steps.forEach { step -> + keyguardTransitionRepository.sendTransitionStep(step) + testScope.runCurrent() + } + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt index ff6ea3a14ff2..7f0937059494 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt @@ -91,12 +91,13 @@ class AodBurnInViewModelTest : SysuiTestCase() { kosmos.fakeKeyguardClockRepository.setCurrentClock(clockController) underTest = kosmos.aodBurnInViewModel + underTest.updateBurnInParams(burnInParameters) } @Test fun movement_initializedToDefaultValues() = testScope.runTest { - val movement by collectLastValue(underTest.movement(burnInParameters)) + val movement by collectLastValue(underTest.movement) assertThat(movement?.translationY).isEqualTo(0) assertThat(movement?.translationX).isEqualTo(0) assertThat(movement?.scale).isEqualTo(1f) @@ -105,7 +106,7 @@ class AodBurnInViewModelTest : SysuiTestCase() { @Test fun translationAndScale_whenNotDozing() = testScope.runTest { - val movement by collectLastValue(underTest.movement(burnInParameters)) + val movement by collectLastValue(underTest.movement) // Set to not dozing (on lockscreen) keyguardTransitionRepository.sendTransitionStep( @@ -128,10 +129,57 @@ class AodBurnInViewModelTest : SysuiTestCase() { } @Test + fun translationX_aodToLockscreen() = + testScope.runTest { + underTest.updateBurnInParams(burnInParameters.copy(translationX = { -100f })) + val movement by collectLastValue(underTest.movement) + assertThat(movement?.translationX).isEqualTo(0) + + // Trigger a change to the burn-in model + burnInFlow.value = BurnInModel(translationX = 20, translationY = 30, scale = 0.5f) + + // Set to not dozing (on lockscreen) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.AOD, + to = KeyguardState.LOCKSCREEN, + value = 0f, + transitionState = TransitionState.STARTED, + ), + validateStep = false, + ) + // Set to not dozing (on lockscreen) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.AOD, + to = KeyguardState.LOCKSCREEN, + value = 0f, + transitionState = TransitionState.RUNNING, + ), + validateStep = false, + ) + assertThat(movement?.translationX).isEqualTo(-100) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.AOD, + to = KeyguardState.LOCKSCREEN, + value = 1f, + transitionState = TransitionState.FINISHED, + ), + validateStep = false, + ) + + assertThat(movement?.translationX).isEqualTo(0) + assertThat(movement?.translationY).isEqualTo(0) + assertThat(movement?.scale).isEqualTo(1f) + assertThat(movement?.scaleClockOnly).isEqualTo(true) + } + + @Test fun translationAndScale_whenFullyDozing() = testScope.runTest { - burnInParameters = burnInParameters.copy(minViewY = 100) - val movement by collectLastValue(underTest.movement(burnInParameters)) + underTest.updateBurnInParams(burnInParameters.copy(minViewY = 100)) + val movement by collectLastValue(underTest.movement) // Set to dozing (on AOD) keyguardTransitionRepository.sendTransitionStep( @@ -171,8 +219,8 @@ class AodBurnInViewModelTest : SysuiTestCase() { @DisableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) fun translationAndScale_whenFullyDozing_MigrationFlagOff_staysOutOfTopInset() = testScope.runTest { - burnInParameters = burnInParameters.copy(minViewY = 100, topInset = 80) - val movement by collectLastValue(underTest.movement(burnInParameters)) + underTest.updateBurnInParams(burnInParameters.copy(minViewY = 100, topInset = 80)) + val movement by collectLastValue(underTest.movement) // Set to dozing (on AOD) keyguardTransitionRepository.sendTransitionStep( @@ -213,8 +261,8 @@ class AodBurnInViewModelTest : SysuiTestCase() { @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) fun translationAndScale_whenFullyDozing_MigrationFlagOn_staysOutOfTopInset() = testScope.runTest { - burnInParameters = burnInParameters.copy(minViewY = 100, topInset = 80) - val movement by collectLastValue(underTest.movement(burnInParameters)) + underTest.updateBurnInParams(burnInParameters.copy(minViewY = 100, topInset = 80)) + val movement by collectLastValue(underTest.movement) // Set to dozing (on AOD) keyguardTransitionRepository.sendTransitionStep( @@ -256,7 +304,7 @@ class AodBurnInViewModelTest : SysuiTestCase() { testScope.runTest { whenever(clockController.config.useAlternateSmartspaceAODTransition).thenReturn(true) - val movement by collectLastValue(underTest.movement(burnInParameters)) + val movement by collectLastValue(underTest.movement) // Set to dozing (on AOD) keyguardTransitionRepository.sendTransitionStep( @@ -374,7 +422,7 @@ class AodBurnInViewModelTest : SysuiTestCase() { whenever(clockController.config.useAlternateSmartspaceAODTransition) .thenReturn(if (isWeatherClock) true else false) - val movement by collectLastValue(underTest.movement(burnInParameters)) + val movement by collectLastValue(underTest.movement) // Set to dozing (on AOD) keyguardTransitionRepository.sendTransitionStep( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt index 2fd94e2016aa..51865368d91a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt @@ -26,7 +26,6 @@ import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState import com.android.systemui.Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT -import com.android.systemui.Flags.FLAG_NEW_AOD_TRANSITION import com.android.systemui.SysuiTestCase import com.android.systemui.communal.data.repository.communalSceneRepository import com.android.systemui.communal.shared.model.CommunalScenes @@ -47,10 +46,14 @@ import com.android.systemui.scene.data.repository.setSceneTransition import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.shadeTestUtil +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.stack.domain.interactor.notificationsKeyguardInteractor import com.android.systemui.statusbar.phone.dozeParameters import com.android.systemui.statusbar.phone.screenOffAnimationController import com.android.systemui.testKosmos +import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.ui.isAnimating import com.android.systemui.util.ui.stopAnimating @@ -70,11 +73,7 @@ import platform.test.runner.parameterized.Parameters @SmallTest @RunWith(ParameterizedAndroidJunit4::class) -@EnableFlags( - FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT, - FLAG_NEW_AOD_TRANSITION, - FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR -) +@EnableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT, FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR) class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope @@ -110,6 +109,20 @@ class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase() @Before fun setUp() { kosmos.sceneContainerRepository.setTransitionState(transitionState) + + // Add sample notif so that the notif shelf has something to display + kosmos.activeNotificationListRepository.activeNotifications.value = + ActiveNotificationsStore.Builder() + .apply { + addIndividualNotif( + activeNotificationModel( + key = "notif", + aodIcon = mock(), + groupKey = "testGroup", + ) + ) + } + .build() } @Test @@ -129,7 +142,7 @@ class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase() from = KeyguardState.LOCKSCREEN, to = KeyguardState.AOD, value = 0f, - transitionState = TransitionState.STARTED + transitionState = TransitionState.STARTED, ), validateStep = false, ) @@ -393,7 +406,7 @@ class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase() flowOf(Scenes.Communal), flowOf(0.5f), false, - emptyFlow() + emptyFlow(), ) keyguardTransitionRepository.sendTransitionSteps( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/OWNERS b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/OWNERS index cd04e82d7816..d3eec977fd53 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/OWNERS +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/OWNERS @@ -1,3 +1,4 @@ set noparent include /packages/SystemUI/src/com/android/systemui/qs/OWNERS +include /packages/SystemUI/TEST_OWNERS diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorTest.kt index e58cf152be93..79a303db079a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorTest.kt @@ -85,12 +85,12 @@ class IconTilesInteractorTest : SysuiTestCase() { runCurrent() // Assert that the tile is removed from the large tiles after resizing - underTest.resize(largeTile) + underTest.resize(largeTile, toIcon = true) runCurrent() assertThat(latest).doesNotContain(largeTile) // Assert that the tile is added to the large tiles after resizing - underTest.resize(largeTile) + underTest.resize(largeTile, toIcon = false) runCurrent() assertThat(latest).contains(largeTile) } @@ -122,7 +122,7 @@ class IconTilesInteractorTest : SysuiTestCase() { val newTile = TileSpec.create("newTile") // Remove the large tile from the current tiles - underTest.resize(newTile) + underTest.resize(newTile, toIcon = false) runCurrent() // Assert that it's still small diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/EditTileListStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/EditTileListStateTest.kt index 484a8ff973c1..3910903af4aa 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/EditTileListStateTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/EditTileListStateTest.kt @@ -24,7 +24,6 @@ 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.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.shared.TileSpec @@ -39,13 +38,6 @@ class EditTileListStateTest : SysuiTestCase() { private val underTest = EditTileListState(TestEditTiles, 4) @Test - fun noDrag_listUnchanged() { - underTest.tiles.forEach { assertThat(it).isNotInstanceOf(SpacerGridCell::class.java) } - assertThat(underTest.tiles.map { (it as TileGridCell).tile.tileSpec }) - .containsExactly(*TestEditTiles.map { it.tile.tileSpec }.toTypedArray()) - } - - @Test fun startDrag_listHasSpacers() { underTest.onStarted(TestEditTiles[0]) @@ -109,16 +101,6 @@ class EditTileListStateTest : SysuiTestCase() { } @Test - fun droppedNewTile_spacersDisappear() { - underTest.onStarted(TestEditTiles[0]) - underTest.onDrop() - - assertThat(underTest.tiles.toStrings()).isEqualTo(listOf("a", "b", "c", "d", "e")) - assertThat(underTest.isMoving(TestEditTiles[0].tile.tileSpec)).isFalse() - assertThat(underTest.dragInProgress).isFalse() - } - - @Test fun movedTileOutOfBounds_tileDisappears() { underTest.onStarted(TestEditTiles[0]) underTest.movedOutOfBounds() 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 index fa72d740b2f0..4acf3ee7878b 100644 --- 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 @@ -27,23 +27,25 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class MutableSelectionStateTest : SysuiTestCase() { - private val underTest = MutableSelectionState() + private val underTest = MutableSelectionState({}, {}) @Test fun selectTile_isCorrectlySelected() { - assertThat(underTest.isSelected(TEST_SPEC)).isFalse() + assertThat(underTest.selection?.tileSpec).isNotEqualTo(TEST_SPEC) - underTest.select(TEST_SPEC) - assertThat(underTest.isSelected(TEST_SPEC)).isTrue() + underTest.select(TEST_SPEC, manual = true) + assertThat(underTest.selection?.tileSpec).isEqualTo(TEST_SPEC) + assertThat(underTest.selection?.manual).isTrue() underTest.unSelect() - assertThat(underTest.isSelected(TEST_SPEC)).isFalse() + assertThat(underTest.selection).isNull() val newSpec = TileSpec.create("newSpec") - underTest.select(TEST_SPEC) - underTest.select(newSpec) - assertThat(underTest.isSelected(TEST_SPEC)).isFalse() - assertThat(underTest.isSelected(newSpec)).isTrue() + underTest.select(TEST_SPEC, manual = true) + underTest.select(newSpec, manual = false) + assertThat(underTest.selection?.tileSpec).isNotEqualTo(TEST_SPEC) + assertThat(underTest.selection?.tileSpec).isEqualTo(newSpec) + assertThat(underTest.selection?.manual).isFalse() } @Test @@ -51,12 +53,12 @@ class MutableSelectionStateTest : SysuiTestCase() { assertThat(underTest.resizingState).isNull() // Resizing starts but no tile is selected - underTest.onResizingDragStart(TileWidths(0, 0, 1)) {} + 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)) {} + underTest.select(TEST_SPEC, manual = true) + underTest.onResizingDragStart(TileWidths(0, 0, 1)) assertThat(underTest.resizingState).isNotNull() } @@ -66,8 +68,8 @@ class MutableSelectionStateTest : SysuiTestCase() { val spec = TileSpec.create("testSpec") // Resizing starts with a selected tile - underTest.select(spec) - underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) {} + underTest.select(spec, manual = true) + underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) assertThat(underTest.resizingState).isNotNull() underTest.onResizingDragEnd() @@ -77,8 +79,8 @@ class MutableSelectionStateTest : SysuiTestCase() { @Test fun unselect_clearsResizingState() { // Resizing starts with a selected tile - underTest.select(TEST_SPEC) - underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) {} + underTest.select(TEST_SPEC, manual = true) + underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) assertThat(underTest.resizingState).isNotNull() underTest.unSelect() @@ -88,8 +90,8 @@ class MutableSelectionStateTest : SysuiTestCase() { @Test fun onResizingDrag_updatesResizingState() { // Resizing starts with a selected tile - underTest.select(TEST_SPEC) - underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) {} + underTest.select(TEST_SPEC, manual = true) + underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) assertThat(underTest.resizingState).isNotNull() underTest.onResizingDrag(5f) @@ -105,11 +107,15 @@ class MutableSelectionStateTest : SysuiTestCase() { @Test fun onResizingDrag_receivesResizeCallback() { var resized = false - val onResize: () -> Unit = { resized = !resized } + val onResize: (TileSpec) -> Unit = { + assertThat(it).isEqualTo(TEST_SPEC) + resized = !resized + } + val underTest = MutableSelectionState(onResize = onResize, {}) // Resizing starts with a selected tile - underTest.select(TEST_SPEC) - underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10), onResize) + underTest.select(TEST_SPEC, true) + underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) assertThat(underTest.resizingState).isNotNull() // Drag under the threshold @@ -125,6 +131,37 @@ class MutableSelectionStateTest : SysuiTestCase() { assertThat(resized).isFalse() } + @Test + fun onResizingEnded_receivesResizeEndCallback() { + var resizeEnded = false + val onResizeEnd: (TileSpec) -> Unit = { resizeEnded = true } + val underTest = MutableSelectionState({}, onResizeEnd = onResizeEnd) + + // Resizing starts with a selected tile + underTest.select(TEST_SPEC, true) + underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) + + underTest.onResizingDragEnd() + assertThat(resizeEnded).isTrue() + } + + @Test + fun onResizingEnded_setsSelectionAutomatically() { + val underTest = MutableSelectionState({}, {}) + + // Resizing starts with a selected tile + underTest.select(TEST_SPEC, manual = true) + underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) + + // Assert the selection was manual + assertThat(underTest.selection?.manual).isTrue() + + underTest.onResizingDragEnd() + + // Assert the selection is no longer manual due to the resizing + assertThat(underTest.selection?.manual).isFalse() + } + companion object { private val TEST_SPEC = TileSpec.create("testSpec") } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt index f72a2e861be5..aefbc6b3b646 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt @@ -35,6 +35,7 @@ import com.android.systemui.jank.interactionJankMonitor import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus @@ -107,6 +108,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest uiEventLogger, { kosmos.interactionJankMonitor }, JavaAdapter(testScope.backgroundScope), + { kosmos.keyguardInteractor }, { kosmos.keyguardTransitionInteractor }, { kosmos.shadeInteractor }, { kosmos.deviceUnlockedInteractor }, @@ -139,6 +141,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest } @Test + @DisableSceneContainer fun testSetDozeAmountInternal_onlySetsOnce() { val listener = mock(StatusBarStateController.StateListener::class.java) underTest.addCallback(listener) @@ -190,6 +193,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest } @Test + @DisableSceneContainer fun testSetDozeAmount_immediatelyChangesDozeAmount_lockscreenTransitionFromAod() { // Put controller in AOD state underTest.setAndInstrumentDozeAmount(null, 1f, false) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt index 425f16ec7da1..add7ac95e8c4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt @@ -44,6 +44,7 @@ import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.shared.model.BurnInModel import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER import com.android.systemui.keyguard.shared.model.KeyguardState.AOD +import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB import com.android.systemui.keyguard.shared.model.KeyguardState.GONE @@ -54,7 +55,6 @@ import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel -import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.keyguard.ui.viewmodel.ViewStateAccessor import com.android.systemui.keyguard.ui.viewmodel.aodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel @@ -69,7 +69,6 @@ import com.android.systemui.shade.mockLargeScreenHeaderHelper import com.android.systemui.shade.shadeTestUtil import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor import com.android.systemui.testKosmos -import com.android.systemui.util.mockito.any import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -154,7 +153,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S fun setUp() { shadeTestUtil.setSplitShade(false) movementFlow = MutableStateFlow(BurnInModel()) - whenever(aodBurnInViewModel.movement(any())).thenReturn(movementFlow) + whenever(aodBurnInViewModel.movement).thenReturn(movementFlow) underTest = kosmos.sharedNotificationContainerViewModel } @@ -363,6 +362,69 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S showLockscreen() assertThat(alpha).isEqualTo(1f) + // Go to dozing + keyguardTransitionRepository.sendTransitionSteps( + from = LOCKSCREEN, + to = DOZING, + testScope, + ) + assertThat(alpha).isEqualTo(1f) + + // Start transitioning to glanceable hub + val progress = 0.6f + kosmos.setTransition( + sceneTransition = Transition(from = Scenes.Lockscreen, to = Scenes.Communal), + stateTransition = + TransitionStep( + transitionState = TransitionState.STARTED, + from = DOZING, + to = GLANCEABLE_HUB, + value = 0f, + ), + ) + runCurrent() + kosmos.setTransition( + sceneTransition = + Transition( + from = Scenes.Lockscreen, + to = Scenes.Communal, + progress = flowOf(progress), + ), + stateTransition = + TransitionStep( + transitionState = TransitionState.RUNNING, + from = DOZING, + to = GLANCEABLE_HUB, + value = progress, + ), + ) + runCurrent() + // Keep notifications hidden during the transition from dream to hub + assertThat(alpha).isEqualTo(0) + + // Finish transition to glanceable hub + kosmos.setTransition( + sceneTransition = Idle(Scenes.Communal), + stateTransition = + TransitionStep( + transitionState = TransitionState.FINISHED, + from = DOZING, + to = GLANCEABLE_HUB, + value = 1f, + ), + ) + assertThat(alpha).isEqualTo(0f) + } + + @Test + fun glanceableHubAlpha_dozingToHub() = + testScope.runTest { + val alpha by collectLastValue(underTest.glanceableHubAlpha) + + // Start on lockscreen, notifications should be unhidden. + showLockscreen() + assertThat(alpha).isEqualTo(1f) + // Transition to dream, notifications should be hidden so that transition // from dream->hub doesn't cause notification flicker. showDream() @@ -746,7 +808,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S @DisableSceneContainer fun translationYUpdatesOnKeyguardForBurnIn() = testScope.runTest { - val translationY by collectLastValue(underTest.translationY(BurnInParameters())) + val translationY by collectLastValue(underTest.translationY) showLockscreen() assertThat(translationY).isEqualTo(0) @@ -759,7 +821,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S @DisableSceneContainer fun translationYUpdatesOnKeyguard() = testScope.runTest { - val translationY by collectLastValue(underTest.translationY(BurnInParameters())) + val translationY by collectLastValue(underTest.translationY) configurationRepository.setDimensionPixelSize( R.dimen.keyguard_translate_distance_on_swipe_up, @@ -780,7 +842,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S @DisableSceneContainer fun translationYDoesNotUpdateWhenShadeIsExpanded() = testScope.runTest { - val translationY by collectLastValue(underTest.translationY(BurnInParameters())) + val translationY by collectLastValue(underTest.translationY) configurationRepository.setDimensionPixelSize( R.dimen.keyguard_translate_distance_on_swipe_up, diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp index 682a68fdf846..a26cf1232636 100644 --- a/packages/SystemUI/plugin/Android.bp +++ b/packages/SystemUI/plugin/Android.bp @@ -23,9 +23,7 @@ package { } java_library { - name: "SystemUIPluginLib", - srcs: [ "bcsmartspace/src/**/*.java", "bcsmartspace/src/**/*.kt", @@ -40,6 +38,8 @@ java_library { export_proguard_flags_files: true, }, + plugins: ["PluginAnnotationProcessor"], + // If you add a static lib here, you may need to also add the package to the ClassLoaderFilter // in PluginInstance. That will ensure that loaded plugins have access to the related classes. // You should also add it to proguard_common.flags so that proguard does not remove the portions @@ -53,7 +53,6 @@ java_library { "SystemUILogLib", "androidx.annotation_annotation", ], - } android_app { diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/TestPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/TestPlugin.kt new file mode 100644 index 000000000000..33f7b7acdef5 --- /dev/null +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/TestPlugin.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.plugins + +import com.android.systemui.plugins.annotations.ProtectedInterface +import com.android.systemui.plugins.annotations.ProtectedReturn +import com.android.systemui.plugins.annotations.ProvidesInterface + +@ProtectedInterface +@ProvidesInterface(action = TestPlugin.ACTION, version = TestPlugin.VERSION) +/** Interface intended for use in tests */ +interface TestPlugin : Plugin { + companion object { + const val VERSION = 1 + + const val ACTION = "testAction" + } + + @ProtectedReturn("return new Object();") + /** Test method, implemented by test */ + fun methodThrowsError(): Object +} diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt index 8dc4815b6f57..6d27b6f9637b 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt @@ -21,7 +21,11 @@ import androidx.constraintlayout.widget.ConstraintSet import com.android.internal.annotations.Keep import com.android.systemui.log.core.MessageBuffer import com.android.systemui.plugins.Plugin +import com.android.systemui.plugins.annotations.GeneratedImport +import com.android.systemui.plugins.annotations.ProtectedInterface +import com.android.systemui.plugins.annotations.ProtectedReturn import com.android.systemui.plugins.annotations.ProvidesInterface +import com.android.systemui.plugins.annotations.SimpleProperty import java.io.PrintWriter import java.util.Locale import java.util.TimeZone @@ -31,6 +35,7 @@ import org.json.JSONObject typealias ClockId = String /** A Plugin which exposes the ClockProvider interface */ +@ProtectedInterface @ProvidesInterface(action = ClockProviderPlugin.ACTION, version = ClockProviderPlugin.VERSION) interface ClockProviderPlugin : Plugin, ClockProvider { companion object { @@ -40,31 +45,42 @@ interface ClockProviderPlugin : Plugin, ClockProvider { } /** Interface for building clocks and providing information about those clocks */ +@ProtectedInterface +@GeneratedImport("java.util.List") +@GeneratedImport("java.util.ArrayList") interface ClockProvider { /** Initializes the clock provider with debug log buffers */ fun initialize(buffers: ClockMessageBuffers?) + @ProtectedReturn("return new ArrayList<ClockMetadata>();") /** Returns metadata for all clocks this provider knows about */ fun getClocks(): List<ClockMetadata> + @ProtectedReturn("return null;") /** Initializes and returns the target clock design */ - fun createClock(settings: ClockSettings): ClockController + fun createClock(settings: ClockSettings): ClockController? + @ProtectedReturn("return new ClockPickerConfig(\"\", \"\", \"\", null);") /** Settings configuration parameters for the clock */ fun getClockPickerConfig(id: ClockId): ClockPickerConfig } /** Interface for controlling an active clock */ +@ProtectedInterface interface ClockController { + @get:SimpleProperty /** A small version of the clock, appropriate for smaller viewports */ val smallClock: ClockFaceController + @get:SimpleProperty /** A large version of the clock, appropriate when a bigger viewport is available */ val largeClock: ClockFaceController + @get:SimpleProperty /** Determines the way the hosting app should behave when rendering either clock face */ val config: ClockConfig + @get:SimpleProperty /** Events that clocks may need to respond to */ val events: ClockEvents @@ -76,19 +92,26 @@ interface ClockController { } /** Interface for a specific clock face version rendered by the clock */ +@ProtectedInterface interface ClockFaceController { + @get:SimpleProperty + @Deprecated("Prefer use of layout") /** View that renders the clock face */ val view: View + @get:SimpleProperty /** Layout specification for this clock */ val layout: ClockFaceLayout + @get:SimpleProperty /** Determines the way the hosting app should behave when rendering this clock face */ val config: ClockFaceConfig + @get:SimpleProperty /** Events specific to this clock face */ val events: ClockFaceEvents + @get:SimpleProperty /** Triggers for various animations */ val animations: ClockAnimations } @@ -107,14 +130,21 @@ data class ClockMessageBuffers( data class AodClockBurnInModel(val scale: Float, val translationX: Float, val translationY: Float) -/** Specifies layout information for the */ +/** Specifies layout information for the clock face */ +@ProtectedInterface +@GeneratedImport("java.util.ArrayList") +@GeneratedImport("android.view.View") interface ClockFaceLayout { + @get:ProtectedReturn("return new ArrayList<View>();") /** All clock views to add to the root constraint layout before applying constraints. */ val views: List<View> + @ProtectedReturn("return constraints;") /** Custom constraints to apply to Lockscreen ConstraintLayout. */ fun applyConstraints(constraints: ConstraintSet): ConstraintSet + @ProtectedReturn("return constraints;") + /** Custom constraints to apply to preview ConstraintLayout. */ fun applyPreviewConstraints(constraints: ConstraintSet): ConstraintSet fun applyAodBurnIn(aodBurnInModel: AodClockBurnInModel) @@ -145,7 +175,9 @@ class DefaultClockFaceLayout(val view: View) : ClockFaceLayout { } /** Events that should call when various rendering parameters change */ +@ProtectedInterface interface ClockEvents { + @get:ProtectedReturn("return false;") /** Set to enable or disable swipe interaction */ var isReactiveTouchInteractionEnabled: Boolean @@ -187,6 +219,7 @@ data class ClockReactiveSetting( ) /** Methods which trigger various clock animations */ +@ProtectedInterface interface ClockAnimations { /** Runs an enter animation (if any) */ fun enter() @@ -230,6 +263,7 @@ interface ClockAnimations { } /** Events that have specific data about the related face */ +@ProtectedInterface interface ClockFaceEvents { /** Call every time tick */ fun onTimeTick() @@ -270,7 +304,9 @@ enum class ClockTickRate(val value: Int) { /** Some data about a clock design */ data class ClockMetadata(val clockId: ClockId) -data class ClockPickerConfig( +data class ClockPickerConfig +@JvmOverloads +constructor( val id: String, /** Localized name of the clock */ @@ -338,7 +374,7 @@ data class ClockConfig( /** Transition to AOD should move smartspace like large clock instead of small clock */ val useAlternateSmartspaceAODTransition: Boolean = false, - /** Use ClockPickerConfig.isReactiveToTone instead */ + /** Deprecated version of isReactiveToTone; moved to ClockPickerConfig */ @Deprecated("TODO(b/352049256): Remove in favor of ClockPickerConfig.isReactiveToTone") val isReactiveToTone: Boolean = true, diff --git a/packages/SystemUI/plugin_core/Android.bp b/packages/SystemUI/plugin_core/Android.bp index 521c019d74f3..31fbda557279 100644 --- a/packages/SystemUI/plugin_core/Android.bp +++ b/packages/SystemUI/plugin_core/Android.bp @@ -24,8 +24,42 @@ package { java_library { sdk_version: "current", + name: "PluginAnnotationLib", + host_supported: true, + device_supported: true, + srcs: [ + "src/**/annotations/*.java", + "src/**/annotations/*.kt", + ], + optimize: { + proguard_flags_files: ["proguard.flags"], + // Ensure downstream clients that reference this as a shared lib + // inherit the appropriate flags to preserve annotations. + export_proguard_flags_files: true, + }, + + // Enforce that the library is built against java 8 so that there are + // no compatibility issues with launcher + java_version: "1.8", +} + +java_library { + sdk_version: "current", name: "PluginCoreLib", - srcs: ["src/**/*.java"], + device_supported: true, + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], + exclude_srcs: [ + "src/**/annotations/*.java", + "src/**/annotations/*.kt", + "src/**/processor/*.java", + "src/**/processor/*.kt", + ], + static_libs: [ + "PluginAnnotationLib", + ], optimize: { proguard_flags_files: ["proguard.flags"], // Ensure downstream clients that reference this as a shared lib @@ -37,3 +71,30 @@ java_library { // no compatibility issues with launcher java_version: "1.8", } + +java_library { + java_version: "1.8", + name: "PluginAnnotationProcessorLib", + host_supported: true, + device_supported: false, + srcs: [ + "src/**/processor/*.java", + "src/**/processor/*.kt", + ], + plugins: ["auto_service_plugin"], + static_libs: [ + "androidx.annotation_annotation", + "auto_service_annotations", + "auto_common", + "PluginAnnotationLib", + "guava", + "jsr330", + ], +} + +java_plugin { + name: "PluginAnnotationProcessor", + processor_class: "com.android.systemui.plugins.processor.ProtectedPluginProcessor", + static_libs: ["PluginAnnotationProcessorLib"], + java_version: "1.8", +} diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/Plugin.java b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/Plugin.java index 8ff6c114dded..84040f984ec5 100644 --- a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/Plugin.java +++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/Plugin.java @@ -15,6 +15,7 @@ package com.android.systemui.plugins; import android.content.Context; +import com.android.systemui.plugins.annotations.ProtectedReturn; import com.android.systemui.plugins.annotations.Requires; /** @@ -116,6 +117,8 @@ public interface Plugin { * @deprecated * @see Requires */ + @Deprecated + @ProtectedReturn(statement = "return -1;") default int getVersion() { // Default of -1 indicates the plugin supports the new Requires model. return -1; diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginWrapper.kt b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginWrapper.kt new file mode 100644 index 000000000000..debb318d6527 --- /dev/null +++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginWrapper.kt @@ -0,0 +1,20 @@ +/* + * 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.plugins + +/** [PluginWrapper] wraps an interface used by a plugin */ +interface PluginWrapper<T> { + /** Instance that is being wrapped */ + fun getPlugin(): T +} diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/ProtectedPluginListener.kt b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/ProtectedPluginListener.kt new file mode 100644 index 000000000000..3a1f251ca672 --- /dev/null +++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/ProtectedPluginListener.kt @@ -0,0 +1,27 @@ +/* + * 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.plugins + +/** Listener for events from proxy types generated by [ProtectedPluginProcessor]. */ +interface ProtectedPluginListener { + /** + * Called when a method call produces a [LinkageError] before returning. This callback is + * provided so that the host application can terminate the plugin or log the error as + * appropriate. + * + * @return true to terminate all methods within this object; false if the error is recoverable + * and the proxied plugin should continue to operate as normal. + */ + fun onFail(className: String, methodName: String, failure: LinkageError): Boolean +} diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/annotations/ProtectedInterface.kt b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/annotations/ProtectedInterface.kt new file mode 100644 index 000000000000..12a977d9350e --- /dev/null +++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/annotations/ProtectedInterface.kt @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package com.android.systemui.plugins.annotations + +/** + * This annotation marks denotes that an interface should use a proxy layer to protect the plugin + * host from crashing due to [LinkageError]s originating within the plugin's implementation. + */ +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.BINARY) +annotation class ProtectedInterface + +/** + * This annotation specifies any additional imports that the processor will require when generating + * the proxy implementation for the target interface. The interface in question must still be + * annotated with [ProtectedInterface]. + */ +@Repeatable +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.BINARY) +annotation class GeneratedImport(val extraImport: String) + +/** + * This annotation provides default values to return when the proxy implementation catches a + * [LinkageError]. The string specified should be a simple but valid java statement. In most cases + * it should be a return statement of the appropriate type, but in some cases throwing a known + * exception type may be preferred. + * + * This annotation is not required for methods that return void, but will behave the same way. + */ +@Target( + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY, + AnnotationTarget.PROPERTY_GETTER, + AnnotationTarget.PROPERTY_SETTER, +) +@Retention(AnnotationRetention.BINARY) +annotation class ProtectedReturn(val statement: String) + +/** + * Some very simple properties and methods need not be protected by the proxy implementation. This + * annotation can be used to omit the normal try-catch wrapper the proxy is using. These members + * will instead be a direct passthrough. + * + * It should only be used for members where the plugin implementation is expected to be exceedingly + * simple. Any member marked with this annotation should be no more complex than kotlin's automatic + * properties, and make no other method calls whatsoever. + */ +@Target( + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY, + AnnotationTarget.PROPERTY_GETTER, + AnnotationTarget.PROPERTY_SETTER, +) +@Retention(AnnotationRetention.BINARY) +annotation class SimpleProperty diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/processor/ProtectedPluginProcessor.kt b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/processor/ProtectedPluginProcessor.kt new file mode 100644 index 000000000000..6b54d8936254 --- /dev/null +++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/processor/ProtectedPluginProcessor.kt @@ -0,0 +1,356 @@ +/* + * 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.plugins.processor + +import com.android.systemui.plugins.annotations.GeneratedImport +import com.android.systemui.plugins.annotations.ProtectedInterface +import com.android.systemui.plugins.annotations.ProtectedReturn +import com.android.systemui.plugins.annotations.SimpleProperty +import com.google.auto.service.AutoService +import javax.annotation.processing.AbstractProcessor +import javax.annotation.processing.ProcessingEnvironment +import javax.annotation.processing.RoundEnvironment +import javax.lang.model.element.Element +import javax.lang.model.element.ElementKind +import javax.lang.model.element.ExecutableElement +import javax.lang.model.element.PackageElement +import javax.lang.model.element.TypeElement +import javax.lang.model.type.TypeKind +import javax.lang.model.type.TypeMirror +import javax.tools.Diagnostic.Kind +import kotlin.collections.ArrayDeque + +/** + * [ProtectedPluginProcessor] generates a proxy implementation for interfaces annotated with + * [ProtectedInterface] which catches [LinkageError]s generated by the proxied target. This protects + * the plugin host from crashing due to out-of-date plugin code, where some call has changed so that + * the [ClassLoader] can no longer resolve it correctly. + * + * [PluginInstance] observes these failures via [ProtectedMethodListener] and unloads the plugin in + * question to prevent further issues. This persists through further load/unload requests. + * + * To centralize access to the proxy types, an additional type [PluginProtector] is also generated. + * This class provides static methods which wrap an instance of the target interface in the proxy + * type if it is not already an instance of the proxy. + */ +@AutoService(ProtectedPluginProcessor::class) +class ProtectedPluginProcessor : AbstractProcessor() { + private lateinit var procEnv: ProcessingEnvironment + + override fun init(procEnv: ProcessingEnvironment) { + this.procEnv = procEnv + } + + override fun getSupportedAnnotationTypes(): Set<String> = + setOf("com.android.systemui.plugins.annotations.ProtectedInterface") + + private data class TargetData( + val attribute: TypeElement, + val sourceType: Element, + val sourcePkg: String, + val sourceName: String, + val outputName: String, + ) + + override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean { + val targets = mutableMapOf<String, TargetData>() // keyed by fully-qualified source name + val additionalImports = mutableSetOf<String>() + for (attr in annotations) { + for (target in roundEnv.getElementsAnnotatedWith(attr)) { + val sourceName = "${target.simpleName}" + val outputName = "${sourceName}Protector" + val pkg = (target.getEnclosingElement() as PackageElement).qualifiedName.toString() + targets.put("$target", TargetData(attr, target, pkg, sourceName, outputName)) + + // This creates excessive imports, but it should be fine + additionalImports.add("$pkg.$sourceName") + additionalImports.add("$pkg.$outputName") + } + } + + if (targets.size <= 0) return false + for ((_, sourceType, sourcePkg, sourceName, outputName) in targets.values) { + // Find all methods in this type and all super types to that need to be implemented + val types = ArrayDeque<TypeMirror>().apply { addLast(sourceType.asType()) } + val impAttrs = mutableListOf<GeneratedImport>() + val methods = mutableListOf<ExecutableElement>() + while (types.size > 0) { + val typeMirror = types.removeLast() + if (typeMirror.toString() == "java.lang.Object") continue + val type = procEnv.typeUtils.asElement(typeMirror) + for (member in type.enclosedElements) { + if (member.kind != ElementKind.METHOD) continue + methods.add(member as ExecutableElement) + } + + impAttrs.addAll(type.getAnnotationsByType(GeneratedImport::class.java)) + types.addAll(procEnv.typeUtils.directSupertypes(typeMirror)) + } + + val file = procEnv.filer.createSourceFile("$outputName") + TabbedWriter.writeTo(file.openWriter()) { + line("package $sourcePkg;") + line() + + // Imports used by the proxy implementation + line("import android.util.Log;") + line("import java.lang.LinkageError;") + line("import com.android.systemui.plugins.PluginWrapper;") + line("import com.android.systemui.plugins.ProtectedPluginListener;") + line() + + // Imports of other generated types + if (additionalImports.size > 0) { + for (impTarget in additionalImports) { + line("import $impTarget;") + } + line() + } + + // Imports declared via @GeneratedImport + if (impAttrs.size > 0) { + for (impAttr in impAttrs) { + line("import ${impAttr.extraImport};") + } + line() + } + + val interfaces = "$sourceName, PluginWrapper<$sourceName>" + braceBlock("public class $outputName implements $interfaces") { + line("private static final String CLASS = \"$sourceName\";") + + // Static factory method to prevent wrapping the same object twice + parenBlock("public static $outputName protect") { + line("$sourceName instance,") + line("ProtectedPluginListener listener") + } + braceBlock { + line("if (instance instanceof $outputName)") + line(" return ($outputName)instance;") + line("return new $outputName(instance, listener);") + } + line() + + // Member Fields + line("private $sourceName mInstance;") + line("private ProtectedPluginListener mListener;") + line("private boolean mHasError = false;") + line() + + // Constructor + parenBlock("private $outputName") { + line("$sourceName instance,") + line("ProtectedPluginListener listener") + } + braceBlock { + line("mInstance = instance;") + line("mListener = listener;") + } + line() + + // Wrapped instance getter for version checker + braceBlock("public $sourceName getPlugin()") { line("return mInstance;") } + + // Method implementations + for (method in methods) { + val methodName = method.simpleName + val returnTypeName = method.returnType.toString() + val callArgs = StringBuilder() + var isFirst = true + + line("@Override") + parenBlock("public $returnTypeName $methodName") { + // While copying the method signature for the proxy type, we also + // accumulate arguments for the nested callsite. + for (param in method.parameters) { + if (!isFirst) completeLine(",") + startLine("${param.asType()} ${param.simpleName}") + isFirst = false + + if (callArgs.length > 0) callArgs.append(", ") + callArgs.append(param.simpleName) + } + } + + val isVoid = method.returnType.kind == TypeKind.VOID + val nestedCall = "mInstance.$methodName($callArgs)" + val callStatement = + when { + isVoid -> "$nestedCall;" + targets.containsKey(returnTypeName) -> { + val targetType = targets.get(returnTypeName)!!.outputName + "return $targetType.protect($nestedCall, mListener);" + } + else -> "return $nestedCall;" + } + + // Simple property methods forgo protection + val simpleAttr = method.getAnnotation(SimpleProperty::class.java) + if (simpleAttr != null) { + braceBlock { + line("final String METHOD = \"$methodName\";") + line(callStatement) + } + line() + continue + } + + // Standard implementation wraps nested call in try-catch + braceBlock { + val retAttr = method.getAnnotation(ProtectedReturn::class.java) + val errorStatement = + when { + retAttr != null -> retAttr.statement + isVoid -> "return;" + else -> { + // Non-void methods must be annotated. + procEnv.messager.printMessage( + Kind.ERROR, + "$outputName.$methodName must be annotated with " + + "@ProtectedReturn or @SimpleProperty", + ) + "throw ex;" + } + } + + line("final String METHOD = \"$methodName\";") + + // Return immediately if any previous call has failed. + braceBlock("if (mHasError)") { line(errorStatement) } + + // Protect callsite in try/catch block + braceBlock("try") { line(callStatement) } + + // Notify listener when a LinkageError is caught + braceBlock("catch (LinkageError ex)") { + line("Log.wtf(CLASS, \"Failed to execute: \" + METHOD, ex);") + line("mHasError = mListener.onFail(CLASS, METHOD, ex);") + line(errorStatement) + } + } + line() + } + } + } + } + + // Write a centralized static factory type to its own file. This is for convience so that + // PluginInstance need not resolve each generated type at runtime as plugins are loaded. + val factoryFile = procEnv.filer.createSourceFile("PluginProtector") + TabbedWriter.writeTo(factoryFile.openWriter()) { + line("package com.android.systemui.plugins;") + line() + + line("import java.util.Map;") + line("import java.util.ArrayList;") + line("import java.util.HashSet;") + line("import android.util.Log;") + line("import static java.util.Map.entry;") + line() + + for (impTarget in additionalImports) { + line("import $impTarget;") + } + line() + + braceBlock("public final class PluginProtector") { + line("private PluginProtector() { }") + line() + + line("private static final String TAG = \"PluginProtector\";") + line() + + // Untyped factory SAM, private to this type. + braceBlock("private interface Factory") { + line("Object create(Object plugin, ProtectedPluginListener listener);") + } + line() + + // Store a reference to each `protect` method in a map by interface type. + parenBlock("private static final Map<Class, Factory> sFactories = Map.ofEntries") { + var isFirst = true + for (target in targets.values) { + if (!isFirst) completeLine(",") + target.apply { + startLine("entry($sourceName.class, ") + appendLine("(p, h) -> $outputName.protect(($sourceName)p, h))") + } + isFirst = false + } + } + completeLine(";") + line() + + // Lookup the relevant factory based on the instance type, if not found return null. + parenBlock("public static <T> T tryProtect") { + line("T target,") + line("ProtectedPluginListener listener") + } + braceBlock { + // Accumulate interfaces from type and all base types + line("HashSet<Class> interfaces = new HashSet<Class>();") + line("Class current = target.getClass();") + braceBlock("while (current != null)") { + braceBlock("for (Class cls : current.getInterfaces())") { + line("interfaces.add(cls);") + } + line("current = current.getSuperclass();") + } + line() + + // Check if any of the interfaces are marked protectable + line("int candidateCount = 0;") + line("Factory candidateFactory = null;") + braceBlock("for (Class cls : interfaces)") { + line("Factory factory = sFactories.get(cls);") + braceBlock("if (factory != null)") { + line("candidateFactory = factory;") + line("candidateCount++;") + } + } + line() + + // No match, return null + braceBlock("if (candidateFactory == null)") { + line("Log.i(TAG, \"Wasn't able to wrap \" + target);") + line("return null;") + } + + // Multiple matches, not supported + braceBlock("if (candidateCount >= 2)") { + var error = "Plugin implements more than one protected interface" + line("throw new UnsupportedOperationException(\"$error\");") + } + + // Call the factory and wrap the target object + line("return (T)candidateFactory.create(target, listener);") + } + line() + + // Wraps the target with the appropriate generated proxy if it exists. + parenBlock("public static <T> T protectIfAble") { + line("T target,") + line("ProtectedPluginListener listener") + } + braceBlock { + line("T result = tryProtect(target, listener);") + line("return result != null ? result : target;") + } + line() + } + } + + return true + } +} diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/processor/TabbedWriter.kt b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/processor/TabbedWriter.kt new file mode 100644 index 000000000000..941b2c2db4c1 --- /dev/null +++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/processor/TabbedWriter.kt @@ -0,0 +1,112 @@ +/* + * 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.plugins.processor + +import java.io.BufferedWriter +import java.io.Writer + +/** + * [TabbedWriter] is a convience class which tracks and writes correctly tabbed lines for generating + * source files. These files don't need to be correctly tabbed as they're ephemeral and not part of + * the source tree, but correct tabbing makes debugging much easier when the build fails. + */ +class TabbedWriter(writer: Writer) : AutoCloseable { + private val target = BufferedWriter(writer) + private var isInProgress = false + var tabCount: Int = 0 + private set + + override fun close() = target.close() + + fun line() { + target.newLine() + isInProgress = false + } + + fun line(str: String) { + if (isInProgress) { + target.newLine() + } + + target.append(" ".repeat(tabCount)) + target.append(str) + target.newLine() + isInProgress = false + } + + fun completeLine(str: String) { + if (!isInProgress) { + target.newLine() + target.append(" ".repeat(tabCount)) + } + + target.append(str) + target.newLine() + isInProgress = false + } + + fun startLine(str: String) { + if (isInProgress) { + target.newLine() + } + + target.append(" ".repeat(tabCount)) + target.append(str) + isInProgress = true + } + + fun appendLine(str: String) { + if (!isInProgress) { + target.append(" ".repeat(tabCount)) + } + + target.append(str) + isInProgress = true + } + + fun braceBlock(str: String = "", write: TabbedWriter.() -> Unit) { + block(str, " {", "}", true, write) + } + + fun parenBlock(str: String = "", write: TabbedWriter.() -> Unit) { + block(str, "(", ")", false, write) + } + + private fun block( + str: String, + start: String, + end: String, + newLineForEnd: Boolean, + write: TabbedWriter.() -> Unit, + ) { + appendLine(str) + completeLine(start) + + tabCount++ + this.write() + tabCount-- + + if (newLineForEnd) { + line(end) + } else { + startLine(end) + } + } + + companion object { + fun writeTo(writer: Writer, write: TabbedWriter.() -> Unit) { + TabbedWriter(writer).use { it.write() } + } + } +} diff --git a/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml index 91cd019c85d1..3b3ed39c8993 100644 --- a/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml +++ b/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml @@ -215,4 +215,17 @@ app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="1.0" tools:srcCompat="@tools:sample/avatars" /> + + <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper + android:id="@+id/biometric_icon_overlay" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_gravity="center" + android:contentDescription="@null" + android:scaleType="fitXY" + android:importantForAccessibility="no" + app:layout_constraintBottom_toBottomOf="@+id/biometric_icon" + app:layout_constraintEnd_toEndOf="@+id/biometric_icon" + app:layout_constraintStart_toStartOf="@+id/biometric_icon" + app:layout_constraintTop_toTopOf="@+id/biometric_icon" /> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml index 51117a7845df..2a00495e9d01 100644 --- a/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml +++ b/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml @@ -40,6 +40,19 @@ android:layout_height="match_parent"> app:layout_constraintTop_toTopOf="parent" tools:srcCompat="@tools:sample/avatars" /> + <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper + android:id="@+id/biometric_icon_overlay" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_gravity="center" + android:contentDescription="@null" + android:scaleType="fitXY" + android:importantForAccessibility="no" + app:layout_constraintBottom_toBottomOf="@+id/biometric_icon" + app:layout_constraintEnd_toEndOf="@+id/biometric_icon" + app:layout_constraintStart_toStartOf="@+id/biometric_icon" + app:layout_constraintTop_toTopOf="@+id/biometric_icon" /> + <ScrollView android:id="@+id/scrollView" android:layout_width="0dp" diff --git a/packages/SystemUI/res/layout/status_bar_no_notifications.xml b/packages/SystemUI/res/layout/status_bar_no_notifications.xml index 856ba92b6d41..248e61100cad 100644 --- a/packages/SystemUI/res/layout/status_bar_no_notifications.xml +++ b/packages/SystemUI/res/layout/status_bar_no_notifications.xml @@ -15,7 +15,7 @@ --> <!-- Extends Framelayout --> -<com.android.systemui.statusbar.EmptyShadeView +<com.android.systemui.statusbar.notification.emptyshade.ui.view.EmptyShadeView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -46,4 +46,4 @@ android:textAppearance="?android:attr/textAppearanceButton" android:text="@string/unlock_to_see_notif_text"/> </LinearLayout> -</com.android.systemui.statusbar.EmptyShadeView> +</com.android.systemui.statusbar.notification.emptyshade.ui.view.EmptyShadeView> diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml index fbb07bed4b50..22d34eb7b115 100644 --- a/packages/SystemUI/res/layout/super_notification_shade.xml +++ b/packages/SystemUI/res/layout/super_notification_shade.xml @@ -58,14 +58,6 @@ android:layout_height="match_parent" android:visibility="invisible" /> - <!-- Root for all keyguard content. It was previously located within the shade. --> - <com.android.systemui.keyguard.ui.view.KeyguardRootView - android:id="@id/keyguard_root_view" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:clipChildren="false" - /> - <!-- Shared container for the notification stack. Can be positioned by either the keyguard_root_view or notification_panel --> <com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer @@ -76,6 +68,14 @@ android:clipToPadding="false" /> + <!-- Root for all keyguard content. It was previously located within the shade. --> + <com.android.systemui.keyguard.ui.view.KeyguardRootView + android:id="@id/keyguard_root_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:clipChildren="false" + /> + <include layout="@layout/brightness_mirror_container" /> <com.android.systemui.scrim.ScrimView diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 3fe421455782..d7c13598644f 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Voeg by"</string> <string name="manage_users" msgid="1823875311934643849">"Bestuur gebruikers"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Sleep na verdeelde skerm word nie vir hierdie kennisgewing gesteun nie"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Ligging is aktief"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑fi onbeskikbaar"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteitmodus"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wekker gestel"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Pasmaak sluitskerm"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Ontsluit om sluitskerm te pasmaak"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-fi is nie beskikbaar nie"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Ligging is aktief"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera is geblokkeer"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera en mikrofoon is geblokkeer"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofoon is geblokkeer"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Vou ikoon in"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Vou ikoon uit"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"of"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigeer met jou sleutelbord"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Leer kortpadsleutels"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigeer met jou raakpaneel"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Leer raakpaneelgebare, kortpadsleutels en meer"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Teruggebaar"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Tuisgebaar"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Bekyk onlangse apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Klaar"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gaan terug"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Swiep enige plek op die raakpaneel links of regs met drie vingers om terug te gaan.\n\nJy kan ook die kortpadsleutelhandeling + Esc hiervoor gebruik."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Swiep enige tyd van die onderkant van jou skerm af op met drie vingers om na jou tuisskerm toe te gaan."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Mooi so!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Jy het die Gaan na Tuisskerm-gebaar voltooi."</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">"Bekyk onlangse apps"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Swiep op en hou met drie vingers op jou raakpaneel."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Knap gedaan!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Jy het die Bekyk Onlangse Apps-gebaar voltooi."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Handelingsleutel"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Druk die handelingsleutel op jou sleutelbord om toegang tot jou apps te kry."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Geluk!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Swiep op en hou met drie vingers. Tik om meer gebare te leer."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Gebruik jou sleutelbord om alle apps te bekyk"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Druk enige tyd die handelingsleutel. Tik om meer gebare te leer."</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">"Ekstra donker is nou deel van die helderheidglyer"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Jy kan nou die skerm ekstra donker maak deur die helderheidvlak nog laer te maak.\n\nAangesien hierdie kenmerk nou deel van die helderheidglyer is, word kortpaaie vir ekstra donker verwyder."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Verwyder kortpaaie vir ekstra donker"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Kortpaaie vir ekstra donker is verwyder"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Konnektiwiteit"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Toeganklikheid"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Nutsdienste"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 77da382904c4..388601bc157d 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"ግብዓት"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"ውጤት"</string> <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> @@ -1293,8 +1291,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> @@ -1351,8 +1348,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> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"መሰብሰቢያ አዶ"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"መዘርጊያ አዶ"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ወይም"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"የቁልፍ ሰሌዳዎን በመጠቀም ያስሱ"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"የቁልፍ ሰሌዳ አቋራጮችን ይወቁ"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"የመዳሰሻ ሰሌዳዎን በመጠቀም ያስሱ"</string> @@ -1408,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> @@ -1419,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> @@ -1450,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-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 64b0f0b221f8..53b1dfb920fa 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"الإدخال"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"الإخراج"</string> <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> @@ -1293,8 +1291,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> @@ -1351,8 +1348,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> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"رمز التصغير"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"رمز التوسيع"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"أو"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"التنقّل باستخدام لوحة المفاتيح"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"تعرَّف على اختصارات لوحة المفاتيح"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"التنقّل باستخدام لوحة اللمس"</string> @@ -1408,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> @@ -1419,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> @@ -1450,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-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 6e3ba230fd66..04cb99cb7157 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"ইনপুট"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"আউটপুট"</string> <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> @@ -1398,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"সংকোচন কৰাৰ চিহ্ন"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"বিস্তাৰ কৰাৰ চিহ্ন"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"অথবা"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"কীব’ৰ্ড ব্যৱহাৰ কৰি নেভিগে’ট কৰক"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"কীব’ৰ্ডৰ শ্বৰ্টকাটসমূহৰ বিষয়ে জানক"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"আপোনাৰ টাচ্চপেড ব্যৱহাৰ কৰি নেভিগে’ট কৰক"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 33f1e74e5764..85aa42f13a23 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -1398,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"İkonanı yığcamlaşdırın"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"İkonanı genişləndirin"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"və ya"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Klaviaturadan istifadə edərək hərəkət edin"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Klaviatura qısayolları haqqında öyrənin"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Taçpeddən istifadə edərək hərəkət edin"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 4c25b4b64e69..b838f7c445b5 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Ulaz"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Izlaz"</string> <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> @@ -1293,8 +1291,7 @@ <string name="add" msgid="81036585205287996">"Dodaj"</string> <string name="manage_users" msgid="1823875311934643849">"Upravljaj korisnicima"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Ovo obaveštenje ne podržava prevlačenje na podeljeni ekran"</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">"WiFi nije dostupan"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritetni režim"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je podešen"</string> @@ -1351,8 +1348,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Prilagodi zaključani ekran"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Otključajte da biste prilagodili zaključani ekran"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"WiFi nije dostupan"</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">"Kamera je blokirana"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon su blokirani"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokiran"</string> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za skupljanje"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za proširivanje"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Krećite se pomoću tastature"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Saznajte više o tasterskim prečicama"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Krećite se pomoću tačpeda"</string> @@ -1408,8 +1406,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Naučite pokrete za tačped, tasterske prečice i drugo"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Pokret za vraćanje"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Pokret za početnu stranicu"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Prikaži nedavno korišćene aplikacije"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotovo"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazad"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Da biste se vratili, prevucite ulevo sa tri prsta bilo gde na tačpedu.\n\nMožete da koristite i tastersku prečicu Alt + ESC za ovo."</string> @@ -1419,14 +1416,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Da biste otišli na početni ekran u bilo kom trenutku, prevucite nagore od dna ekrana pomoću tri prsta."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Svaka čast!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Dovršili ste pokret za povratak na početnu stranicu."</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">"Prikaži nedavno korišćene aplikacije"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Prevucite nagore i zadržite pomoću tri prsta na tačpedu."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Odlično!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Dovršili ste pokret za prikazivanje nedavno korišćenih aplikacija."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Taster radnji"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Da biste pristupili aplikacijama, pritisnite taster radnji na tastaturi."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Čestitamo!"</string> @@ -1450,14 +1443,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Prevucite nagore i zadržite sa tri prsta. Dodirnite da biste videli više pokreta."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Koristite tastaturu da biste pregledali sve aplikacije"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pritisnite taster radnji u bilo kom trenutku. Dodirnite da biste videli više pokreta."</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">"Dodatno zatamnjivanje je sada deo klizača za osvetljenost"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Sada možete dodatno da zatamnite ekran smanjivanjem nivoa osvetljenosti. \n\nOva funkcija je sada deo klizača za osvetljenost, pa se prečice za dodatno zatamnjivanje uklanjaju."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Ukloni prečice za dodatno zatamnjivanje"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Uklonjene su prečice za dodatno zatamnjivanje"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Povezivanje"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Pristupačnost"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Uslužne aplikacije"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 4a79ceedff9a..038732c45559 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -1293,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> @@ -1351,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> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок \"Згарнуць\""</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок \"Разгарнуць\""</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"або"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навігацыя з дапамогай клавіятуры"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Азнаёмцеся са спалучэннямі клавіш"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навігацыя з дапамогай сэнсарнай панэлі"</string> @@ -1408,8 +1408,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> @@ -1419,14 +1418,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> @@ -1450,14 +1445,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-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 148bc1dc56f2..17a8ed520618 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -1293,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> @@ -1351,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> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за свиване"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за разгъване"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навигирайте посредством клавиатурата си"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Научете за клавишните комбинации"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навигирайте посредством сензорния панел"</string> @@ -1408,8 +1408,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> @@ -1419,14 +1418,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> @@ -1450,14 +1445,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-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index e7fde1643351..ebec6522d049 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -1398,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"আইকন আড়াল করুন"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"আইকন বড় করুন"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"অথবা"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"আপনার কীবোর্ড ব্যবহার করে নেভিগেট করুন"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"কীবোর্ড শর্টকাট সম্পর্কে জানুন"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"আপনার টাচপ্যাড ব্যবহার করে নেভিগেট করুন"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index b687ccd6126c..34e3d805ba35 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Ulaz"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Izlaz"</string> <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> @@ -1293,8 +1291,7 @@ <string name="add" msgid="81036585205287996">"Dodaj"</string> <string name="manage_users" msgid="1823875311934643849">"Upravljajte korisnicima"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Ovo obavještenje ne podržava prevlačenje na podijeljeni ekran"</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">"WiFi je nedostupan"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Način rada Prioriteti"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je postavljen"</string> @@ -1351,8 +1348,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Prilagodi zaključani ekran"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Otključajte da prilagodite zaključani ekran"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"WiFi mreža nije dostupna"</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">"Kamera je blokirana"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon su blokirani"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokiran"</string> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sužavanja"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona proširivanja"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Krećite se pomoću tastature"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Saznajte više o prečicama tastature"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Krećite se pomoću dodirne podloge"</string> @@ -1408,8 +1406,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Saznajte više o pokretima na dodirnoj podlozi, prečicama tastature i drugim opcijama"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Pokret za povratak"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Pokret za povratak na početni ekran"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Prikaži nedavne aplikacije"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotovo"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazad"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Da se vratite, prevucite ulijevo ili udesno s tri prsta bilo gdje na dodirnoj podlozi.\n\nZa ovo možete koristiti i radnju za prečicu i Esc na tastaturi."</string> @@ -1419,14 +1416,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Da odete na početni ekran bilo kada, prevucite s dna ekrana nagore s tri prsta."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Lijepo!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Savladali ste pokret za odlazak na početni ekran."</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">"Prikaz nedavnih aplikacija"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Prevucite nagore i zadržite s tri prsta na dodirnoj podlozi."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Sjajno!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Izvršili ste pokret za prikaz nedavnih aplikacija."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tipka radnji"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Da pristupite aplikacijama, pritisnite tipku radnji na tastaturi."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Čestitamo!"</string> @@ -1450,14 +1443,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Prevucite nagore i zadržite s tri prsta. Dodirnite da saznate za više pokreta."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Koristite tastaturu da pregledate sve aplikacije"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pritisnite tipku radnji bilo kada. Dodirnite da saznate za više pokreta."</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">"Dodatno zatamnjenje je sada dio klizača za osvijetljenost"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Sada možete dodatno zatamniti ekran daljnjim smanjenjem nivoa osvijetljenosti.\n\nBudući da je ova funkcija sada dio klizača za osvijetljenost, prečice za dodatno zatamnjenje se uklanjaju."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Ukloni prečice za dodatno zatamnjenje"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Prečice za dodatno zatamnjenje su uklonjene"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Povezivost"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Pristupačnost"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Uslužni programi"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 5b764a86a002..27f704d6c4d5 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Entrada"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Sortida"</string> <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> @@ -1293,8 +1291,7 @@ <string name="add" msgid="81036585205287996">"Afegeix"</string> <string name="manage_users" msgid="1823875311934643849">"Gestiona usuaris"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Aquesta notificació no es pot arrossegar a la pantalla dividida"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Ubicació activa"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi no disponible"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode Prioritat"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma definida"</string> @@ -1351,8 +1348,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Personalitza pantalla de bloqueig"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Desbloqueja per personalitzar la pantalla de bloqueig"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"No hi ha cap Wi‑Fi disponible"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Ubicació activa"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"La càmera està bloquejada"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"La càmera i el micròfon estan bloquejats"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"El micròfon està bloquejat"</string> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Replega la icona"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Desplega la icona"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navega amb el teclat"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprèn les tecles de drecera"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navega amb el ratolí tàctil"</string> @@ -1408,8 +1406,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprèn els gestos del ratolí tàctil, les tecles de drecera i més"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gest Enrere"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gest Inici"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Mostra les aplicacions recents"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Fet"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Torna"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Per tornar enrere, llisca cap a l\'esquerra o cap a la dreta amb tres dits en qualsevol lloc del ratolí tàctil.\n\nTambé pots utilitzar les tecles d\'accions de drecera+Esc."</string> @@ -1419,14 +1416,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Per anar a la pantalla d\'inici en qualsevol moment, fes lliscar tres dits cap amunt des de la part inferior de la pantalla."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Molt bé!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Has completat el gest per anar a la pantalla d\'inici."</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">"Mostra les aplicacions recents"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Llisca cap amunt amb tres dits i mantén premut al ratolí tàctil."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Ben fet!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Has completat el gest per veure les aplicacions recents."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla d\'acció"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Per accedir a les aplicacions, prem la tecla d\'acció al teclat."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Enhorabona!"</string> @@ -1450,14 +1443,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Llisca cap amunt amb tres dits i mantén premut. Toca per aprendre més gestos."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Utilitza el teclat per veure totes les aplicacions"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Prem la tecla d\'acció en qualsevol moment. Toca per aprendre més gestos."</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">"L\'atenuació extra ara forma part del control lliscant de brillantor"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Ara pots atenuar encara més la pantalla abaixant-ne el nivell de brillantor.\n\nCom que aquesta funció ara forma part del control lliscant de brillantor, les dreceres d\'atenuació extra se suprimiran."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Suprimeix les dreceres d\'atenuació extra"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"S\'han suprimit les dreceres d\'atenuació extra"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connectivitat"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibilitat"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilitats"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index f609e2a0c79c..c824837a73cd 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Přidat"</string> <string name="manage_users" msgid="1823875311934643849">"Spravovat uživatele"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Toto oznámení nepodporuje přetažení na rozdělenou obrazovku"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Určování polohy aktivní"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Síť Wi‑Fi není k dispozici"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritní režim"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Je nastaven budík"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Přizpůsobit obrazovku uzamčení"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Obrazovku uzamčení upravíte, když zařízení odemknete"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Síť Wi-Fi není dostupná"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Určování polohy aktivní"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokována"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera a mikrofon jsou blokovány"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokován"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sbalení"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozbalení"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"nebo"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigujte pomocí klávesnice"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Naučte se klávesové zkratky"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigujte pomocí touchpadu"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Naučte se gesta touchpadu, klávesové zkratky a další"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto zpět"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto domů"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Zobrazit nedávné aplikace"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hotovo"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Zpět"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Pokud se chcete vrátit zpět, stačí kdekoli na touchpadu přejet třemi prsty doleva nebo doprava.\n\nMůžete také použít klávesovou zkratku Akce + ESC."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Na plochu přejdete kdykoli přejetím třemi prsty ze spodní části obrazovky nahoru."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Skvělé!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Dokončili jste gesto pro přechod na plochu."</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">"Zobrazit nedávné aplikace"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Přejeďte po touchpadu třemi prsty nahoru a podržte je."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Výborně!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Provedli jste gesto pro zobrazení nedávných aplikací."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Akční klávesa"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Přístup k aplikacím získáte stisknutím akční klávesy na klávesnici."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Gratulujeme!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Přejeďte třemi prsty nahoru a podržte je. Další gesta zjistíte klepnutím."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Zobrazení všech aplikací pomocí klávesnice"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Kdykoli stiskněte akční klávesu. Další gesta zjistíte klepnutím."</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">"Na posuvníku jasu lze nově nastavit velmi tmavou obrazovku"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Obrazovku můžete nastavit jako velmi tmavou tím, že ještě víc snížíte jas.\n\nVzhledem k tomu, že je tato funkce nyní součástí posuvníku jasu, zkratky pro velmi tmavou obrazovku budou odstraněny."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Odstranit zkratky pro velmi tmavou obrazovku"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Zkratky pro velmi tmavou obrazovku byly odstraněny"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Připojení"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Přístupnost"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Nástroje"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 5d429af446e5..feac02dc0ac7 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Tilføj"</string> <string name="manage_users" msgid="1823875311934643849">"Administrer brugere"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Denne notifikation kan ikke trækkes til en opdelt skærm"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Lokation er aktiv"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Ingen tilgængelig Wi-Fi-forbindelse"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Tilstanden Prioritet"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmen er indstillet"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Tilpas låseskærm"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Lås op for at tilpasse låseskærmen"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi er ikke tilgængeligt"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Lokation er aktiv"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kameraet er blokeret"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Der er blokeret for kameraet og mikrofonen"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonen er blokeret"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikon for Skjul"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikon for Udvid"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviger ved hjælp af dit tastatur"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Se tastaturgenveje"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviger ved hjælp af din touchplade"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Se bevægelser på touchpladen, tastaturgenveje m.m."</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Bevægelse for at gå tilbage"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Bevægelse for at gå til startskærm"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Se seneste apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Udfør"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gå tilbage"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Du kan gå tilbage ved at stryge mod venstre eller højre med tre fingre et vilkårligt sted på touchpladen.\n\nDu kan også bruge tastaturgenvejen Alt + Esc."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Du kan til enhver tid stryge opad med tre fingre fra bunden af skærmen, hvis du vil gå til startskærmen."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Sådan!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Du har fuldført bevægelsen for Gå til startskærmen."</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">"Se seneste apps"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Stryg opad, og hold tre fingre på touchpladen."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Godt klaret!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du har udført bevægelsen for at se de seneste apps."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Handlingstast"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Du kan tilgå alle dine apps ved at trykke på handlingstasten på dit tastatur."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Tillykke!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Stryg opad, og hold tre fingre nede. Tryk for at lære flere bevægelser."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Brug dit tastatur til at se alle apps"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Tryk på handlingstasten når som helst. Tryk for at lære flere bevægelser."</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">"Ekstra dæmpet belysning er nu en del af skyderen til lysstyrke"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Du kan nu dæmpe skærmens belysning ekstra meget ved at reducere lysstyrken endnu mere.\n\nDa denne funktion nu er en del af skyderen til lysstyrke, fjernes genveje til ekstra dæmpet belysning."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Fjern genveje til ekstra dæmpet belysning"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Genveje til ekstra dæmpet belysning er fjernet"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Forbindelse"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Hjælpefunktioner"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Værktøjer"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 7d5fed918731..3235c3ad8b79 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -1400,6 +1400,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Symbol „Minimieren“"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Symbol „Maximieren“"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"oder"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigation mit der Tastatur"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Informationen zu Tastenkombinationen"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigation mit dem Touchpad"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index ab65136250fe..2187a172a4aa 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -1293,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> @@ -1351,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> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Εικονίδιο σύμπτυξης"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Εικονίδιο ανάπτυξης"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ή"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Πλοήγηση με το πληκτρολόγιο"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Μάθετε συντομεύσεις πληκτρολογίου"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Πλοήγηση με την επιφάνεια αφής"</string> @@ -1408,8 +1408,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> @@ -1419,14 +1418,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> @@ -1450,14 +1445,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-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 3f1a40c1a125..3a961e2aeeb2 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Input"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Output"</string> <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> @@ -1293,8 +1291,7 @@ <string name="add" msgid="81036585205287996">"Add"</string> <string name="manage_users" msgid="1823875311934643849">"Manage users"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"This notification does not support dragging to split screen"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Location active"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi unavailable"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string> @@ -1351,8 +1348,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Customise lock screen"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Unlock to customise lock screen"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi not available"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Location active"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera is blocked"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone is blocked"</string> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string> @@ -1408,8 +1406,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Learn touchpad gestures, keyboards shortcuts and more"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Back gesture"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Home gesture"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"To go back, swipe left or right using three fingers anywhere on the touchpad.\n\nYou can also use the keyboard shortcut Action + Esc for this."</string> @@ -1419,14 +1416,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"To go to your home screen at any time, swipe up with three fingers from the bottom of your screen."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Nice!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"You completed the go home gesture."</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">"View recent apps"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Swipe up and hold using three fingers on your touchpad."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Well done!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Action key"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"To access your apps, press the action key on your keyboard."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Congratulations!"</string> @@ -1450,14 +1443,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Swipe up and hold using three fingers. Tap to learn more gestures."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Use your keyboard to view all apps"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Press the action key at any time. Tap to learn more gestures."</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">"Extra dim is now part of the brightness slider"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"You can now make the screen extra dim by lowering the brightness level even further.\n\nSince this feature is now part of the brightness slider, extra dim shortcuts are being removed."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Remove extra dim shortcuts"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Extra dim shortcuts removed"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connectivity"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibility"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilities"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 4ed330e399ff..ba71ccfd4256 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Input"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Output"</string> <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> @@ -1398,6 +1396,7 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string> + <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Drag handle"</string> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 3f1a40c1a125..3a961e2aeeb2 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Input"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Output"</string> <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> @@ -1293,8 +1291,7 @@ <string name="add" msgid="81036585205287996">"Add"</string> <string name="manage_users" msgid="1823875311934643849">"Manage users"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"This notification does not support dragging to split screen"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Location active"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi unavailable"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string> @@ -1351,8 +1348,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Customise lock screen"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Unlock to customise lock screen"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi not available"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Location active"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera is blocked"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone is blocked"</string> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string> @@ -1408,8 +1406,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Learn touchpad gestures, keyboards shortcuts and more"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Back gesture"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Home gesture"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"To go back, swipe left or right using three fingers anywhere on the touchpad.\n\nYou can also use the keyboard shortcut Action + Esc for this."</string> @@ -1419,14 +1416,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"To go to your home screen at any time, swipe up with three fingers from the bottom of your screen."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Nice!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"You completed the go home gesture."</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">"View recent apps"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Swipe up and hold using three fingers on your touchpad."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Well done!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Action key"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"To access your apps, press the action key on your keyboard."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Congratulations!"</string> @@ -1450,14 +1443,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Swipe up and hold using three fingers. Tap to learn more gestures."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Use your keyboard to view all apps"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Press the action key at any time. Tap to learn more gestures."</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">"Extra dim is now part of the brightness slider"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"You can now make the screen extra dim by lowering the brightness level even further.\n\nSince this feature is now part of the brightness slider, extra dim shortcuts are being removed."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Remove extra dim shortcuts"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Extra dim shortcuts removed"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connectivity"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibility"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilities"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 3f1a40c1a125..3a961e2aeeb2 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Input"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Output"</string> <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> @@ -1293,8 +1291,7 @@ <string name="add" msgid="81036585205287996">"Add"</string> <string name="manage_users" msgid="1823875311934643849">"Manage users"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"This notification does not support dragging to split screen"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Location active"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi unavailable"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string> @@ -1351,8 +1348,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Customise lock screen"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Unlock to customise lock screen"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi not available"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Location active"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera is blocked"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone is blocked"</string> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string> @@ -1408,8 +1406,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Learn touchpad gestures, keyboards shortcuts and more"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Back gesture"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Home gesture"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"To go back, swipe left or right using three fingers anywhere on the touchpad.\n\nYou can also use the keyboard shortcut Action + Esc for this."</string> @@ -1419,14 +1416,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"To go to your home screen at any time, swipe up with three fingers from the bottom of your screen."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Nice!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"You completed the go home gesture."</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">"View recent apps"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Swipe up and hold using three fingers on your touchpad."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Well done!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Action key"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"To access your apps, press the action key on your keyboard."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Congratulations!"</string> @@ -1450,14 +1443,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Swipe up and hold using three fingers. Tap to learn more gestures."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Use your keyboard to view all apps"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Press the action key at any time. Tap to learn more gestures."</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">"Extra dim is now part of the brightness slider"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"You can now make the screen extra dim by lowering the brightness level even further.\n\nSince this feature is now part of the brightness slider, extra dim shortcuts are being removed."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Remove extra dim shortcuts"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Extra dim shortcuts removed"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connectivity"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibility"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilities"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index fea4ebf4b774..eb76a7edcb87 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Input"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Output"</string> <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> @@ -1398,6 +1396,7 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string> + <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Drag handle"</string> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index faf6ff86acce..b1d0c23761ff 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -1400,6 +1400,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícono de contraer"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícono de expandir"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navega con el teclado"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprende combinaciones de teclas"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navega con el panel táctil"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index df9af2ab9a49..21b42ad2bfb0 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Añadir"</string> <string name="manage_users" msgid="1823875311934643849">"Gestionar usuarios"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Esta notificación no se puede arrastrar a la pantalla dividida"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Ubicación activa"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi no disponible"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo prioritario"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma añadida"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Personalizar pantalla de bloqueo"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Desbloquea para personalizar la pantalla de bloqueo"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Red Wi-Fi no disponible"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Ubicación activa"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Cámara bloqueada"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Cámara y micrófono bloqueados"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micrófono bloqueado"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icono de contraer"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icono de desplegar"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Desplázate con el teclado"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprende combinaciones de teclas"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Desplázate con el panel táctil"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprende gestos del panel táctil, combinaciones de teclas y más"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto para volver"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto para ir al inicio"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver aplicaciones recientes"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hecho"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atrás"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para volver, desliza con tres dedos hacia la izquierda o la derecha en cualquier parte del panel táctil.\n\nTambién puedes hacerlo con la combinación de teclas asignada + Esc."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para ir a la pantalla de inicio en cualquier momento, desliza hacia arriba con tres dedos desde la parte inferior de la pantalla."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"¡Muy bien!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Has completado el gesto para ir a la pantalla de 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">"Ver aplicaciones recientes"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Desliza tres dedos hacia arriba y mantén pulsado en el panel táctil."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"¡Bien hecho!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Has completado el gesto para ver las aplicaciones recientes."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de acción"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para acceder a tus aplicaciones, pulsa la tecla de acción de tu teclado."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"¡Enhorabuena!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Desliza hacia arriba y mantén pulsado con tres dedos. Toca para aprender a usar más gestos."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Usa el teclado para ver todas las aplicaciones"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pulsa la tecla de acción en cualquier momento. Toca para aprender a usar más gestos."</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">"La atenuación extra ahora forma parte del control deslizante de brillo"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Ahora puedes atenuar aún más tu pantalla reduciendo el nivel de brillo incluso más todavía.\n\nComo esta función ahora forma parte del control deslizante de brillo, se van a quitar los accesos directos de atenuación extra."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Eliminar accesos directos de atenuación extra"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Accesos directos de atenuación extra eliminados"</string> <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> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 5c2e4db0a0ec..c1807ad7d208 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -1398,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ahendamisikoon"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Laiendamisikoon"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"või"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigeerige klaviatuuri abil"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Õppige klaviatuuri otseteid"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigeerige puuteplaadi abil"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 5221cebfd9f2..50a55f921347 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -1398,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tolesteko ikonoa"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Zabaltzeko ikonoa"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"edo"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Nabigatu teklatua erabilita"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Ikasi lasterbideak"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Nabigatu ukipen-panela erabilita"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 0696752c0a1d..8f413c8f859d 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"ورودی"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"برونداد"</string> <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> @@ -1293,8 +1291,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> @@ -1351,8 +1348,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> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"نماد جمع کردن"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"نماد ازهم بازکردن"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"یا"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"پیمایش کردن بااستفاده از صفحهکلید"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"آشنایی با میانبرهای صفحهکلید"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"پیمایش کردن بااستفاده از صفحه لمسی"</string> @@ -1408,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برای این کار میتوانید از میانبر صفحهکلید «کنش + گریز» هم استفاده کنید."</string> @@ -1419,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> @@ -1450,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-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 527d3c963967..f8fa57d72d27 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Lisää"</string> <string name="manage_users" msgid="1823875311934643849">"Ylläpidä käyttäjiä"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Ilmoitus ei tue jaetulle näytölle vetämistä"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Aktiivinen sijainti"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ei ole saatavilla"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Tärkeät-tila"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Hälytys asetettu"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Muokkaa lukitusnäyttöä"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Voit muokata lukitusnäyttöä, kun avaat lukituksen"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi-yhteys ei ole käytettävissä"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Aktiivinen sijainti"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera estetty"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera ja mikrofoni estetty"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofoni estetty"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tiivistyskuvake"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Laajennuskuvake"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"tai"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Siirry käyttämällä näppäimistöä"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Opettele pikanäppäimiä"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Siirry käyttämällä kosketuslevyä"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Opettele kosketuslevyn eleitä, pikanäppäimiä ja muuta"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Takaisin-ele"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Etusivu-ele"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Katso viimeisimmät sovellukset"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Valmis"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Takaisin"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Jos haluat siirtyä takaisin, pyyhkäise kosketuslevyllä vasemmalle tai oikealle kolmella sormella.\n\nVoit myös käyttää pikanäppäinyhdistelmää toimintonäppäin + ESC."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Voit siirtyä aloitusnäytölle milloin tahansa pyyhkäisemällä ylös näytön alareunasta kolmella sormella."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Hienoa!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Olet oppinut aloitusnäytölle palaamiseleen."</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">"Katso viimeisimmät sovellukset"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Pyyhkäise ylös ja pidä kosketuslevyä painettuna kolmella sormella."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Hienoa!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Olet oppinut Katso viimeisimmät sovellukset ‑eleen."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Toimintonäppäin"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Voit käyttää sovelluksia painamalla näppäimistön toimintonäppäintä."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Onnittelut!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Pyyhkäise ylös ja pidä kosketuslevyä painettuna kolmella sormella. Lue lisää eleistä napauttamalla."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Kaikkien sovellusten näkeminen näppäimistön avulla"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Voit painaa toimintonäppäintä milloin tahansa. Lue lisää eleistä napauttamalla."</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">"Erittäin himmeä on nyt osa kirkkauden liukusäädintä"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Voit nyt tehdä näytöstä erittäin himmeän vähentämällä kirkkautta entistäkin enemmän.\n\nKoska tämä ominaisuus on nyt osa kirkkauden liukusäädintä, erittäin himmeä ‑pikanäppäimet poistetaan."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Poista erittäin himmeä ‑pikanäppäimet"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Erittäin himmeä ‑pikanäppäimet poistettu"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Yhteydet"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Saavutettavuus"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Apusovellukset"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index f7753eca8c63..106af39f6d1b 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Ajouter"</string> <string name="manage_users" msgid="1823875311934643849">"Gérer utilisateurs"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Cette notification ne prend pas en charge l\'écran partagé par glissement"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Position active"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi non disponible"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode priorité"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"L\'alarme a été réglée"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Personn. l\'écran de verrouillage"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Déverrouiller pour personnaliser l\'écran de verrouillage"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non accessible"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Position active"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Appareil photo bloqué"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Appareil photo et microphone bloqués"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone bloqué"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icône Réduire"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icône Développer"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviguer à l\'aide de votre clavier"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Apprenez à utiliser les raccourcis-clavier"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviguer à l\'aide de votre pavé tactile"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Apprenez les gestes du pavé tactile, les raccourcis-clavier et bien plus encore"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Geste de retour"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Geste d\'accès à l\'écran d\'accueil"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Afficher les applis récentes"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"OK"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Retour"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Pour revenir en arrière, balayez vers la gauche ou la droite en utilisant trois doigts n\'importe où sur le pavé tactile.\n\nVous pouvez également utiliser le raccourci clavier Action+Échap."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Pour accéder à votre écran d\'accueil à tout moment, balayez l\'écran du bas vers le haut avec trois doigts."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bien!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Vous avez appris le geste de retour à l\'écran d\'accueil."</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">"Afficher les applis récentes"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Balayez l\'écran vers le haut avec trois doigts et maintenez-les en place sur votre pavé tactile."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bon travail!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Vous avez effectué le geste pour afficher les applis récentes."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Touche d\'action"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Pour accéder à vos applis, appuyez sur la touche d\'action de votre clavier."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Félicitations!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Balayez l\'écran vers le haut avec trois doigts et maintenez-les en place. Touchez pour apprendre d\'autres gestes."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Utiliser votre clavier pour afficher toutes les applis"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Appuyez sur la touche d\'action à tout moment. Touchez pour apprendre d\'autres gestes."</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">"La réduction supplémentaire de la luminosité fait désormais partie du curseur de luminosité"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Vous pouvez désormais réduire la luminosité de l\'écran encore plus.\n\nÉtant donné que cette fonctionnalité fait désormais partie du curseur de luminosité, les raccourcis de la réduction supplémentaire de la luminosité sont retirés."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Retirer les raccourcis de la réduction supplémentaire de la luminosité"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Les raccourcis de la réduction supplémentaire de la luminosité ont été retirés"</string> <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> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 8b5214eb5798..ad7a87595cab 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Ajouter"</string> <string name="manage_users" msgid="1823875311934643849">"Gérer utilisateurs"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Impossible de faire glisser cette notification vers l\'écran partagé"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Position active"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi non disponible"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode Prioritaire"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme réglée"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Personnaliser écran verrouillage"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Déverrouillez pour personnaliser l\'écran de verrouillage"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non disponible"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Position active"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Caméra bloquée"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Caméra et micro bloqués"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micro bloqué"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icône Réduire"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icône Développer"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviguer à l\'aide du clavier"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Découvrir les raccourcis clavier"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviguer à l\'aide de votre pavé tactile"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Découvrir les gestes au pavé tactile, les raccourcis clavier et plus encore"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Geste Retour"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Geste Accueil"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Afficher les applis récentes"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"OK"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Retour"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Pour revenir en arrière, balayez vers la gauche ou vers la droite avec trois doigts n\'importe où sur le pavé tactile.\n\nVous pouvez aussi utiliser le raccourci clavier Action+Échap pour cela."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Pour accéder à l\'écran d\'accueil à tout moment, balayez l\'écran du bas vers le haut avec trois doigts."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bravo !"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Vous avez appris le geste pour revenir à l\'écran d\'accueil."</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">"Afficher les applis récentes"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Avec trois doigts, balayez le pavé tactile vers le haut et maintenez la position."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bravo !"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Vous avez appris le geste pour afficher les applis récentes"</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Touche d\'action"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Pour accéder à vos applis, appuyez sur la touche d\'action de votre clavier."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Félicitations !"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Balayez vers le haut en utilisant trois doigts et maintenez. Appuyez pour apprendre d\'autres gestes."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Utilisez votre clavier pour afficher toutes les applis"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Appuyez sur la touche d\'action à tout moment. Appuyez pour apprendre d\'autres gestes."</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">"Luminosité ultra-réduite fait désormais partie du curseur de luminosité"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Vous pouvez désormais rendre l\'écran encore plus sombre en abaissant davantage le niveau de luminosité.\n\nComme cette fonctionnalité fait désormais partie du curseur de luminosité, les raccourcis de luminosité ultra-réduite sont supprimés."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Supprimer les raccourcis de luminosité ultra-réduite"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Raccourcis de luminosité ultra-réduite supprimés"</string> <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> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 799e577708e8..bfe5b58d7f17 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -1398,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona de contraer"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icona de despregar"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navega co teclado"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprende a usar os atallos de teclado"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navega co panel táctil"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index a0732d73812a..5d952ac1f4cd 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"ઇનપુટ"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"આઉટપુટ"</string> <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> @@ -1398,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"\'નાનું કરો\'નું આઇકન"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"\'મોટું કરો\'નું આઇકન"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"અથવા"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"તમારા કીબોર્ડ વડે નૅવિગેટ કરો"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"કીબોર્ડ શૉર્ટકર્ટ જાણો"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"તમારા ટચપૅડ વડે નૅવિગેટ કરો"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 3984f7176252..03028b14b7d1 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"इनपुट"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"आउटपुट"</string> <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> @@ -1398,6 +1396,7 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"छोटा करने का आइकॉन"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"बड़ा करने का आइकॉन"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"या"</string> + <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"खींचकर छोड़ने वाला हैंडल"</string> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"कीबोर्ड का इस्तेमाल करके नेविगेट करें"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"कीबोर्ड शॉर्टकट के बारे में जानें"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"टचपैड का इस्तेमाल करके नेविगेट करें"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 545d1d1af64f..4055e7441675 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Ulaz"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Izlaz"</string> <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> @@ -1293,8 +1291,7 @@ <string name="add" msgid="81036585205287996">"Dodaj"</string> <string name="manage_users" msgid="1823875311934643849">"Upravljanje korisnicima"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Ova obavijest ne podržava povlačenje na podijeljeni 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 nije dostupan"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritetni način rada"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je postavljen"</string> @@ -1351,8 +1348,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Prilagodite zaključavanje zaslona"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Otključajte da biste prilagodili zaključani zaslon"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi nije dostupan"</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">"Kamera je blokirana"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Blokirani su kamera i mikrofon"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokiran"</string> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za sažimanje"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za proširivanje"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Krećite se pomoću tipkovnice"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Saznajte više o tipkovnim prečacima"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Krećite se pomoću dodirne podloge"</string> @@ -1408,8 +1406,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Saznajte više o pokretima za dodirnu podlogu, tipkovnim prečacima i ostalom"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Pokret za povratak"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Pokret za otvaranje početnog zaslona"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Pregled nedavnih aplikacija"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotovo"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Natrag"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Da biste se vratili natrag, s tri prsta prijeđite ulijevo ili udesno bilo gdje na dodirnoj podlozi.\n\nZa to možete upotrijebiti i tipku za radnju tipkovnog prečaca + ESC."</string> @@ -1419,14 +1416,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Da biste u bilo kojem trenutku otvorili početni zaslon, trima prstima prijeđite prema gore od dna zaslona."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Odlično!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Izvršili ste pokret za otvaranje početnog zaslona."</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">"Pregled nedavnih aplikacija"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Prijeđite prema gore trima prstima na dodirnoj podlozi i zadržite pritisak."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Sjajno!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Izvršili ste pokret za prikaz nedavno korištenih aplikacija."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tipka za radnju"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Da biste pristupili svojim aplikacijama, pritisnite tipku za radnje na tipkovnici."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Čestitamo!"</string> @@ -1450,14 +1443,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Prijeđite prema gore trima prstima i zadržite pritisak. Dodirnite da biste naučili više pokreta."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Upotrijebite tipkovnicu za prikaz svih aplikacija"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pritisnite tipku za radnju u bilo kojem trenutku. Dodirnite da biste naučili više pokreta."</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">"Dodatno zatamnjenje sada je dio klizača za svjetlinu"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Zaslon možete dodatno zatamniti daljnjim smanjivanjem razine svjetline.\n\nBudući da je ta značajka sada dio klizača za svjetlinu, prečaci za dodatno zatamnjenje uklanjaju se."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Ukloni prečace za dodatno zatamnjenje"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Uklonjeni su prečaci za dodatno zatamnjenje"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Povezivost"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Pristupačnost"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Uslužni programi"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index e0df7c4aa1a4..685e21930378 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Hozzáadás"</string> <string name="manage_users" msgid="1823875311934643849">"Kezelés"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Az értesítés nem támogatja az osztott képernyőre való áthúzást."</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"A helyinformáció aktív"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"A Wi‑Fi nem áll rendelkezésre"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritás mód"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Ébresztő beállítva"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Lezárási képernyő testreszabása"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Oldja fel a zárolást a lezárási képernyő testreszabásához"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Nem áll rendelkezésre 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">"A helyinformáció aktív"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera letiltva"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera és mikrofon letiltva"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon letiltva"</string> @@ -1400,6 +1398,7 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Összecsukás ikon"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Kibontás ikon"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"vagy"</string> + <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Fogópont"</string> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigáció a billentyűzet segítségével"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Billentyűparancsok megismerése"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigálás az érintőpaddal"</string> @@ -1408,8 +1407,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Érintőpad-kézmozdulatok, billentyűparancsok és egyebek megismerése"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Vissza kézmozdulat"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Kezdőképernyő kézmozdulat"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Legutóbbi alkalmazások megtekintése"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Kész"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Vissza"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"A visszalépéshez csúsztasson három ujjal balra vagy a jobbra az érintőpadon.\n\nEnnek végrehajtásához használhatja az Action + Esc billentyűparancsot is."</string> @@ -1419,14 +1417,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Ha bármikor vissza szeretne térni a kezdőképernyőre, csúsztassa gyorsan felfelé három ujját a képernyő aljáról."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Remek!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Teljesítette a kezdőképernyőre lépés kézmozdulatát."</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">"Legutóbbi alkalmazások megtekintése"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Csúsztasson felfelé három ujjal az érintőpadon, és tartsa lenyomva az ujjait."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Kiváló!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Teljesítette a legutóbbi alkalmazások megtekintésének kézmozdulatát."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Műveletbillentyű"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Az alkalmazásokhoz való hozzáféréshez nyomja meg a billentyűzet műveletbillentyűjét."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Gratulálunk!"</string> @@ -1450,14 +1444,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Gyúsztason felfelé három ujjal, és tartsa lenyomva az ujjait. Koppintson a további kézmozdulatokért."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"A billentyűzet használatával valamennyi alkalmazás megtekinthető"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"A műveletbillentyű bármikor használható. Koppintson a további kézmozdulatokért."</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">"Az extrasötét funkció mostantól része a fényerő-beállítási csúszkának"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Mostantól extrasötétre állíthatja a képernyőt, amivel a korábbinál még jobban csökkentheti a fényerőt.\n\nMivel az extrasötét funkció mostantól a fényerő-szabályozó csúszka része, eltávolítjuk a parancsikonjait."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Az extrasötét funkció parancsikonjainak eltávolítása"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Az extrasötét funkció parancsikonjai eltávolítva"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Kapcsolódás"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Kisegítő lehetőségek"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Segédprogramok"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index db3553a78575..36d3e42791fe 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -1293,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> @@ -1351,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> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ծալել պատկերակը"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ծավալել պատկերակը"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"կամ"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Կողմնորոշվեք ձեր ստեղնաշարի օգնությամբ"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Սովորեք օգտագործել ստեղնային դյուրանցումները"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Կողմնորոշվեք ձեր հպահարթակի օգնությամբ"</string> @@ -1408,8 +1408,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> @@ -1419,14 +1418,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> @@ -1450,14 +1445,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-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 97b0337cb080..a5317258498c 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Tambahkan"</string> <string name="manage_users" msgid="1823875311934643849">"Kelola pengguna"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Notifikasi ini tidak mendukung fitur tarik ke layar terpisah"</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 tidak tersedia"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode prioritas"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm disetel"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Sesuaikan layar kunci"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Buka kunci untuk menyesuaikan layar 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 diblokir"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dan mikrofon diblokir"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon diblokir"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikon ciutkan"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikon luaskan"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"atau"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Menavigasi menggunakan keyboard"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Pelajari pintasan keyboard"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Menavigasi menggunakan touchpad"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Pelajari gestur touchpad, pintasan keyboard, dan lainnya"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gestur kembali"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gestur layar 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 aplikasi terbaru"</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, geser ke kiri atau kanan menggunakan tiga jari di touchpad.\n\nAnda juga dapat menggunakan pintasan keyboard Action + ECS untuk melakukannya."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Untuk membuka layar utama kapan saja, geser ke atas menggunakan tiga jari dari bawah layar Anda."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bagus!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Anda telah menyelesaikan gestur buka layar 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 aplikasi terbaru"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Geser ke atas dan tahan menggunakan tiga jari di touchpad."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bagus!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Anda telah menyelesaikan gestur untuk melihat aplikasi terbaru."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tombol tindakan"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Untuk mengakses aplikasi, tekan tombol tindakan di keyboard."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Selamat!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Geser ke atas dan tahan menggunakan tiga jari. Ketuk untuk mempelajari gestur lainnya."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Gunakan keyboard untuk melihat semua aplikasi"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Tekan tombol tindakan kapan saja. Ketuk untuk mempelajari gestur lainnya."</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">"Ekstra redup kini menjadi bagian dari penggeser kecerahan"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Anda kini dapat membuat layar menjadi ekstra redup dengan menurunkan tingkat kecerahan lebih banyak lagi.\n\nKarena fitur ini kini menjadi bagian dari penggeser kecerahan, pintasan ekstra redup akan dihapus."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Hapus pintasan ekstra redup"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Pintasan ekstra redup dihapus"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Konektivitas"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Aksesibilitas"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilitas"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 7df9b2a9a181..c2ada41cc902 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -1398,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Minnka tákn"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Stækka tákn"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eða"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Flettu með því að nota lyklaborðið"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Kynntu þér flýtilykla"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Flettu með því að nota snertiflötinn"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index f1bbc0a732ff..4ff2eda198fe 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Aggiungi"</string> <string name="manage_users" msgid="1823875311934643849">"Gestisci utenti"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Non è possibile trascinare questa notifica tra le due parti dello schermo diviso"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Posizione attiva"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi non disponibile"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modalità Priorità"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Sveglia impostata"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Personalizza schermata di blocco"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Sblocca per personalizzare la schermata di blocco"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non disponibile"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Posizione attiva"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Videocamera bloccata"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Videocamera e microfono bloccati"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfono bloccato"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona Comprimi"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icona Espandi"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"oppure"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviga usando la tastiera"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Informazioni sulle scorciatoie da tastiera"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviga usando il touchpad"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Scopri gesti con il touchpad, scorciatoie da tastiera e altro ancora"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto Indietro"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto Home"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Visualizza app recenti"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Fine"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Indietro"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Per tornare indietro, scorri verso sinistra o verso destra utilizzando tre dita in un punto qualsiasi del touchpad.\n\nPuoi usare anche la scorciatoia da tastiera Action + Esc per farlo."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Per andare alla schermata Home, scorri verso l\'alto con tre dita dalla parte inferiore dello schermo."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bene!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Hai completato il gesto Vai alla schermata Home."</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">"Visualizza app recenti"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Scorri verso l\'alto e tieni premuto con tre dita sul touchpad."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Ottimo lavoro."</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Hai completato il gesto Visualizza app recenti."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tasto azione"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Per accedere alle tue app, premi il tasto azione sulla tastiera."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Complimenti!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Scorri verso l\'alto e tieni premuto con tre dita. Tocca per scoprire altri gesti."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Usa la tastiera per visualizzare tutte le app"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Premi il tasto azione in qualsiasi momento. Tocca per scoprire altri gesti."</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">"Ora l\'attenuazione extra è nel cursore della luminosità"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Ora puoi usare l\'attenuazione extra per lo schermo abbassando il livello di luminosità ancora di più.\n\nDato che questa funzionalità ora fa parte del cursore della luminosità, le scorciatoie per l\'attenuazione extra vengono rimosse."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Rimuovi scorciatoie attenuazione extra"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Scorciatoie attenuazione extra rimosse"</string> <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> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 2cf4f37f926b..1c212e12a0ea 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -1293,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> @@ -1351,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> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"סמל הכיווץ"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"סמל ההרחבה"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"או"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ניווט באמצעות המקלדת"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"מידע על מקשי קיצור"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ניווט באמצעות לוח המגע"</string> @@ -1408,8 +1408,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> @@ -1419,14 +1418,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> @@ -1450,14 +1445,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-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 56491fda20bd..eda727f21232 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"入力"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"出力"</string> <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> @@ -1293,8 +1291,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> @@ -1351,8 +1348,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> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"閉じるアイコン"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"開くアイコン"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"または"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"キーボードを使用して移動する"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"キーボード ショートカットの詳細"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"タッチパッドを使用して移動する"</string> @@ -1408,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> @@ -1419,14 +1416,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"3 本の指で画面を下から上にスワイプすると、ホーム画面にいつでも移動できます。"</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> @@ -1450,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-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index d3583fa536ea..836bd44b52bd 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"შემავალი"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"გამომავალი"</string> <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> @@ -1293,8 +1291,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> @@ -1351,8 +1348,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> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ხატულის ჩაკეცვა"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ხატულის გაფართოება"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ან"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ნავიგაცია კლავიატურის გამოყენებით"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"კლავიატურის მალსახმობების სწავლა"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ნავიგაცია სენსორული პანელის გამოყენებით"</string> @@ -1408,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> @@ -1419,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> @@ -1450,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-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 391606392366..dc2a618fc396 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -1293,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> @@ -1351,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> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жию белгішесі"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Жаю белгішесі"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"немесе"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Пернетақтамен жұмыс істеңіз"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Перне тіркесімдерін үйреніңіз."</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Сенсорлық тақтамен жұмыс істеңіз"</string> @@ -1408,8 +1408,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> @@ -1419,14 +1418,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> @@ -1450,14 +1445,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-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index c72ee714ad9f..6c15c79fc53e 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"ឧបករណ៍បញ្ចូល"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"ឧបករណ៍បញ្ចេញ"</string> <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> @@ -1398,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"រូបតំណាង \"បង្រួម\""</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"រូបតំណាង \"ពង្រីក\""</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ឬ"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"រុករកដោយប្រើក្ដារចុចរបស់អ្នក"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ស្វែងយល់អំពីផ្លូវកាត់ក្ដារចុច"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"រុករកដោយប្រើផ្ទាំងប៉ះរបស់អ្នក"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index f1873c61f11f..a16f110d0230 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -1398,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ಕುಗ್ಗಿಸುವ ಐಕಾನ್"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ವಿಸ್ತೃತಗೊಳಿಸುವ ಐಕಾನ್"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ಅಥವಾ"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ ಬಳಸಿ ನ್ಯಾವಿಗೇಟ್ ಮಾಡಿ"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಕಲಿಯಿರಿ"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ನಿಮ್ಮ ಟಚ್ಪ್ಯಾಡ್ ಬಳಸಿ ನ್ಯಾವಿಗೇಟ್ ಮಾಡಿ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 3e851a16cddf..622f0fb127b2 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -1293,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> @@ -1351,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> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"접기 아이콘"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"확장 아이콘"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"또는"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"키보드를 사용하여 이동"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"단축키 알아보기"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"터치패드를 사용하여 이동"</string> @@ -1408,8 +1408,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> @@ -1419,14 +1418,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> @@ -1450,14 +1445,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-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 7148a5ba2377..0edb3f82735a 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -1293,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> @@ -1351,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> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жыйыштыруу сүрөтчөсү"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Жайып көрсөтүү сүрөтчөсү"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"же"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Нерселерге баскычтоп аркылуу өтүңүз"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Ыкчам баскычтар тууралуу билип алыңыз"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Нерселерге сенсордук такта аркылуу өтүңүз"</string> @@ -1408,8 +1408,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> @@ -1419,14 +1418,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> @@ -1450,14 +1445,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-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index a5b621886ab6..242d766a7543 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -1398,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ໄອຄອນຫຍໍ້ລົງ"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ໄອຄອນຂະຫຍາຍ"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ຫຼື"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ນຳທາງໂດຍໃຊ້ແປ້ນພິມຂອງທ່ານ"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ສຶກສາຄີລັດ"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ນຳທາງໂດຍໃຊ້ແຜ່ນສຳຜັດຂອງທ່ານ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index e210a999709a..fd625995c44d 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -230,7 +230,7 @@ <string name="face_re_enroll_dialog_title" msgid="6392173708176069994">"Atrakinimo pagal veidą nustatymas"</string> <string name="face_re_enroll_dialog_content" msgid="7353502359464038511">"Norint dar kartą nustatyti atrakinimą pagal veidą, dabartinis veido modelis bus ištrintas.\n\nTurite dar kartą nustatyti šią funkciją, kad galėtumėte atrakinti telefoną pagal veidą."</string> <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Nepavyko nustatyti atrakinimo pagal veidą. Eikite į skiltį „Nustatymai“ ir bandykite dar kartą."</string> - <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Palieskite piršto antspaudo jutiklį"</string> + <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Palieskite piršto atspaudo jutiklį"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Tęskite paspaudę atrakinimo piktogramą"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="5542430577183894219">"Veidas neatpažintas. Naudokite piršto antspaudą."</string> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> @@ -1240,7 +1240,7 @@ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Palieskite, kad sužinotumėte daugiau informacijos"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nenustatyta signalų"</string> <string name="accessibility_bouncer" msgid="5896923685673320070">"įvesti ekrano užraktą"</string> - <string name="accessibility_side_fingerprint_indicator_label" msgid="1673807833352363712">"Palieskite piršto antspaudo jutiklį. Tai yra trumpesnis mygtukas telefono šone"</string> + <string name="accessibility_side_fingerprint_indicator_label" msgid="1673807833352363712">"Palieskite piršto atspaudo jutiklį. Tai yra trumpesnis mygtukas telefono šone"</string> <string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Kontrolinio kodo jutiklis"</string> <string name="accessibility_authenticate_hint" msgid="798914151813205721">"nustatytumėte tapatybę"</string> <string name="accessibility_enter_hint" msgid="2617864063504824834">"pasiektumėte įrenginį"</string> @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Pridėti"</string> <string name="manage_users" msgid="1823875311934643849">"Tvarkyti naudotojus"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Šio pranešimo vilkimas išskaidyto ekrano režimu nepalaikomas"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Vietovė aktyvi"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"„Wi‑Fi“ ryšys nepasiekiamas"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteto režimas"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signalas nustatytas"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Užrakinimo ekrano tinkinimas"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Atrakinę tinkinkite užrakinimo ekraną"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"„Wi-Fi“ ryšys nepasiekiamas"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Vietovė aktyvi"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Fotoaparatas užblokuotas"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Fotoaparatas ir mikrofonas užblokuoti"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonas užblokuotas"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Sutraukimo piktograma"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Išskleidimo piktograma"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"arba"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naršykite naudodamiesi klaviatūra"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Sužinokite apie sparčiuosius klavišus"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naršykite naudodamiesi jutikline dalimi"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Sužinokite jutiklinės dalies gestus, sparčiuosius klavišus ir kt."</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Grįžimo atgal gestas"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Pagrindinio ekrano gestas"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Peržiūrėti naujausias programas"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Atlikta"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Grįžti"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Jei norite grįžti, perbraukite kairėn arba dešinėn trimis pirštais bet kurioje jutiklinės dalies vietoje.\n\nTaip pat galite naudoti šį spartųjį klavišą: veiksmų klavišas + klavišas „Esc“."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Jei norite bet kada pasiekti pagrindinį ekraną, perbraukite aukštyn trim pirštais iš ekrano apačios."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Šaunu!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Atlikote perėjimo į pagrindinį ekraną gestą."</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">"Peržiūrėti naujausias programas"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Jutiklinėje dalyje perbraukite aukštyn trimis pirštais ir palaikykite."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Puiku!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Atlikote naujausių programų peržiūros gestą."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Veiksmų klavišas"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Jei norite pasiekti programas, paspauskite klaviatūros veiksmų klavišą."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Sveikiname!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Perbraukite aukštyn trimis pirštais ir palaikykite. Palieskite, kad sužinotumėte daugiau gestų."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Naudokite klaviatūrą, kad peržiūrėtumėte visas programas"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Bet kuriuo metu paspauskite veiksmų klavišą. Palieskite, kad sužinotumėte daugiau gestų."</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 „Itin blanku“ dabar yra ryškumo šliaužiklio dalis"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Dabar galite padaryti ekraną itin blankų, dar labiau sumažindami ryškumo lygį.\n\nKadangi ši funkcija dabar yra ryškumo šliaužiklio dalis, funkcijos „Itin blanku“ spartieji klavišai bus pašalinti."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Pašalinti funkcijos „Itin blanku“ sparčiuosius klavišus"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Funkcijos „Itin blanku“ spartieji klavišai pašalinti"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Ryšiai"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Pritaikomumas"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Paslaugų programos"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 625da9210410..a6b7570a77e9 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Pievienot"</string> <string name="manage_users" msgid="1823875311934643849">"Pārvaldīt"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Šis paziņojums neatbalsta vilkšanu uz sadalīto ekrānu."</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Atrašanās vietas noteikšana ir aktīva"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi nav pieejams"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritātes režīms"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signāls ir iestatīts"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Pielāgot bloķēšanas ekrānu"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Bloķēšanas ekrāna pielāgošana pēc atbloķēšanas"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi nav pieejams"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Atrašanās vietas noteikšana ir aktīva"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera ir bloķēta"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameras un mikrofona lietošana ir bloķēta"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofons ir bloķēts"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Sakļaušanas ikona"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Izvēršanas ikona"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"vai"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Pārvietošanās, izmantojot tastatūru"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Uzziniet par īsinājumtaustiņiem."</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Pārvietošanās, izmantojot skārienpaliktni"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Uzziniet par skārienpaliktņa žestiem, īsinājumtaustiņiem un citām iespējām."</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Žests pāriešanai atpakaļ"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Žests pāriešanai uz sākumu"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Skatīt nesen izmantotās lietotnes"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gatavs"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atpakaļ"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Lai atgrieztos, ar trīs pirkstiem velciet pa kreisi vai pa labi jebkurā vietā uz skārienpaliktņa.\n\nVarat arī izmantot šim nolūkam īsinājumtaustiņus: darbību taustiņu + Esc."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Lai jebkurā brīdī pārietu uz sākuma ekrānu, ar trim pirkstiem velciet augšup no ekrāna apakšdaļas."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Lieliski!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Jūs sekmīgi veicāt sākuma ekrāna atvēršanas žestu."</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">"Nesen izmantoto lietotņu skatīšana"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Skārienpaliktnī ar trīs pirkstiem velciet augšup un turiet."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Lieliski!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Jūs sekmīgi veicāt nesen izmantoto lietotņu skatīšanas žestu."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Darbību taustiņš"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Lai piekļūtu savām lietotnēm, tastatūrā nospiediet darbību taustiņu."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Apsveicam!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Ar trīs pirkstiem velciet augšup un turiet. Lai apgūtu citus žestus, pieskarieties šeit."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Visu lietotņu skatīšana, izmantojot tastatūru"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Jebkurā laikā varat nospiest darbību taustiņu. Lai apgūtu citus žestus, pieskarieties šeit."</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">"Papildu aptumšošana tagad ir iekļauta spilgtuma slīdnī"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Tagad varat veikt ekrāna papildu aptumšošanu, vēl vairāk samazinot spilgtuma līmeni.\n\nTā kā šī funkcija tagad ir iekļauta spilgtuma slīdnī, papildu aptumšošanas saīsnes tiek noņemtas."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Noņemt papildu aptumšošanas saīsnes"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Papildu aptumšošanas saīsnes ir noņemtas."</string> <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> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index f1aab8437d93..1773e3612771 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Влез"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Излез"</string> <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> @@ -1398,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за собирање"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за проширување"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Движете се со користење на тастатурата"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Научете кратенки од тастатурата"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Движете се со користење на допирната подлога"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 42281ce1294d..05b76d3a3ef9 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"ഇൻപുട്ട്"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"ഔട്ട്പുട്ട്"</string> <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> @@ -1398,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ചുരുക്കൽ ഐക്കൺ"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"വികസിപ്പിക്കൽ ഐക്കൺ"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"അല്ലെങ്കിൽ"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"നിങ്ങളുടെ കീബോർഡ് ഉപയോഗിച്ച് നാവിഗേറ്റ് ചെയ്യുക"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"കീബോർഡ് കുറുക്കുവഴികൾ മനസ്സിലാക്കുക"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"നിങ്ങളുടെ ടച്ച്പാഡ് ഉപയോഗിച്ച് നാവിഗേറ്റ് ചെയ്യുക"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index b861020614a0..7a9a38b8e4d7 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -1398,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Хураах дүрс тэмдэг"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Дэлгэх дүрс тэмдэг"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"эсвэл"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Гараа ашиглан шилжих"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Товчлуурын шууд холбоосыг мэдэж аваарай"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Мэдрэгч самбараа ашиглан шилжээрэй"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index eac5553c8655..e4063f629619 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"इनपुट"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"आउटपुट"</string> <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> @@ -1398,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"कोलॅप्स करा आयकन"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"विस्तार करा आयकन"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"किंवा"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"तुमचा कीबोर्ड वापरून नेव्हिगेट करा"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"कीबोर्ड शॉर्टकट जाणून घ्या"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"तुमचा टचपॅड वापरून नेव्हिगेट करा"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index ab7ae77e021f..710d342f6ed6 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Input"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Output"</string> <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> @@ -1398,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kuncupkan ikon"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Kembangkan ikon"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"atau"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigasi menggunakan papan kekunci anda"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Ketahui pintasan papan kekunci"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigasi menggunakan pad sentuh anda"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 89449f83e0ea..0c9bbe6b9eda 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -1293,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> @@ -1351,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> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"လျှော့ပြရန် သင်္ကေတ"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ပိုပြရန် သင်္ကေတ"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"သို့မဟုတ်"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"သင့်ကီးဘုတ်ကိုသုံး၍ လမ်းညွှန်ခြင်း"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"လက်ကွက်ဖြတ်လမ်းများကို လေ့လာပါ"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"သင့်တာ့ချ်ပက်ကိုသုံး၍ လမ်းညွှန်ခြင်း"</string> @@ -1408,8 +1408,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> @@ -1419,14 +1418,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> @@ -1450,14 +1445,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-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index c9656f25e4a0..a097505043dc 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Legg til"</string> <string name="manage_users" msgid="1823875311934643849">"Brukervalg"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Dette varselet støtter ikke at du drar det til en delt skjerm"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Posisjon er aktiv"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi er utilgjengelig"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteringsmodus"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmen er stilt inn"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Tilpass låseskjermen"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Du må låse opp enheten for å tilpasse låseskjermen"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi er ikke tilgjengelig"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Posisjon er aktiv"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kameraet er blokkert"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameraet og mikrofonen er blokkert"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonen er blokkert"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Skjul-ikon"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Vis-ikon"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviger med tastaturet"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Lær deg hurtigtaster"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviger med styreflaten"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Lær deg styreflatebevegelser, hurtigtaster med mer"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Tilbakebevegelse"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Startskjermbevegelse"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Se nylige apper"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Ferdig"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gå tilbake"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"For å gå tilbake, sveip mot høyre eller venstre med tre fingre hvor som helst på styreflaten.\n\nDu kan også gjøre dette med hurtigtasten Action + Esc."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"For å gå til startskjermen, sveip opp med tre fingre fra bunnen av skjermen når som helst."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bra!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Du har fullført bevegelsen for å gå til startskjermen."</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">"Se nylige apper"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Sveip opp og hold med tre fingre på styreflaten."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bra jobbet!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du har fullført bevegelsen for å se nylige apper."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Handlingstast"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"For å åpne appene dine, trykk på handlingstasten på tastaturet."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Gratulerer!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Sveip opp og hold med tre fingre. Trykk for å lære flere bevegelser."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Bruk tastaturet for å se alle apper"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Trykk på handlingstasten når som helst. Trykk for å lære flere bevegelser."</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 ekstra dimming en del av glidebryteren for lysstyrke"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Nå kan du gjøre skjermen ekstra dimmet ved å redusere lysstyrken enda mer.\n\nSiden denne funksjonen nå er en del av glidebryteren for lysstyrke, fjernes snarveiene for ekstra dimming."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Fjern snarveiene for ekstra dimming"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Snarveiene for ekstra dimming er fjernet"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Tilkobling"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Tilgjengelighet"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Systemverktøy"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 16dd82f86a41..e2ae7b9717ca 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"इन्पुट"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"आउटपुट"</string> <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> @@ -1398,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"\"कोल्याप्स गर्नुहोस्\" आइकन"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"\"एक्स्पान्ड गर्नुहोस्\" आइकन"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"वा"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"किबोर्ड प्रयोग गरी नेभिगेट गर्नुहोस्"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"किबोर्डका सर्टकटहरू प्रयोग गर्न सिक्नुहोस्"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"टचप्याड प्रयोग गरी नेभिगेट गर्नुहोस्"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index b10c2033d259..9681f1e94c95 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Invoer"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Uitvoer"</string> <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> @@ -1293,8 +1291,7 @@ <string name="add" msgid="81036585205287996">"Toevoegen"</string> <string name="manage_users" msgid="1823875311934643849">"Gebruikers beheren"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Deze melding biedt geen ondersteuning voor slepen naar het gesplitste scherm"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Locatie actief"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wifi niet beschikbaar"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteitsmodus"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wekker gezet"</string> @@ -1351,8 +1348,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Vergrendelscherm aanpassen"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Ontgrendelen om het vergrendelscherm aan te passen"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi niet beschikbaar"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Locatie actief"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera geblokkeerd"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera en microfoon geblokkeerd"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfoon geblokkeerd"</string> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icoon voor samenvouwen"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icoon voor uitvouwen"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"of"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigeren met je toetsenbord"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Leer sneltoetsen die je kunt gebruiken"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigeren met je touchpad"</string> @@ -1408,8 +1406,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Leer meer over onder andere touchpadgebaren en sneltoetsen"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gebaar voor terug"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gebaar voor startscherm"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Recente apps bekijken"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Klaar"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Terug"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Als je wilt teruggaan, swipe je met 3 vingers naar links of rechts op de touchpad.\n\nJe kunt hiervoor ook de sneltoets Actie + ESC gebruiken."</string> @@ -1419,14 +1416,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Swipe met 3 vingers omhoog vanaf de onderkant van het scherm om naar het startscherm te gaan."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Mooi zo!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Je weet nu hoe je het gebaar Naar startscherm maakt."</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">"Recente apps bekijken"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Swipe met 3 vingers omhoog en houd vast op je touchpad."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Goed werk!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Je weet nu hoe je het gebaar Recente apps bekijken maakt."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Actietoets"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Als je toegang tot je apps wilt krijgen, druk je op de actietoets op je toetsenbord."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Gefeliciteerd!"</string> @@ -1450,14 +1443,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Swipe met 3 vingers omhoog en houd vast. Tik voor meer gebaren."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Je toetsenbord gebruiken om alle apps te bekijken"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Druk op de actietoets wanneer je wilt. Tik voor meer gebaren."</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">"Extra dimmen maakt nu deel uit van de schuifregelaar voor helderheid"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Je kunt het scherm nu extra dimmen door het helderheidsniveau nog verder te verlagen.\n\nOmdat deze functie nu deel uitmaakt van de schuifregelaar voor helderheid, worden snelkoppelingen voor extra dimmen verwijderd."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Snelkoppelingen voor extra dimmen verwijderen"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Snelkoppelingen voor extra dimmen verwijderd"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connectiviteit"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Toegankelijkheid"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Hulpprogramma\'s"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 64b2b7caef33..14e84901a081 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -1398,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ଆଇକନକୁ ସଙ୍କୁଚିତ କରନ୍ତୁ"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ଆଇକନକୁ ବିସ୍ତାର କରନ୍ତୁ"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"କିମ୍ବା"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ଆପଣଙ୍କ କୀବୋର୍ଡ ବ୍ୟବହାର କରି ନାଭିଗେଟ କରନ୍ତୁ"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"କୀବୋର୍ଡ ସର୍ଟକଟଗୁଡ଼ିକ ବିଷୟରେ ଜାଣନ୍ତୁ"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ଆପଣଙ୍କ ଟଚପେଡ ବ୍ୟବହାର କରି ନାଭିଗେଟ କରନ୍ତୁ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index dda36f7b657d..8e7ed22ec4f5 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -1398,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ਪ੍ਰਤੀਕ ਨੂੰ ਸਮੇਟੋ"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ਪ੍ਰਤੀਕ ਦਾ ਵਿਸਤਾਰ ਕਰੋ"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ਜਾਂ"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ਆਪਣੇ ਕੀ-ਬੋਰਡ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਨੈਵੀਗੇਟ ਕਰੋ"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ ਬਾਰੇ ਜਾਣੋ"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ਆਪਣੇ ਟੱਚਪੈਡ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਨੈਵੀਗੇਟ ਕਰੋ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index c1cdb58ebab1..287ecd37fdf5 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Urządzenie wejściowe"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Urządzenie wyjściowe"</string> <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> @@ -1293,8 +1291,7 @@ <string name="add" msgid="81036585205287996">"Dodaj"</string> <string name="manage_users" msgid="1823875311934643849">"Zarządzaj użytkownikami"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"To powiadomienie nie obsługuje dzielenia ekranu przez przeciąganie."</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Lokalizacja jest aktywna"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Sieć Wi‑Fi niedostępna"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Tryb priorytetowy"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm ustawiony"</string> @@ -1351,8 +1348,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Dostosuj ekran blokady"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Odblokuj, aby dostosować ekran blokady"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Sieć Wi-Fi jest niedostępna"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Lokalizacja jest aktywna"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera jest zablokowana"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon są zablokowane"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon jest zablokowany"</string> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zwijania"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozwijania"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"lub"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Nawiguj za pomocą klawiatury"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Dowiedz się więcej o skrótach klawiszowych"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Nawiguj za pomocą touchpada"</string> @@ -1408,8 +1406,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Poznaj gesty na touchpada, skróty klawiszowe i inne funkcje"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gest przejścia wstecz"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gest przejścia na ekran główny"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Wyświetlanie ostatnich aplikacji"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotowe"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Wróć"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Aby przejść wstecz, przesuń 3 palcami w lewo lub w prawo w dowolnym miejscu touchpada.\n\nMożesz też użyć do tego skrótu klawiszowego Action + ESC."</string> @@ -1419,14 +1416,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Aby w dowolnym momencie wyświetlić ekran główny, przesuń od dołu ekranu w górę 3 palcami."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Super!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Gest przechodzenia na ekran główny został opanowany."</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">"Wyświetlanie ostatnich aplikacji"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Przesuń w górę za pomocą 3 palców na touchpadzie i przytrzymaj."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Brawo!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Znasz już gest wyświetlania ostatnio używanych aplikacji."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Klawisz działania"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Aby uzyskać dostęp do aplikacji, naciśnij klawisz działania na klawiaturze."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Gratulacje!"</string> @@ -1450,14 +1443,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Przesuń w górę za pomocą 3 palców i przytrzymaj. Kliknij, aby poznać więcej gestów."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Wyświetlanie wszystkich aplikacji za pomocą klawiatury"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Naciśnij klawisz działania w dowolnym momencie. Kliknij, aby poznać więcej gestów."</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">"Dodatkowe przyciemnienie jest teraz częścią suwaka jasności"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Możesz teraz dodatkowo przyciemnić ekran, jeszcze bardziej zmniejszając poziom jasności.\n\nTa funkcja jest teraz częścią suwaka jasności, więc skróty do dodatkowego przyciemniania zostaną usunięte."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Usuń skróty do dodatkowego przyciemnienia"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Skróty do dodatkowego przyciemnienia zostały usunięte"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Łączność"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Ułatwienia dostępu"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Narzędzia"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index fe90562eaf22..408ffcbac092 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Entrada"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Saída"</string> <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> @@ -1293,8 +1291,7 @@ <string name="add" msgid="81036585205287996">"Adicionar"</string> <string name="manage_users" msgid="1823875311934643849">"Gerenciar usuários"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Esta notificação não pode ser arrastada para a tela dividida"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Localização ativa"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi indisponível"</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">"Alarme definido"</string> @@ -1351,8 +1348,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Personalizar a tela de bloqueio"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Desbloqueie para personalizar a tela de bloqueio"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi indisponível"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Localização ativa"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Câmara bloqueada"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Câmera e microfone bloqueados"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfone bloqueado"</string> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone \"Fechar\""</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone \"Abrir\""</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navegue usando o teclado"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprenda atalhos do teclado"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navegue usando o touchpad"</string> @@ -1408,8 +1406,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprenda gestos do touchpad, atalhos do teclado e muito mais"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto de volta"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto de início"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver os apps recentes"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Concluído"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para voltar, deslize para a esquerda ou direita usando 3 dedos em qualquer lugar do touchpad.\n\nVocê também pode usar o atalho de teclado Ação + ESC."</string> @@ -1419,14 +1416,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para acessar sua tela inicial a qualquer momento, deslize de baixo para cima na tela com três dedos."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Legal!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Você concluiu o gesto para acessar a tela inicial."</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">"Ver os apps recentes"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Deslize para cima e pressione com 3 dedos no touchpad."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Muito bem!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Você concluiu o gesto para ver os apps recentes."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de ação"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para acessar os apps, pressione a tecla de ação no teclado."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Parabéns!"</string> @@ -1450,14 +1443,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Deslize para cima e pressione com três dedos. Toque para aprender outros gestos."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Use o teclado para ver todos os apps"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pressione a tecla de ação a qualquer momento. Toque para aprender outros gestos."</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">"O recurso Escurecer a tela agora faz parte do controle deslizante de brilho"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Agora, é possível usar o recurso Escurecer a tela mostrado na parte de cima, que diminui ainda mais o nível de brilho.\n\nComo esse recurso agora faz parte do controle deslizante de brilho, os atalhos de Escurecer a tela estão sendo removidos."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Remover atalhos de Escurecer a tela"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Atalhos de Escurecer a tela removidos"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Conectividade"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Acessibilidade"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilitários"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 3e9d7824f6fa..2e0bb56ab230 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Adicionar"</string> <string name="manage_users" msgid="1823875311934643849">"Gerir utilizadores"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Esta notificação não pode ser arrastada para o ecrã dividido"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Localização ativa"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi indisponível"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo Prioridade"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme definido"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Personalizar ecrã de bloqueio"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Desbloqueie para personalizar o ecrã de bloqueio"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi indisponível"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Localização ativa"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Câmara bloqueada"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Câmara e microfone bloqueados"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfone bloqueado"</string> @@ -1400,6 +1398,7 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone de reduzir"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone de expandir"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string> + <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Indicador para arrastar"</string> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navegue com o teclado"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprenda atalhos de teclado"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navegue com o touchpad"</string> @@ -1408,8 +1407,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprenda gestos do touchpad, atalhos de teclado e muito mais"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto para retroceder"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto para aceder ao ecrã principal"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver apps recentes"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Concluir"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para retroceder, deslize rapidamente para a esquerda ou direita com 3 dedos em qualquer parte do touchpad.\n\nPara o fazer, também pode usar o atalho de teclado Ação + ESC."</string> @@ -1419,14 +1417,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para aceder ao ecrã principal em qualquer altura, deslize rapidamente com 3 dedos de baixo para cima no ecrã."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Boa!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Concluiu o gesto para aceder ao ecrã principal."</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">"Ver apps recentes"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Deslize rapidamente para cima e mantenha premido com 3 dedos no touchpad."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Muito bem!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Concluiu o gesto para ver as apps recentes."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de ação"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para aceder às suas apps, prima a tecla de ação no teclado."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Parabéns!"</string> @@ -1450,14 +1444,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Deslize rapidamente para cima e mantenha premido com 3 dedos. Toque para aprender mais gestos."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Use o teclado para ver todas as apps"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Prima a tecla de ação em qualquer altura. Toque para aprender mais gestos."</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">"Agora, o escurecimento extra faz parte do controlo de deslize"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Agora, pode tornar o ecrã ainda mais escuro reduzindo ainda mais o nível de brilho.\n\nUma vez que esta funcionalidade faz agora parte do controlo de deslize do brilho, os atalhos de escurecimento extra vão ser removidos."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Remover atalhos de escurecimento extra"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Atalhos de escurecimento extra removidos"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Conetividade"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Acessibilidade"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilitários"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index fe90562eaf22..408ffcbac092 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Entrada"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Saída"</string> <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> @@ -1293,8 +1291,7 @@ <string name="add" msgid="81036585205287996">"Adicionar"</string> <string name="manage_users" msgid="1823875311934643849">"Gerenciar usuários"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Esta notificação não pode ser arrastada para a tela dividida"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Localização ativa"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi indisponível"</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">"Alarme definido"</string> @@ -1351,8 +1348,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Personalizar a tela de bloqueio"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Desbloqueie para personalizar a tela de bloqueio"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi indisponível"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Localização ativa"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Câmara bloqueada"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Câmera e microfone bloqueados"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfone bloqueado"</string> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone \"Fechar\""</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone \"Abrir\""</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navegue usando o teclado"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprenda atalhos do teclado"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navegue usando o touchpad"</string> @@ -1408,8 +1406,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprenda gestos do touchpad, atalhos do teclado e muito mais"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto de volta"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto de início"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver os apps recentes"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Concluído"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para voltar, deslize para a esquerda ou direita usando 3 dedos em qualquer lugar do touchpad.\n\nVocê também pode usar o atalho de teclado Ação + ESC."</string> @@ -1419,14 +1416,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para acessar sua tela inicial a qualquer momento, deslize de baixo para cima na tela com três dedos."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Legal!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Você concluiu o gesto para acessar a tela inicial."</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">"Ver os apps recentes"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Deslize para cima e pressione com 3 dedos no touchpad."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Muito bem!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Você concluiu o gesto para ver os apps recentes."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de ação"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para acessar os apps, pressione a tecla de ação no teclado."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Parabéns!"</string> @@ -1450,14 +1443,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Deslize para cima e pressione com três dedos. Toque para aprender outros gestos."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Use o teclado para ver todos os apps"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pressione a tecla de ação a qualquer momento. Toque para aprender outros gestos."</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">"O recurso Escurecer a tela agora faz parte do controle deslizante de brilho"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Agora, é possível usar o recurso Escurecer a tela mostrado na parte de cima, que diminui ainda mais o nível de brilho.\n\nComo esse recurso agora faz parte do controle deslizante de brilho, os atalhos de Escurecer a tela estão sendo removidos."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Remover atalhos de Escurecer a tela"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Atalhos de Escurecer a tela removidos"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Conectividade"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Acessibilidade"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilitários"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 1279ca224618..443d28aa04ed 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Adaugă"</string> <string name="manage_users" msgid="1823875311934643849">"Gestionează"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Notificarea nu acceptă tragerea pe ecranul împărțit"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Locație activă"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi indisponibil"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modul Prioritate"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmă setată"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Personalizează ecranul de blocare"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Deblochează pentru a personaliza ecranul de blocare"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Conexiune Wi-Fi indisponibilă"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Locație activă"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera foto a fost blocată"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera foto și microfonul sunt blocate"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfonul a fost blocat"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Pictograma de restrângere"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Pictograma de extindere"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"sau"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navighează folosind tastatura"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Învață comenzile rapide de la tastatură"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navighează folosind touchpadul"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Învață gesturi pentru touchpad, comenzi rapide de la tastatură și altele"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gestul Înapoi"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gestul Ecran de pornire"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Vezi aplicațiile recente"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gata"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Înapoi"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Pentru a reveni, glisează spre stânga sau spre dreapta cu trei degete oriunde pe touchpad.\n\nPoți folosi și comanda rapidă de la tastatură Action + ESC pentru aceasta."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Pentru a accesa oricând ecranul de pornire, glisează în sus cu trei degete din partea de jos a ecranului"</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bravo!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Ai finalizat gestul „accesează ecranul de pornire”."</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">"Vezi aplicațiile recente"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Glisează în sus și ține apăsat cu trei degete pe touchpad."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Excelent!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Ai finalizat gestul pentru afișarea aplicațiilor recente."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Tasta de acțiuni"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Pentru a accesa aplicațiile, apasă tasta de acțiuni de pe tastatură."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Felicitări!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Glisează în sus și ține apăsat cu trei degete. Atinge ca să înveți mai multe gesturi."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Folosește-ți tastatura ca să vezi toate aplicațiile"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Apasă oricând tasta de acțiuni. Atinge ca să înveți mai multe gesturi."</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">"Luminozitatea redusă suplimentar face acum parte din glisorul de luminozitate"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Poți reduce suplimentar luminozitatea ecranului dacă scazi nivelul de luminozitate.\n\nÎntrucât această funcție este acum disponibilă în glisorul de luminozitate, comenzile rapide de luminozitate redusă suplimentar sunt eliminate."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Elimină comenzile rapide de luminozitate redusă suplimentar"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"S-au eliminat comenzile rapide de luminozitate redusă suplimentar"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Conectivitate"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accesibilitate"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilitare"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 557265852d32..66d78087d792 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Устройства ввода"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Устройства вывода"</string> <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> @@ -1293,8 +1291,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> @@ -1351,8 +1348,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> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок \"Свернуть\""</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок \"Развернуть\""</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навигация с помощью клавиатуры"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Узнайте о сочетаниях клавиш."</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навигация с помощью сенсорной панели"</string> @@ -1408,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> @@ -1419,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> @@ -1450,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-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index b0e322edeae3..7dd43a95ebf1 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"ආදානය"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"ප්රතිදානය"</string> <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> @@ -1398,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"හැකුළුම් නිරූපකය"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"දිගහැරීම් නිරූපකය"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"හෝ"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ඔබේ යතුරු පුවරුව භාවිතයෙන් සංචාලනය කරන්න"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"යතුරුපුවරු කෙටිමං ඉගෙන ගන්න"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ඔබේ ස්පර්ශ පෑඩ් භාවිතයෙන් සංචාලනය කරන්න"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 50d98288df2b..a13a1b45f0af 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Pridať"</string> <string name="manage_users" msgid="1823875311934643849">"Spravovať použ."</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Toto upozornenie nepodporuje presun na rozdelenú obrazovku"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Aktívne miesto"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi nie je k dispozícii"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Režim priority"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Budík je nastavený"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Prispôsobiť uzamknutú obrazovku"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Uzamknutú obrazovku môžete prispôsobiť po odomknutí"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi‑Fi nie je k dispozícii"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Aktívne miesto"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokovaná"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera a mikrofón sú blokované"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofón je blokovaný"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zbalenia"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozbalenia"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"alebo"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Prechádzajte pomocou klávesnice"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Naučte sa klávesové skratky"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Prechádzajte pomocou touchpadu"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Naučte sa gestá touchpadu, klávesové skratky a ďalšie funkcie"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto prechodu späť"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto prechodu domov"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Zobrazenie nedávnych aplikácií"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hotovo"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Prejsť späť"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Ak chcete prejsť späť, potiahnite kdekoľvek na touchpade troma prstami doľava alebo doprava.\n\nMôžete použiť aj klávesovú skratku, teda akčný kláves + ESC."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Na plochu môžete kedykoľvek prejsť potiahnutím troma prstami zdola obrazovky."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Výborne!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Dokončili ste gesto na prechod na plochu."</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">"Zobrazenie nedávnych aplikácií"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Potiahnite troma prstami na touchpade nahor a pridržte ich."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Skvelé!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Dokončili ste gesto na zobrazenie nedávnych aplikácií."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Akčný kláves"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Ak chcete získať prístup k aplikáciám, stlačte na klávesnici akčný kláves."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Blahoželáme!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Potiahnite troma prstami nahor a pridržte ich. Viac o gestách sa dozviete klepnutím."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Zobrazte si všetky aplikácie pomocou klávesnice"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Akčný kláves môžete stlačiť kedykoľvek. Viac o gestách sa dozviete klepnutím."</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">"Mimoriadne stmavenie je teraz súčasťou posúvača jasu"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Teraz môžete obrazovku mimoriadne stmaviť ešte ďalším znížením úrovne jasu.\n\nTáto funkcia je teraz súčasťou posúvača jasu, preto odstraňujeme skratky mimoriadneho stmavenia."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Odstrániť skratky mimoriadneho stmavenia"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Skratky mimoriadneho stmavenia boli odstránené"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Pripojenie"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Dostupnosť"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utility"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 6452a54dcdf7..653bb586200d 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Vhodno"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Izhodno"</string> <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> @@ -1398,6 +1396,7 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za strnitev"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za razširitev"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ali"</string> + <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ročica za vlečenje"</string> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Krmarjenje s tipkovnico"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Učenje bližnjičnih tipk"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Krmarjenje s sledilno ploščico"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 7ea8044ce1a8..00484a7b737d 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -1398,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona e palosjes"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona e zgjerimit"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ose"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigo duke përdorur tastierën tënde"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Mëso shkurtoret e tastierës"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigo duke përdorur bllokun me prekje"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 1930eade82b4..3a940c1155f6 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Улаз"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Излаз"</string> <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> @@ -1293,8 +1291,7 @@ <string name="add" msgid="81036585205287996">"Додај"</string> <string name="manage_users" msgid="1823875311934643849">"Управљаj корисницима"</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">"WiFi није доступан"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Приоритетни режим"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Аларм је подешен"</string> @@ -1351,8 +1348,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">"WiFi није доступан"</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> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за скупљање"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за проширивање"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Крећите се помоћу тастатуре"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Сазнајте више о тастерским пречицама"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Крећите се помоћу тачпеда"</string> @@ -1408,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Можете да користите и тастерску пречицу Alt + ESC за ово."</string> @@ -1419,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> @@ -1450,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-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index a4abb771f9fb..23f476ddad93 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Lägg till"</string> <string name="manage_users" msgid="1823875311934643849">"Välj användare"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Det går inte att dra den här aviseringen till delad skärm"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Aktiv plats"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wifi är inte tillgängligt"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritetsläge"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmet är aktiverat"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Anpassa låsskärmen"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Lås upp för att anpassa låsskärmen"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi är inte tillgängligt"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Aktiv plats"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kameran är blockerad"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameran och mikrofonen är blockerade"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonen är blockerad"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikonen Komprimera"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikonen Utöka"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigera med tangentbordet"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Lär dig kortkommandon"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigera med styrplattan"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Lär dig rörelser för styrplattan, kortkommandon med mera"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Tillbaka-rörelse"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Rörelse för att öppna startskärmen"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Se de senaste apparna"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Klar"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Tillbaka"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Gå tillbaka genom att svepa åt vänster eller höger med tre fingrar var som helst på styrplattan.\n\nDu kan även använda kortkommandot Åtgärd + Esc."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Öppna startskärmen när som helst genom att svepa uppåt med tre fingrar från skärmens nederkant."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bra!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Du är klar med rörelsen för att öppna startskärmen."</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">"Se de senaste apparna"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Svep uppåt med tre fingrar på styrplattan och håll kvar."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bra jobbat!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du är klar med rörelsen för att se de senaste apparna."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Åtgärdstangent"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Tryck på åtgärdstangenten på tangentbordet för att komma åt dina appar."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Grattis!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Svep uppåt med tre fingrar och håll kvar. Tryck för att lära dig fler rörelser."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Använd tangentbordet för att se alla appar"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Tryck på åtgärdstangenten när som helst. Tryck för att lära dig fler rörelser."</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">"Extradimmat är nu en del av skjutreglaget för ljusstyrka"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Nu kan du göra skärmen extradimmad genom att sänka ljusstyrkan ännu mer.\n\nEftersom den här funktionen nu är en del av skjutreglaget för ljusstyrka tas kortkommandon för extradimmat bort."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Ta bort kortkommandon för extradimmat"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Kortkommandon för extradimmat har tagits bort"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Anslutning"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Tillgänglighet"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Verktyg"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 67ad0b50ba1d..dee6a5f49879 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Weka"</string> <string name="manage_users" msgid="1823875311934643849">"Dhibiti watumiaji"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Arifa hii haitumii utaratibu wa kuburuta ili kugawa skrini"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Inatumia data ya mahali ulipo"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi haipatikani"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Hali ya kipaumbele"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Kengele imewekwa"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Wekea mapendeleo skrini iliyofungwa"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Fungua ili uweke mapendeleo ya skrini iliyofungwa"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi haipatikani"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Inatumia data ya mahali ulipo"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera imezuiwa"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera na maikrofoni zimezuiwa"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Maikrofoni imezuiwa"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kunja aikoni"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Panua aikoni"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"au"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Kusogeza kwa kutumia kibodi yako"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Jifunze kuhusu mikato ya kibodi"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Kusogeza kwa kutumia padi yako ya kugusa"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Jifunze kuhusu miguso ya padi ya kugusa, mikato ya kibodi na mengineyo"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Ishara ya kurudi nyuma"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Mguso wa kurudi kwenye skrini ya kwanza"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Angalia programu za hivi majuzi"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Nimemaliza"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Rudi nyuma"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Telezesha vidole vitatu kushoto au kulia mahali popote kwenye padi ya kugusa ili urudi nyuma.\n\nUnaweza pia kutumia mikato ya kibodi ya Kitendo pamoja na ESC kutekeleza kitendo hiki."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Ili uende kwenye skrini ya kwanza wakati wowote, telezesha vidole vitatu juu kutoka sehemu ya chini ya skrini yako."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Safi!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Umeweka ishara ya kwenda kwenye skrini ya kwanza."</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">"Angalia programu za hivi majuzi"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Telezesha vidole vitatu juu kisha ushikilie kwenye padi yako ya kugusa."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Kazi nzuri!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Umekamilisha mafunzo ya mguso wa kuangalia programu za hivi majuzi."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Kitufe cha vitendo"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Bonyeza kitufe cha vitendo kwenye kibodi yako ili ufikie programu zako."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Hongera!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Telezesha vidole vitatu juu na ushikilie. Gusa ili upate maelezo kuhusu miguso zaidi."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Kutumia kibodi yako kuangalia programu zote"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Bonyeza kitufe cha vitendo wakati wowote. Gusa ili upate maelezo kuhusu miguso zaidi."</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">"Sasa kipunguza mwangaza zaidi ni sehemu ya kitelezi cha mwangaza"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Sasa unaweza kupunguza kiwango cha mwangaza wa skrini hata zaidi.\n\nKwa kuwa kipengele hiki sasa ni sehemu ya kitelezi cha mwangaza, njia za mkato za kipunguza mwangaza zaidi zinaondolewa."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Ondoa njia za mkato za kipunguza mwangaza zaidi"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Njia za mkato za kipunguza mwangaza zaidi zimeondolewa"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Muunganisho"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Ufikivu"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Vipengee"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index c574912d17d4..92da9089a8f4 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -1293,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> @@ -1351,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> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"சுருக்குவதற்கான ஐகான்"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"விரிவாக்குவதற்கான ஐகான்"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"அல்லது"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"கீபோர்டைப் பயன்படுத்திச் செல்லுதல்"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"கீபோர்டு ஷார்ட்கட்கள் குறித்துத் தெரிந்துகொள்ளுங்கள்"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"டச்பேடைப் பயன்படுத்திச் செல்லுதல்"</string> @@ -1408,8 +1408,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> @@ -1419,14 +1418,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> @@ -1450,14 +1445,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-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index f4bf055599bd..16500ed9d415 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"ఇన్పుట్"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"అవుట్పుట్"</string> <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> @@ -1398,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"కుదించండి చిహ్నం"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"విస్తరించండి చిహ్నం"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"లేదా"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"మీ కీబోర్డ్ ఉపయోగించి నావిగేట్ చేయండి"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"కీబోర్డ్ షార్ట్కట్ల గురించి తెలుసుకోండి"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"మీ టచ్ప్యాడ్ని ఉపయోగించి నావిగేట్ చేయండి"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 42248317ffe5..6bfc9f9be3d1 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"อินพุต"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"เอาต์พุต"</string> <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> @@ -1293,8 +1291,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> @@ -1351,8 +1348,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> @@ -1400,6 +1396,7 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ไอคอนยุบ"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ไอคอนขยาย"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"หรือ"</string> + <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"แฮนเดิลการลาก"</string> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ไปยังส่วนต่างๆ โดยใช้แป้นพิมพ์"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"ดูข้อมูลเกี่ยวกับแป้นพิมพ์ลัด"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ไปยังส่วนต่างๆ โดยใช้ทัชแพด"</string> @@ -1408,8 +1405,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> @@ -1419,14 +1415,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ใช้ 3 นิ้วปัดขึ้นจากด้านล่างของหน้าจอเพื่อไปที่หน้าจอหลักได้ทุกเมื่อ"</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> @@ -1450,14 +1442,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-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 5145f26a886a..4f3819b161ee 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"Input"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"Output"</string> <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> @@ -1293,8 +1291,7 @@ <string name="add" msgid="81036585205287996">"Magdagdag"</string> <string name="manage_users" msgid="1823875311934643849">"Pamahalaan ang mga user"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Hindi sinusuportahan ng notification na ito ang pag-drag sa split screen"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Aktibo ang lokasyon"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Hindi available ang Wi‑Fi"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Nakatakda ang alarm"</string> @@ -1351,8 +1348,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"I-customize ang lock screen"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"I-unlock para i-customize ang lock screen"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Hindi available ang 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">"Aktibo ang lokasyon"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Naka-block ang camera"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Naka-block ang camera at mikropono"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Naka-block ang mikropono"</string> @@ -1400,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"I-collapse ang icon"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"I-expand ang icon"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Mag-navigate gamit ang iyong keyboard"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Matuto ng mga keyboard shortcut"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Mag-navigate gamit ang iyong touchpad"</string> @@ -1408,8 +1406,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Matuto ng mga galaw sa touchpad, keyboard shortcut, at higit pa"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Galaw para bumalik"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Galaw para sa Home"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Tingnan ang mga kamakailang app"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Tapos na"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Bumalik"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para bumalik, mag-swipe pakaliwa o pakanan gamit ang tatlong daliri saanman sa touchpad.\n\nPuwede mo ring gamitin ang keyboard shortcut na Action + ESC para dito."</string> @@ -1419,14 +1416,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para pumunta sa iyong home screen anumang oras, mag-swipe pataas gamit ang tatlong daliri mula sa ibaba ng screen. mo."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Magaling!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Nakumpleto mo na ang galaw para pumunta sa home."</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">"Tingnan ang mga kamakailang app"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Mag-swipe pataas at i-hold gamit ang tatlong daliri sa iyong touchpad."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Magaling!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Nakumpleto mo ang galaw sa pag-view ng mga kamakailang app."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Action key"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para ma-access ang iyong mga app, pindutin ang action key sa keyboard mo."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Binabati kita!"</string> @@ -1450,14 +1443,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Mag-swipe pataas at i-hold gamit ang tatlong daliri. I-tap para matuto pa tungkol sa mga galaw."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Gamitin ang iyong keyboard para tingnan ang lahat ng app"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pindutin ang action key kahit kailan. I-tap para matuto pa tungkol sa mga galaw."</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">"Bahagi na ng slider ng liwanag ang extra dim"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Puwede mo nang gawing extra dim ang screen sa pamamagitan ng pagbababa pa sa antas ng liwanag .\n\nDahil bahagi na ang feature na ito ng slider ng liwanag, aalisin na ang mga shortcut sa extra dim."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Alisin ang mga shortcut sa extra dim"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Inalis ang mga shortcut sa extra dim"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Pagkakonekta"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibility"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Mga Utility"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 63c9a3c1672d..19fad73cf2c9 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Ekle"</string> <string name="manage_users" msgid="1823875311934643849">"Kullanıcıları yönet"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Bu bildirim bölünmüş ekrana sürüklemeyi desteklemiyor"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Konum etkin"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Kablosuz kullanılamıyor"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Öncelik modu"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm kuruldu"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Kilit ekranını özelleştir"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Kilit ekranını özelleştirmek için kilidi açın"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Kablosuz bağlantı kullanılamıyor"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Konum etkin"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera engellendi"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera ve mikrofon engellendi"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon engellendi"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Daralt simgesi"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Genişlet simgesi"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"veya"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Klavyenizi kullanarak gezinin"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Klavye kısayollarını öğrenin"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Dokunmatik alanınızı kullanarak gezinin"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Dokunmatik alan hareketlerini, klavye kısayollarını ve daha fazlasını öğrenin"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Geri hareketi"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Ana sayfa hareketi"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Son uygulamaları görüntüle"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Bitti"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Geri dön"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Geri dönmek için dokunmatik alanın herhangi bir yerinde üç parmağınızla sola veya sağa kaydırın.\n\nDilerseniz işlem düğmesi + Esc klavye kısayolunu kullanarak da geri dönebilirsiniz."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"İstediğiniz zaman ana ekrana gitmek için üç parmağınızla ekranınızın altından yukarı doğru kaydırın."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Güzel!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Ana ekrana git hareketini 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 uygulamaları görüntüle"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Dokunmatik alanda üç parmağınızla yukarı doğru kaydırıp basılı tutun."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Tebrikler!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Son uygulamaları görüntüleme hareketini tamamladınız."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Eylem tuşu"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Uygulamalarınıza erişmek için klavyenizdeki eylem tuşuna basın."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Tebrikler!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Üç parmağınızla yukarı kaydırıp basılı tutun. Daha fazla hareket öğrenmek için dokunun."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Tüm uygulamaları görüntülemek için klavyenizi kullanın"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"İstediğiniz zaman eylem tuşuna basın. Daha fazla hareket öğrenmek için dokunun."</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">"Ekstra loş özelliği, parlaklık kaydırma çubuğuna eklendi"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Artık parlaklık seviyesini daha da düşürerek ekranı ekstra loş hale getirebilirsiniz.\n\nBu özellik artık parlaklık kaydırma çubuğuna eklendiği için ekstra loş kısayolları kaldırılıyor."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Ekstra loş kısayollarını kaldır"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Ekstra loş kısayolları kaldırıldı"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Bağlantı"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Erişilebilirlik"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Yardımcı programlar"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 98ed6c0470c5..453ce4a9bb58 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -1293,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> @@ -1351,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> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок згортання"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок розгортання"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"або"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навігація за допомогою клавіатури"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Комбінації клавіш: докладніше"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навігація за допомогою сенсорної панелі"</string> @@ -1408,8 +1408,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> @@ -1419,14 +1418,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> @@ -1450,14 +1445,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-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index cd57d52a20aa..9865c8de6290 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -1179,10 +1179,8 @@ <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_input_group_title" msgid="2057057473860783021">"ان پٹ"</string> + <string name="media_output_group_title" msgid="6789001895863332576">"آؤٹ پٹ"</string> <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> @@ -1398,6 +1396,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"آئیکن سکیڑیں"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"آئیکن پھیلائیں"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"یا"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"اپنے کی بورڈ کا استعمال کر کے نیویگیٹ کریں"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"کی بورڈ شارٹ کٹس جانیں"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"اپنے ٹچ پیڈ کا استعمال کر کے نیویگیٹ کریں"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 07faf6a9d41a..cd4cc0dc9681 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Kiritish"</string> <string name="manage_users" msgid="1823875311934643849">"Foyd-ni boshqarish"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Bu bildirishnoma ikkiga ajratilgan ekranda ishlamaydi."</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Joylashuv faol"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ishlamayapti"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Imtiyozli rejim"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signal oʻrnatildi"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Ekran qulfini moslash"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Ekran qulfini sozlash uchun qulfni oching"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi mavjud emas"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Joylashuv faol"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera bloklangan"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera va mikrofon bloklangan"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon bloklangan"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Yigʻish belgisi"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Yoyish belgisi"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"yoki"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Klaviatura yordamida kezing"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Tezkor tugmalar haqida"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Sensorli panel yordamida kezing"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Sensorli panel ishoralari, tezkor tugmalar va boshqalar haqida"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Orqaga qaytish ishorasi"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Asosiy ekran ishorasi"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Oxirgi ilovalarni koʻrish"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Tayyor"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Orqaga qaytish"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Ortga qaytish uchun sensorli panelda uchta barmoqni chapga yoki oʻngga suring.\n\nBuning uchun Action + ESC tezkor tugmalaridan ham foydalanishingiz mumkin."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Istalgan vaqtda bosh ekranga oʻtish uchun ekranning pastidan uchta barmoq bilan tepaga suring."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Yaxshi!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Bosh ekranni ochish ishorasi darsini tamomladingiz."</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">"Oxirgi ilovalarni koʻrish"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Sensorli panelda uchta barmoq bilan tepaga surib, bosib turing."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Barakalla!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Oxirgi ilovalarni koʻrish ishorasini tugalladingiz."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Amal tugmasi"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Ilovalarga kirish uchun klaviaturadagi amal tugmasini bosing"</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Tabriklaymiz!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Uchta barmoq bilan tepaga surib, bosib turing. Boshqa ishoralar bilan tanishish uchun bosing."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Klaviatura orqali barcha ilovalarni koʻrish"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Amal tugmasini istalganda bosing. Boshqa ishoralar bilan tanishish uchun bosing."</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">"Juda xira endi yorqinlik slayderida joylashgan"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Endi yorqinlik darajasini yanada pasaytirish orqali ekranni yanada xiralashtirishingiz mumkin.\n\nBu funksiya yorqinlik slayderiga kiritilgani uchun \"juda xira\" buyruqlari olib tashlanmoqda."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Juda xira buyruqlarini olib tashlash"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Juda xira buyruqlari olib tashlandi"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Aloqa"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Qulayliklar"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Vositalar"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 279fe1ee55ec..28a6900c1a5e 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Thêm"</string> <string name="manage_users" msgid="1823875311934643849">"Quản lý ng.dùng"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Thông báo này không hỗ trợ thao tác kéo để chia đôi màn hình"</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Vị trí đang hoạt động"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Không có Wi‑Fi"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Chế độ ưu tiên"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Đã đặt chuông báo"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Tuỳ chỉnh màn hình khoá"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Mở khoá để tuỳ chỉnh màn hình khoá"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Không có 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">"Vị trí đang hoạt động"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Máy ảnh bị chặn"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Máy ảnh và micrô bị chặn"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micrô bị chặn"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Biểu tượng Thu gọn"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Biểu tượng Mở rộng"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"hoặc"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Di chuyển bằng bàn phím"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Tìm hiểu về phím tắt"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Di chuyển bằng bàn di chuột"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Tìm hiểu về cử chỉ trên bàn di chuột, phím tắt và nhiều mục khác"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Cử chỉ quay lại"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Cử chỉ chuyển đến màn hình chính"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Xem các ứng dụng gần đây"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Xong"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Quay lại"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Để quay lại, hãy dùng 3 ngón tay vuốt sang trái hoặc sang phải ở vị trí bất kỳ trên bàn di chuột.\n\nBạn cũng có thể dùng phím tắt Hành động + ESC cho thao tác này."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Để chuyển đến màn hình chính bất cứ lúc nào, hãy dùng 3 ngón tay vuốt lên từ cuối màn hình lên."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Tốt lắm!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Bạn đã thực hiện xong cử chỉ chuyển đến màn hình chính."</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">"Xem các ứng dụng gần đây"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Dùng 3 ngón tay vuốt lên và giữ trên bàn di chuột."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Tuyệt vời!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Bạn đã hoàn tất cử chỉ xem ứng dụng gần đây."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Phím hành động"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Để truy cập vào các ứng dụng của bạn, hãy nhấn phím hành động trên bàn phím."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Xin chúc mừng!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Dùng 3 ngón tay vuốt lên và giữ. Hãy nhấn để tìm hiểu các cử chỉ khác."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Sử dụng bàn phím để xem tất cả ứng dụng"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Nhấn phím hành động bất cứ lúc nào. Hãy nhấn để tìm hiểu các cử chỉ khác."</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">"Tính năng siêu tối hiện đã có trên thanh trượt điều chỉnh độ sáng"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Giờ đây, bạn có thể giảm thêm độ sáng để làm màn hình trở nên siêu tối.\n\nVì tính năng này hiện đã có trên thanh trượt điều chỉnh độ sáng nên lối tắt đến tính năng siêu tối sẽ bị xoá."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Xoá lối tắt đến tính năng siêu tối"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Đã xoá lối tắt đến tính năng siêu tối"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Khả năng kết nối"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Hỗ trợ tiếp cận"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Phần mềm tiện ích"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 6b1f0a7f0841..267f3923fac5 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -667,7 +667,7 @@ <string name="volume_ringer_status_normal" msgid="1339039682222461143">"响铃"</string> <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"振动"</string> <string name="volume_ringer_status_silent" msgid="3691324657849880883">"静音"</string> - <string name="media_device_cast" msgid="4786241789687569892">"投屏"</string> + <string name="media_device_cast" msgid="4786241789687569892">"投放"</string> <string name="stream_notification_unavailable" msgid="4313854556205836435">"该功能无法使用,因为铃声被静音"</string> <string name="stream_alarm_unavailable" msgid="4059817189292197839">"“勿扰”模式已开启,因此无法调整音量"</string> <string name="stream_media_unavailable" msgid="6823020894438959853">"“勿扰”模式已开启,因此无法调整音量"</string> @@ -1293,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">"WLAN 已关闭"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"优先模式"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"闹钟已设置"</string> @@ -1351,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">"没有 WLAN 连接"</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> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收起图标"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展开图标"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"使用键盘导航"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"了解键盘快捷键"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"使用触控板导航"</string> @@ -1408,8 +1408,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> @@ -1419,14 +1418,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> @@ -1450,14 +1445,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-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 13b1a0f89504..c08835a38c60 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -1293,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> @@ -1351,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> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收合圖示"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展開圖示"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"使用鍵盤導覽"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"瞭解鍵盤快速鍵"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"使用觸控板導覽"</string> @@ -1408,8 +1408,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> @@ -1419,14 +1418,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> @@ -1450,14 +1445,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-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 0107819914f2..787698ca8912 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -1293,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> @@ -1351,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> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收合圖示"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展開圖示"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"使用鍵盤操作"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"學習鍵盤快速鍵"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"使用觸控板操作"</string> @@ -1408,8 +1408,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> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"用 3 指從螢幕底部向上滑動,就能隨時返回主畫面。"</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> @@ -1450,14 +1445,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-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 8eddc80f6483..3205b0ea6c64 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -1293,8 +1293,7 @@ <string name="add" msgid="81036585205287996">"Faka"</string> <string name="manage_users" msgid="1823875311934643849">"Phatha abasebenzisi"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Lesi saziso asikusekeli ukuhudulela ekuhlukaniseni isikrini."</string> - <!-- no translation found for dream_overlay_location_active (6484763493158166618) --> - <skip /> + <string name="dream_overlay_location_active" msgid="6484763493158166618">"Indawo iyasebenza"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"I-Wi-Fi ayitholakali"</string> <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Imodi ebalulekile"</string> <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"I-alamu isethiwe"</string> @@ -1351,8 +1350,7 @@ <string name="lock_screen_settings" msgid="6152703934761402399">"Yenza ngokwezifiso ukukhiya isikrini"</string> <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Vula ukuze wenze ukuvala isikrini ngendlela oyifisayo"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"I-Wi-Fi ayitholakali"</string> - <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) --> - <skip /> + <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Indawo iyasebenza"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Ikhamera ivinjiwe"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Ikhamera nemakrofoni zivinjiwe"</string> <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Imakrofoni ivinjiwe"</string> @@ -1400,6 +1398,8 @@ <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Goqa isithonjana"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Nweba isithonjana"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"noma"</string> + <!-- no translation found for shortcut_helper_content_description_drag_handle (5092426406009848110) --> + <skip /> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Funa usebenzisa ikhibhodi yakho"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Funda izinqamuleli zamakhibhodi"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Funa usebenzisa iphedi yokuthinta"</string> @@ -1408,8 +1408,7 @@ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Funda ukunyakaza kwephedi yokuthinta, izinqamuleli zamakhibhodi, nokuningi"</string> <string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Ukunyakazisa umzimba kwangemuva"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Ukunyakazisa umzimba kwasekhaya"</string> - <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) --> - <skip /> + <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Buka ama-app akamuva"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Kwenziwe"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Buyela emuva"</string> <string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Ukuze ubuyele emuva, swayiphela kwesokunxele noma kwesokudla usebenzisa iminwe emithathu noma yikuphi ephedini yokuthinta.\n\nUngasebenzisa nesinqamuleli sekhibhodi Isenzo + ESC kulokhu."</string> @@ -1419,14 +1418,10 @@ <string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Ukuze uye esikrinini sakho sasekhaya nganoma isiphi isikhathi, swayipha uye phezulu ngeminwe emithathu usuka phansi esikrinini sakho."</string> <string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Kuhle!"</string> <string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Ukuqedile ukuthinta kokuya ekhaya."</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">"Buka ama-app akamuva"</string> + <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Swayiphela phezulu bese ubamba usebenzisa iminwe emithathu kuphedi yokuthinta."</string> + <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Umsebenzi omuhle!"</string> + <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Uqedele ukubuka ukuthinta kwama-app akamuva."</string> <string name="tutorial_action_key_title" msgid="2659466586996495447">"Inkinobho yokufinyelela"</string> <string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Ukuze ufinyelele ama-app wakho, cindezela inkinobho yokufinyelela kukhibhodi yakho."</string> <string name="tutorial_action_key_success_title" msgid="466467860120112933">"Halala!"</string> @@ -1450,14 +1445,10 @@ <string name="overview_edu_notification_content" msgid="3578204677648432500">"Swayiphela phezulu bese uyabamba usebenzisa iminwe emithathu. Thepha ukuze ufunde kabanzi ngokunyakazisa umzimba."</string> <string name="all_apps_edu_notification_title" msgid="372262997265569063">"Sebenzisa ikhibhodi yakho ukubuka wonke ama-app"</string> <string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Cindezela inkinobho yokufinyelela noma kunini. Thepha ukuze ufunde kabanzi ngokunyakazisa umzimba."</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">"Ukufiphala okwengeziwe manje sekuyingxenye yokukhanya kwesislayida"</string> + <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"Manje ungenza isikrini sifiphaze ngokwengeziwe ngokwehlisa izinga lokukhanya nakakhulu.\n\nNjengoba lesi sakhi manje sesiyingxenye yesilayida sokukhanya, izinqamuleli ezokufiphaza okwengeziwe ziyasuswa."</string> + <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Susa izinqamuleli zokufiphaza okwengeziwe"</string> + <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Izinqamuleli zokufiphaza okwengeziwe zisusiwe"</string> <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Ukuxhumana"</string> <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Ukufinyeleleka"</string> <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Okusetshenziswayo"</string> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index a3db7761f59d..24b657943e37 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1482,7 +1482,7 @@ <!-- Text which is shown in the expanded notification shade when there are currently no notifications visible that the user hasn't already seen. [CHAR LIMIT=30] --> <string name="no_unseen_notif_text">No new notifications</string> - <!-- Title of heads up notification for adaptive notifications user education. [CHAR LIMIT=50] --> + <!-- Title of heads up notification for adaptive notifications user education. [CHAR LIMIT=60] --> <string name="adaptive_notification_edu_hun_title">Notification cooldown is on</string> <!-- Text of heads up notification for adaptive notifications user education. [CHAR LIMIT=100] --> diff --git a/packages/SystemUI/res/xml/media_session_collapsed.xml b/packages/SystemUI/res/xml/media_session_collapsed.xml index 2f2b10f8dc0c..66c54a389c8e 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 0140d52bd175..19cc3bc507b2 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/plugins/PluginInstance.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java index 87cc86f18fdc..82983973b5f5 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java @@ -32,6 +32,9 @@ import com.android.systemui.plugins.Plugin; import com.android.systemui.plugins.PluginFragment; import com.android.systemui.plugins.PluginLifecycleManager; import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.PluginProtector; +import com.android.systemui.plugins.PluginWrapper; +import com.android.systemui.plugins.ProtectedPluginListener; import dalvik.system.PathClassLoader; @@ -49,7 +52,8 @@ import java.util.function.Supplier; * * @param <T> The type of plugin that this contains. */ -public class PluginInstance<T extends Plugin> implements PluginLifecycleManager { +public class PluginInstance<T extends Plugin> + implements PluginLifecycleManager, ProtectedPluginListener { private static final String TAG = "PluginInstance"; private final Context mAppContext; @@ -58,6 +62,7 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager private final PluginFactory<T> mPluginFactory; private final String mTag; + private boolean mHasError = false; private BiConsumer<String, String> mLogConsumer = null; private Context mPluginContext; private T mPlugin; @@ -87,6 +92,11 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager return mTag; } + /** */ + public boolean hasError() { + return mHasError; + } + public void setLogFunc(BiConsumer logConsumer) { mLogConsumer = logConsumer; } @@ -97,8 +107,21 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager } } + @Override + public synchronized boolean onFail(String className, String methodName, LinkageError failure) { + mHasError = true; + unloadPlugin(); + mListener.onPluginDetached(this); + return true; + } + /** Alerts listener and plugin that the plugin has been created. */ public synchronized void onCreate() { + if (mHasError) { + log("Previous LinkageError detected for plugin class"); + return; + } + boolean loadPlugin = mListener.onPluginAttached(this); if (!loadPlugin) { if (mPlugin != null) { @@ -109,13 +132,17 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager } if (mPlugin == null) { - log("onCreate auto-load"); + log("onCreate: auto-load"); loadPlugin(); return; } + if (!checkVersion()) { + log("onCreate: version check failed"); + return; + } + log("onCreate: load callbacks"); - mPluginFactory.checkVersion(mPlugin); if (!(mPlugin instanceof PluginFragment)) { // Only call onCreate for plugins that aren't fragments, as fragments // will get the onCreate as part of the fragment lifecycle. @@ -126,6 +153,12 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager /** Alerts listener and plugin that the plugin is being shutdown. */ public synchronized void onDestroy() { + if (mHasError) { + // Detached in error handler + log("onDestroy - no-op"); + return; + } + log("onDestroy"); unloadPlugin(); mListener.onPluginDetached(this); @@ -134,28 +167,37 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager /** Returns the current plugin instance (if it is loaded). */ @Nullable public T getPlugin() { - return mPlugin; + return mHasError ? null : mPlugin; } /** * Loads and creates the plugin if it does not exist. */ public synchronized void loadPlugin() { + if (mHasError) { + log("Previous LinkageError detected for plugin class"); + return; + } + if (mPlugin != null) { log("Load request when already loaded"); return; } // Both of these calls take about 1 - 1.5 seconds in test runs - mPlugin = mPluginFactory.createPlugin(); + mPlugin = mPluginFactory.createPlugin(this); mPluginContext = mPluginFactory.createPluginContext(); if (mPlugin == null || mPluginContext == null) { Log.e(mTag, "Requested load, but failed"); return; } + if (!checkVersion()) { + log("loadPlugin: version check failed"); + return; + } + log("Loaded plugin; running callbacks"); - mPluginFactory.checkVersion(mPlugin); if (!(mPlugin instanceof PluginFragment)) { // Only call onCreate for plugins that aren't fragments, as fragments // will get the onCreate as part of the fragment lifecycle. @@ -165,6 +207,29 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager } /** + * Checks the plugin version, and permanently destroys the plugin instance on a failure + */ + private synchronized boolean checkVersion() { + if (mHasError) { + return false; + } + + if (mPlugin == null) { + return true; + } + + if (mPluginFactory.checkVersion(mPlugin)) { + return true; + } + + Log.wtf(TAG, "Version check failed for " + mPlugin.getClass().getSimpleName()); + mHasError = true; + unloadPlugin(); + mListener.onPluginDetached(this); + return false; + } + + /** * Unloads and destroys the current plugin instance if it exists. * * This will free the associated memory if there are not other references. @@ -204,7 +269,7 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager } public VersionInfo getVersionInfo() { - return mPluginFactory.checkVersion(mPlugin); + return mPluginFactory.getVersionInfo(mPlugin); } @VisibleForTesting @@ -295,16 +360,19 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager /** Class that compares a plugin class against an implementation for version matching. */ public interface VersionChecker { - /** Compares two plugin classes. */ - <T extends Plugin> VersionInfo checkVersion( + /** Compares two plugin classes. Returns true when match. */ + <T extends Plugin> boolean checkVersion( Class<T> instanceClass, Class<T> pluginClass, Plugin plugin); + + /** Returns VersionInfo for the target class */ + <T extends Plugin> VersionInfo getVersionInfo(Class<T> instanceclass); } /** Class that compares a plugin class against an implementation for version matching. */ public static class VersionCheckerImpl implements VersionChecker { @Override /** Compares two plugin classes. */ - public <T extends Plugin> VersionInfo checkVersion( + public <T extends Plugin> boolean checkVersion( Class<T> instanceClass, Class<T> pluginClass, Plugin plugin) { VersionInfo pluginVersion = new VersionInfo().addClass(pluginClass); VersionInfo instanceVersion = new VersionInfo().addClass(instanceClass); @@ -313,11 +381,17 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager } else if (plugin != null) { int fallbackVersion = plugin.getVersion(); if (fallbackVersion != pluginVersion.getDefaultVersion()) { - throw new VersionInfo.InvalidVersionException("Invalid legacy version", false); + return false; } - return null; } - return instanceVersion; + return true; + } + + @Override + /** Returns the version info for the class */ + public <T extends Plugin> VersionInfo getVersionInfo(Class<T> instanceClass) { + VersionInfo instanceVersion = new VersionInfo().addClass(instanceClass); + return instanceVersion.hasVersionInfo() ? instanceVersion : null; } } @@ -364,20 +438,16 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager } /** Creates the related plugin object from the factory */ - public T createPlugin() { + public T createPlugin(ProtectedPluginListener listener) { try { ClassLoader loader = mClassLoaderFactory.get(); Class<T> instanceClass = (Class<T>) Class.forName( mComponentName.getClassName(), true, loader); T result = (T) mInstanceFactory.create(instanceClass); Log.v(TAG, "Created plugin: " + result); - return result; - } catch (ClassNotFoundException ex) { - Log.e(TAG, "Failed to load plugin", ex); - } catch (IllegalAccessException ex) { - Log.e(TAG, "Failed to load plugin", ex); - } catch (InstantiationException ex) { - Log.e(TAG, "Failed to load plugin", ex); + return PluginProtector.protectIfAble(result, listener); + } catch (ReflectiveOperationException ex) { + Log.wtf(TAG, "Failed to load plugin", ex); } return null; } @@ -394,13 +464,27 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager return null; } - /** Check Version and create VersionInfo for instance */ - public VersionInfo checkVersion(T instance) { + /** Check Version for the instance */ + public boolean checkVersion(T instance) { if (instance == null) { - instance = createPlugin(); + instance = createPlugin(null); + } + if (instance instanceof PluginWrapper) { + instance = ((PluginWrapper<T>) instance).getPlugin(); } return mVersionChecker.checkVersion( (Class<T>) instance.getClass(), mPluginClass, instance); } + + /** Get Version Info for the instance */ + public VersionInfo getVersionInfo(T instance) { + if (instance == null) { + instance = createPlugin(null); + } + if (instance instanceof PluginWrapper) { + instance = ((PluginWrapper<T>) instance).getPlugin(); + } + return mVersionChecker.getVersionInfo((Class<T>) instance.getClass()); + } } } diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index c1eae2e53a44..e5cf7cf0eeb8 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -15,12 +15,15 @@ */ package com.android.keyguard +import android.app.NotificationManager.zenModeFromInterruptionFilter import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter import android.content.res.Resources import android.os.Trace +import android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS +import android.provider.Settings.Global.ZEN_MODE_OFF import android.text.format.DateFormat import android.util.Log import android.util.TypedValue @@ -49,6 +52,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.log.core.Logger +import com.android.systemui.modes.shared.ModesUi import com.android.systemui.plugins.clocks.AlarmData import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockFaceController @@ -63,6 +67,7 @@ import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ZenModeController +import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor import com.android.systemui.util.concurrency.DelayableExecutor import java.util.Locale import java.util.TimeZone @@ -97,12 +102,13 @@ constructor( private val clockBuffers: ClockMessageBuffers, private val featureFlags: FeatureFlagsClassic, private val zenModeController: ZenModeController, + private val zenModeInteractor: ZenModeInteractor, ) { var loggers = listOf( clockBuffers.infraMessageBuffer, clockBuffers.smallClockMessageBuffer, - clockBuffers.largeClockMessageBuffer + clockBuffers.largeClockMessageBuffer, ) .map { Logger(it, TAG) } @@ -146,7 +152,7 @@ constructor( bgExecutor, regionSamplingEnabled, isLockscreen = true, - ::updateColors + ::updateColors, ) .apply { startRegionSampler() } @@ -157,7 +163,7 @@ constructor( bgExecutor, regionSamplingEnabled, isLockscreen = true, - ::updateColors + ::updateColors, ) .apply { startRegionSampler() } @@ -271,7 +277,7 @@ constructor( bgExecutor: Executor?, regionSamplingEnabled: Boolean, isLockscreen: Boolean, - updateColors: () -> Unit + updateColors: () -> Unit, ): RegionSampler { return RegionSampler( sampledView, @@ -384,24 +390,30 @@ constructor( } } + @VisibleForTesting + internal fun listenForDnd(scope: CoroutineScope): Job { + ModesUi.assertInNewMode() + return scope.launch { + zenModeInteractor.dndMode.collect { + val zenMode = + if (it != null && it.isActive) + zenModeFromInterruptionFilter( + it.interruptionFilter, + ZEN_MODE_IMPORTANT_INTERRUPTIONS, + ) + else ZEN_MODE_OFF + + handleZenMode(zenMode) + } + } + } + private val zenModeCallback = object : ZenModeController.Callback { override fun onZenChanged(zen: Int) { - var mode = ZenMode.fromInt(zen) - if (mode == null) { - Log.e(TAG, "Failed to get zen mode from int: $zen") - return + if (!ModesUi.isEnabled) { + handleZenMode(zen) } - - zenData = - ZenData( - mode, - if (mode == ZenMode.OFF) SysuiR.string::dnd_is_off.name - else SysuiR.string::dnd_is_on.name - ) - .also { data -> - mainExecutor.execute { clock?.run { events.onZenDataChanged(data) } } - } } override fun onNextAlarmChanged() { @@ -409,7 +421,7 @@ constructor( alarmData = AlarmData( if (nextAlarmMillis > 0) nextAlarmMillis else null, - SysuiR.string::status_bar_alarm.name + SysuiR.string::status_bar_alarm.name, ) .also { data -> mainExecutor.execute { clock?.run { events.onAlarmDataChanged(data) } } @@ -417,6 +429,24 @@ constructor( } } + private fun handleZenMode(zen: Int) { + val mode = ZenMode.fromInt(zen) + if (mode == null) { + Log.e(TAG, "Failed to get zen mode from int: $zen") + return + } + + zenData = + ZenData( + mode, + if (mode == ZenMode.OFF) SysuiR.string::dnd_is_off.name + else SysuiR.string::dnd_is_on.name, + ) + .also { data -> + mainExecutor.execute { clock?.run { events.onZenDataChanged(data) } } + } + } + fun registerListeners(parent: View) { if (isRegistered) { return @@ -424,7 +454,7 @@ constructor( isRegistered = true broadcastDispatcher.registerReceiver( localeBroadcastReceiver, - IntentFilter(Intent.ACTION_LOCALE_CHANGED) + IntentFilter(Intent.ACTION_LOCALE_CHANGED), ) configurationController.addCallback(configListener) batteryController.addCallback(batteryCallback) @@ -434,6 +464,9 @@ constructor( parent.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { listenForDozing(this) + if (ModesUi.isEnabled) { + listenForDnd(this) + } if (MigrateClocksToBlueprint.isEnabled) { listenForDozeAmountTransition(this) listenForAnyStateToAodTransition(this) @@ -449,7 +482,9 @@ constructor( bgExecutor.execute { // Query ZenMode data - zenModeCallback.onZenChanged(zenModeController.zen) + if (!ModesUi.isEnabled) { + zenModeCallback.onZenChanged(zenModeController.zen) + } zenModeCallback.onNextAlarmChanged() } } @@ -605,10 +640,9 @@ constructor( @VisibleForTesting internal fun listenForDozing(scope: CoroutineScope): Job { return scope.launch { - combine( - keyguardInteractor.dozeAmount, - keyguardInteractor.isDozing, - ) { localDozeAmount, localIsDozing -> + combine(keyguardInteractor.dozeAmount, keyguardInteractor.isDozing) { + localDozeAmount, + localIsDozing -> localDozeAmount > dozeAmount || localIsDozing } .collect { localIsDozing -> isDozing = localIsDozing } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index ffbc85ca530f..f05cbf422707 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -109,6 +109,8 @@ import com.android.systemui.util.settings.GlobalSettings; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executor; +import java.util.function.Consumer; /** Determines how the bouncer is displayed to the user. */ public class KeyguardSecurityContainer extends ConstraintLayout { @@ -170,6 +172,7 @@ public class KeyguardSecurityContainer extends ConstraintLayout { private ViewMode mViewMode = new DefaultViewMode(); private boolean mIsInteractable; protected ViewMediatorCallback mViewMediatorCallback; + private Executor mBgExecutor; /* * Using MODE_UNINITIALIZED to mean the view mode is set to DefaultViewMode, but init() has not * yet been called on it. This will happen when the ViewController is initialized. @@ -352,6 +355,10 @@ public class KeyguardSecurityContainer extends ConstraintLayout { updateBiometricRetry(securityMode, faceAuthEnabled); } + void setBackgroundExecutor(Executor bgExecutor) { + mBgExecutor = bgExecutor; + } + void initMode(@Mode int mode, GlobalSettings globalSettings, FalsingManager falsingManager, UserSwitcherController userSwitcherController, UserSwitcherViewMode.UserSwitcherCallback userSwitcherCallback, @@ -367,7 +374,7 @@ public class KeyguardSecurityContainer extends ConstraintLayout { mViewMode = new OneHandedViewMode(); break; case MODE_USER_SWITCHER: - mViewMode = new UserSwitcherViewMode(userSwitcherCallback); + mViewMode = new UserSwitcherViewMode(userSwitcherCallback, mBgExecutor); break; default: mViewMode = new DefaultViewMode(); @@ -991,6 +998,7 @@ public class KeyguardSecurityContainer extends ConstraintLayout { private FalsingManager mFalsingManager; private UserSwitcherController mUserSwitcherController; private KeyguardUserSwitcherPopupMenu mPopup; + private Executor mBgExecutor; private Resources mResources; private UserSwitcherController.UserSwitchCallback mUserSwitchCallback = this::setupUserSwitcher; @@ -998,8 +1006,9 @@ public class KeyguardSecurityContainer extends ConstraintLayout { private UserSwitcherCallback mUserSwitcherCallback; private FalsingA11yDelegate mFalsingA11yDelegate; - UserSwitcherViewMode(UserSwitcherCallback userSwitcherCallback) { + UserSwitcherViewMode(UserSwitcherCallback userSwitcherCallback, Executor bgExecutor) { mUserSwitcherCallback = userSwitcherCallback; + mBgExecutor = bgExecutor; } @Override @@ -1068,18 +1077,22 @@ public class KeyguardSecurityContainer extends ConstraintLayout { mView.removeView(mUserSwitcher); } - private Drawable findLargeUserIcon(int userId) { - Bitmap userIcon = UserManager.get(mView.getContext()).getUserIcon(userId); - if (userIcon != null) { - int iconSize = - mResources.getDimensionPixelSize(R.dimen.bouncer_user_switcher_icon_size); - return CircleFramedDrawable.getInstance( - mView.getContext(), - Icon.scaleDownIfNecessary(userIcon, iconSize, iconSize) - ); - } - - return UserIcons.getDefaultUserIcon(mResources, userId, false); + private void findLargeUserIcon(int userId, Consumer<Drawable> consumer) { + mBgExecutor.execute(() -> { + Drawable icon; + Bitmap userIcon = UserManager.get(mView.getContext()).getUserIcon(userId); + if (userIcon != null) { + int iconSize = mResources.getDimensionPixelSize( + R.dimen.bouncer_user_switcher_icon_size); + icon = CircleFramedDrawable.getInstance( + mView.getContext(), + Icon.scaleDownIfNecessary(userIcon, iconSize, iconSize) + ); + } else { + icon = UserIcons.getDefaultUserIcon(mResources, userId, false); + } + consumer.accept(icon); + }); } @Override @@ -1136,8 +1149,15 @@ public class KeyguardSecurityContainer extends ConstraintLayout { return; } final String currentUserName = mUserSwitcherController.getCurrentUserName(); - Drawable userIcon = findLargeUserIcon(currentUser.info.id); - ((ImageView) mView.findViewById(R.id.user_icon)).setImageDrawable(userIcon); + findLargeUserIcon(currentUser.info.id, + (Drawable userIcon) -> { + mView.post(() -> { + ImageView view = (ImageView) mView.findViewById(R.id.user_icon); + if (view != null) { + view.setImageDrawable(userIcon); + } + }); + }); mUserSwitcher.setText(currentUserName); KeyguardUserSwitcherAnchor anchor = mView.findViewById(R.id.user_switcher_anchor); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 2d28a189f84d..a4082114cb79 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -76,6 +76,7 @@ import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor; import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor; import com.android.systemui.classifier.FalsingA11yDelegate; import com.android.systemui.classifier.FalsingCollector; +import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor; import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor; import com.android.systemui.flags.FeatureFlags; @@ -102,6 +103,7 @@ import kotlinx.coroutines.Job; import java.io.File; import java.util.Arrays; +import java.util.concurrent.Executor; import javax.inject.Inject; import javax.inject.Provider; @@ -426,6 +428,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard private final Provider<JavaAdapter> mJavaAdapter; private final DeviceProvisionedController mDeviceProvisionedController; private final Lazy<PrimaryBouncerInteractor> mPrimaryBouncerInteractor; + private final Executor mBgExecutor; @Nullable private Job mSceneTransitionCollectionJob; @@ -459,6 +462,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard DevicePolicyManager devicePolicyManager, KeyguardDismissTransitionInteractor keyguardDismissTransitionInteractor, Lazy<PrimaryBouncerInteractor> primaryBouncerInteractor, + @Background Executor bgExecutor, Provider<DeviceEntryInteractor> deviceEntryInteractor ) { super(view); @@ -493,11 +497,13 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mDeviceProvisionedController = deviceProvisionedController; mPrimaryBouncerInteractor = primaryBouncerInteractor; mDevicePolicyManager = devicePolicyManager; + mBgExecutor = bgExecutor; } @Override public void onInit() { mSecurityViewFlipperController.init(); + mView.setBackgroundExecutor(mBgExecutor); updateResources(); configureMode(); } diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java b/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java index 0898134a3db8..76df9c96c801 100644 --- a/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java @@ -25,7 +25,6 @@ import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; import android.graphics.Rect; import android.graphics.Region; import android.os.RemoteException; -import android.util.Log; import android.view.GestureDetector; import android.view.ISystemGestureExclusionListener; import android.view.IWindowManager; @@ -76,10 +75,9 @@ import javax.inject.Named; * touches are consumed. */ public class TouchMonitor { + private final Logger mLogger; // This executor is used to protect {@code mActiveTouchSessions} from being modified // concurrently. Any operation that adds or removes values should use this executor. - public String TAG = "DreamOverlayTouchMonitor"; - private final Logger mLogger; private final Executor mMainExecutor; private final Executor mBackgroundExecutor; @@ -298,13 +296,12 @@ public class TouchMonitor { mWindowManagerService.registerSystemGestureExclusionListener( mGestureExclusionListener, mDisplayId); } catch (RemoteException e) { - // Handle the exception - Log.e(TAG, "Failed to register gesture exclusion listener", e); + mLogger.e("Failed to register gesture exclusion listener", e); } }); } mCurrentInputSession = mInputSessionFactory.create( - "dreamOverlay", + mLoggingName, mInputEventListener, mOnGestureListener, true) @@ -326,7 +323,7 @@ public class TouchMonitor { } } catch (RemoteException e) { // Handle the exception - Log.e(TAG, "unregisterSystemGestureExclusionListener: failed", e); + mLogger.e("unregisterSystemGestureExclusionListener: failed", e); } }); } @@ -543,6 +540,7 @@ public class TouchMonitor { private InputSession mCurrentInputSession; private final int mDisplayId; private final IWindowManager mWindowManagerService; + private final String mLoggingName; private Rect mMaxBounds; @@ -589,7 +587,8 @@ public class TouchMonitor { mDisplayHelper = displayHelper; mWindowManagerService = windowManagerService; mConfigurationInteractor = configurationInteractor; - mLogger = new Logger(logBuffer, loggingName + ":TouchMonitor"); + mLoggingName = loggingName + ":TouchMonitor"; + mLogger = new Logger(logBuffer, mLoggingName); } /** diff --git a/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt index 5bd7e5455c2b..23045a336a5d 100644 --- a/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt @@ -47,7 +47,9 @@ constructor( private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager, private val shadeController: ShadeController, private val notificationShadeWindowController: NotificationShadeWindowController, - private val windowRootViewVisibilityInteractor: WindowRootViewVisibilityInteractor + private val windowRootViewVisibilityInteractor: WindowRootViewVisibilityInteractor, + private val shadeBackActionInteractor: ShadeBackActionInteractor, + private val qsController: QuickSettingsController, ) : CoreStartable { private var isCallbackRegistered = false @@ -77,14 +79,6 @@ constructor( get() = notificationShadeWindowController.windowRootView?.viewRootImpl?.onBackInvokedDispatcher - private lateinit var shadeBackActionInteractor: ShadeBackActionInteractor - private lateinit var qsController: QuickSettingsController - - fun setup(qsController: QuickSettingsController, svController: ShadeBackActionInteractor) { - this.qsController = qsController - this.shadeBackActionInteractor = svController - } - override fun start() { scope.launch { windowRootViewVisibilityInteractor.isLockscreenOrShadeVisibleAndInteractive.collect { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt index 7ecbb88099cb..ec3fd9f7da35 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt @@ -25,8 +25,6 @@ import com.android.systemui.biometrics.domain.interactor.LogContextInteractor import com.android.systemui.biometrics.domain.interactor.LogContextInteractorImpl import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl -import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractor -import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractorImpl import com.android.systemui.dagger.SysUISingleton import dagger.Binds import dagger.Module @@ -48,12 +46,6 @@ interface BiometricsDomainLayerModule { @Binds @SysUISingleton - fun providesSideFpsOverlayInteractor( - impl: SideFpsOverlayInteractorImpl - ): SideFpsOverlayInteractor - - @Binds - @SysUISingleton fun providesCredentialInteractor(impl: CredentialInteractorImpl): CredentialInteractor @Binds diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt deleted file mode 100644 index 10c3483de452..000000000000 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt +++ /dev/null @@ -1,82 +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.biometrics.domain.interactor - -import android.util.Log -import com.android.systemui.biometrics.shared.model.AuthenticationReason.NotRunning -import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor -import com.android.systemui.util.kotlin.sample -import javax.inject.Inject -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.flow.onEach - -/** Encapsulates business logic for showing and hiding the side fingerprint sensor indicator. */ -interface SideFpsOverlayInteractor { - /** Whether the side fingerprint sensor indicator is currently showing. */ - val isShowing: Flow<Boolean> -} - -@OptIn(ExperimentalCoroutinesApi::class) -class SideFpsOverlayInteractorImpl -@Inject -constructor( - biometricStatusInteractor: BiometricStatusInteractor, - displayStateInteractor: DisplayStateInteractor, - deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor, - sfpsSensorInteractor: SideFpsSensorInteractor, - // TODO(b/365182034): add progress bar input when rest to unlock feature is implemented -) : SideFpsOverlayInteractor { - private val sfpsOverlayEnabled: Flow<Boolean> = - sfpsSensorInteractor.isAvailable.sample(displayStateInteractor.isInRearDisplayMode) { - isAvailable: Boolean, - isInRearDisplayMode: Boolean -> - isAvailable && !isInRearDisplayMode - } - - private val showSideFpsOverlay: Flow<Boolean> = - combine( - biometricStatusInteractor.sfpsAuthenticationReason, - deviceEntrySideFpsOverlayInteractor.showIndicatorForDeviceEntry, - // TODO(b/365182034): add progress bar input when rest to unlock feature is implemented - ) { systemServerAuthReason, showIndicatorForDeviceEntry -> - Log.d( - TAG, - "systemServerAuthReason = $systemServerAuthReason, " + - "showIndicatorForDeviceEntry = $showIndicatorForDeviceEntry, " - ) - systemServerAuthReason != NotRunning || showIndicatorForDeviceEntry - } - - override val isShowing: Flow<Boolean> = - sfpsOverlayEnabled - .flatMapLatest { sfpsOverlayEnabled -> - if (!sfpsOverlayEnabled) { - flowOf(false) - } else { - showSideFpsOverlay - } - } - .onEach { Log.d(TAG, "isShowing: $it") } - - companion object { - private const val TAG = "SideFpsOverlayInteractor" - } -} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt index d055731b2698..73f75a4ff639 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt @@ -18,11 +18,13 @@ package com.android.systemui.biometrics.ui.binder import android.animation.Animator import android.animation.AnimatorSet +import android.animation.ValueAnimator import android.graphics.Outline import android.graphics.Rect import android.transition.AutoTransition import android.transition.TransitionManager import android.util.TypedValue +import android.view.Surface import android.view.View import android.view.ViewGroup import android.view.ViewOutlineProvider @@ -158,13 +160,16 @@ object BiometricViewSizeBinder { fun setVisibilities(hideSensorIcon: Boolean, size: PromptSize) { viewsToHideWhenSmall.forEach { it.showContentOrHide(forceHide = size.isSmall) } largeConstraintSet.setVisibility(iconHolderView.id, View.GONE) + largeConstraintSet.setVisibility(R.id.biometric_icon_overlay, View.GONE) largeConstraintSet.setVisibility(R.id.indicator, View.GONE) largeConstraintSet.setVisibility(R.id.scrollView, View.GONE) if (hideSensorIcon) { smallConstraintSet.setVisibility(iconHolderView.id, View.GONE) + smallConstraintSet.setVisibility(R.id.biometric_icon_overlay, View.GONE) smallConstraintSet.setVisibility(R.id.indicator, View.GONE) mediumConstraintSet.setVisibility(iconHolderView.id, View.GONE) + mediumConstraintSet.setVisibility(R.id.biometric_icon_overlay, View.GONE) mediumConstraintSet.setVisibility(R.id.indicator, View.GONE) } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt index 9fe1dc51f4c2..9578da4238ee 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt @@ -33,44 +33,89 @@ import com.airbnb.lottie.LottieProperty import com.android.app.animation.Interpolators import com.android.keyguard.KeyguardPINView import com.android.systemui.CoreStartable -import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractor +import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor +import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor +import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor +import com.android.systemui.biometrics.shared.model.AuthenticationReason.NotRunning import com.android.systemui.biometrics.shared.model.LottieCallback import com.android.systemui.biometrics.ui.viewmodel.SideFpsOverlayViewModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor +import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.res.R +import com.android.systemui.util.kotlin.sample import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch /** Binds the side fingerprint sensor indicator view to [SideFpsOverlayViewModel]. */ +@OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class SideFpsOverlayViewBinder @Inject constructor( @Application private val applicationScope: CoroutineScope, @Application private val applicationContext: Context, + private val biometricStatusInteractor: Lazy<BiometricStatusInteractor>, + private val displayStateInteractor: Lazy<DisplayStateInteractor>, + private val deviceEntrySideFpsOverlayInteractor: Lazy<DeviceEntrySideFpsOverlayInteractor>, private val layoutInflater: Lazy<LayoutInflater>, - private val sideFpsOverlayInteractor: Lazy<SideFpsOverlayInteractor>, - private val sideFpsOverlayViewModel: Lazy<SideFpsOverlayViewModel>, + private val sideFpsProgressBarViewModel: Lazy<SideFpsProgressBarViewModel>, + private val sfpsSensorInteractor: Lazy<SideFpsSensorInteractor>, private val windowManager: Lazy<WindowManager> ) : CoreStartable { - private var overlayView: View? = null override fun start() { - applicationScope.launch { - sideFpsOverlayInteractor.get().isShowing.collect { isShowing: Boolean -> - if (isShowing) { - show() - } else { - hide() + applicationScope + .launch { + sfpsSensorInteractor.get().isAvailable.collect { isSfpsAvailable -> + if (isSfpsAvailable) { + combine( + biometricStatusInteractor.get().sfpsAuthenticationReason, + deviceEntrySideFpsOverlayInteractor + .get() + .showIndicatorForDeviceEntry, + sideFpsProgressBarViewModel.get().isVisible, + ::Triple + ) + .sample(displayStateInteractor.get().isInRearDisplayMode, ::Pair) + .collect { (combinedFlows, isInRearDisplayMode: Boolean) -> + val ( + systemServerAuthReason, + showIndicatorForDeviceEntry, + progressBarIsVisible) = + combinedFlows + Log.d( + TAG, + "systemServerAuthReason = $systemServerAuthReason, " + + "showIndicatorForDeviceEntry = " + + "$showIndicatorForDeviceEntry, " + + "progressBarIsVisible = $progressBarIsVisible" + ) + if (!isInRearDisplayMode) { + if (progressBarIsVisible) { + hide() + } else if (systemServerAuthReason != NotRunning) { + show() + } else if (showIndicatorForDeviceEntry) { + show() + } else { + hide() + } + } + } + } } } - } } + private var overlayView: View? = null + /** Show the side fingerprint sensor indicator */ private fun show() { if (overlayView?.isAttachedToWindow == true) { @@ -80,10 +125,17 @@ constructor( ) return } + overlayView = layoutInflater.get().inflate(R.layout.sidefps_view, null, false) - val overlayViewModel = sideFpsOverlayViewModel.get() - bind(overlayView!!, overlayViewModel, windowManager.get()) + val overlayViewModel = + SideFpsOverlayViewModel( + applicationContext, + deviceEntrySideFpsOverlayInteractor.get(), + displayStateInteractor.get(), + sfpsSensorInteractor.get(), + ) + bind(overlayView!!, overlayViewModel, windowManager.get()) overlayView!!.visibility = View.INVISIBLE Log.d(TAG, "show(): adding overlayView $overlayView") windowManager.get().addView(overlayView, overlayViewModel.defaultOverlayViewParams) @@ -109,20 +161,6 @@ constructor( companion object { private const val TAG = "SideFpsOverlayViewBinder" - private val accessibilityDelegate = - object : View.AccessibilityDelegate() { - override fun dispatchPopulateAccessibilityEvent( - host: View, - event: AccessibilityEvent - ): Boolean { - return if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { - true - } else { - super.dispatchPopulateAccessibilityEvent(host, event) - } - } - } - /** Binds overlayView (side fingerprint sensor indicator view) to SideFpsOverlayViewModel */ fun bind( overlayView: View, @@ -146,7 +184,24 @@ constructor( overlayShowAnimator.start() - it.accessibilityDelegate = accessibilityDelegate + it.setAccessibilityDelegate( + object : View.AccessibilityDelegate() { + override fun dispatchPopulateAccessibilityEvent( + host: View, + event: AccessibilityEvent + ): Boolean { + return if ( + event.getEventType() === + android.view.accessibility.AccessibilityEvent + .TYPE_WINDOW_STATE_CHANGED + ) { + true + } else { + super.dispatchPopulateAccessibilityEvent(host, event) + } + } + } + ) repeatOnLifecycle(Lifecycle.State.STARTED) { launch { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt index 85f221fa951e..168ba11309cc 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt @@ -78,11 +78,11 @@ import kotlinx.coroutines.launch class PromptViewModel @Inject constructor( - private val displayStateInteractor: DisplayStateInteractor, + displayStateInteractor: DisplayStateInteractor, private val promptSelectorInteractor: PromptSelectorInteractor, @Application private val context: Context, - udfpsOverlayInteractor: UdfpsOverlayInteractor, - biometricStatusInteractor: BiometricStatusInteractor, + private val udfpsOverlayInteractor: UdfpsOverlayInteractor, + private val biometricStatusInteractor: BiometricStatusInteractor, private val udfpsUtils: UdfpsUtils, private val iconProvider: IconProvider, private val activityTaskManager: ActivityTaskManager, @@ -135,13 +135,11 @@ constructor( R.dimen.biometric_prompt_landscape_medium_horizontal_padding ) - val currentRotation: StateFlow<DisplayRotation> = displayStateInteractor.currentRotation - val udfpsOverlayParams: StateFlow<UdfpsOverlayParams> = udfpsOverlayInteractor.udfpsOverlayParams private val udfpsSensorBounds: Flow<Rect> = - combine(udfpsOverlayParams, currentRotation) { params, rotation -> + combine(udfpsOverlayParams, displayStateInteractor.currentRotation) { params, rotation -> val rotatedBounds = Rect(params.sensorBounds) RotationUtils.rotateBounds( rotatedBounds, @@ -264,7 +262,7 @@ constructor( _forceLargeSize, promptKind, displayStateInteractor.isLargeScreen, - currentRotation, + displayStateInteractor.currentRotation, modalities ) { forceLarge, promptKind, isLargeScreen, rotation, modalities -> when { @@ -456,7 +454,7 @@ constructor( /** Padding for prompt UI elements */ val promptPadding: Flow<Rect> = - combine(size, currentRotation) { size, rotation -> + combine(size, displayStateInteractor.currentRotation) { size, rotation -> if (size != PromptSize.LARGE) { val navBarInsets = Utils.getNavbarInsets(context) if (rotation == DisplayRotation.ROTATION_90) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt index 7c1984e506c9..c2a4ee36dec6 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt @@ -147,7 +147,8 @@ constructor( _lottieBounds, sensorLocation, displayRotation, - ) { _: Rect?, sensorLocation: SideFpsSensorLocation, _: DisplayRotation -> + ) { bounds: Rect?, sensorLocation: SideFpsSensorLocation, displayRotation: DisplayRotation + -> val topLeft = Point(sensorLocation.left, sensorLocation.top) defaultOverlayViewParams.apply { 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 873d1b3cc03d..4185aed3095c 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 @@ sealed class AuthMethodBouncerViewModel( _animateFailure.value = authenticationResult != AuthenticationResult.SUCCEEDED clearInput() + if (authenticationResult == AuthenticationResult.SUCCEEDED) { + onSuccessfulAuthentication() + } } awaitCancellation() } @@ -116,6 +119,9 @@ sealed class AuthMethodBouncerViewModel( /** 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/PasswordBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt index 2493cf1a101b..1427d787ea86 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 @@ constructor( 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 @@ constructor( 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/clipboardoverlay/ClipboardModel.kt b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardModel.kt index 12597a7679fa..99c026cb028f 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardModel.kt +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardModel.kt @@ -24,6 +24,7 @@ import android.text.TextUtils import android.util.Log import android.util.Size import android.view.textclassifier.TextLinks +import com.android.systemui.Flags.clipboardUseDescriptionMimetype import com.android.systemui.res.R import java.io.IOException @@ -70,11 +71,11 @@ data class ClipboardModel( context: Context, utils: ClipboardOverlayUtils, clipData: ClipData, - source: String + source: String, ): ClipboardModel { val sensitive = clipData.description?.extras?.getBoolean(EXTRA_IS_SENSITIVE) ?: false val item = clipData.getItemAt(0)!! - val type = getType(context, item) + val type = getType(context, item, clipData.description.getMimeType(0)) val remote = utils.isRemoteCopy(context, clipData, source) return ClipboardModel( clipData, @@ -84,18 +85,26 @@ data class ClipboardModel( item.textLinks, item.uri, sensitive, - remote + remote, ) } - private fun getType(context: Context, item: ClipData.Item): Type { + private fun getType(context: Context, item: ClipData.Item, mimeType: String): Type { return if (!TextUtils.isEmpty(item.text)) { Type.TEXT } else if (item.uri != null) { - if (context.contentResolver.getType(item.uri)?.startsWith("image") == true) { - Type.IMAGE + if (clipboardUseDescriptionMimetype()) { + if (mimeType.startsWith("image")) { + Type.IMAGE + } else { + Type.URI + } } else { - Type.URI + if (context.contentResolver.getType(item.uri)?.startsWith("image") == true) { + Type.IMAGE + } else { + Type.URI + } } } else { Type.OTHER @@ -107,6 +116,6 @@ data class ClipboardModel( TEXT, IMAGE, URI, - OTHER + OTHER, } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalDreamStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalDreamStartable.kt index 04393feaae37..1bd541e1088a 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/CommunalDreamStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalDreamStartable.kt @@ -65,7 +65,9 @@ constructor( keyguardTransitionInteractor .transitionValue(Scenes.Communal, KeyguardState.GLANCEABLE_HUB) .map { it == 1f }, - not(keyguardInteractor.isDreaming), + // Use isDreamingAny because isDreaming is false in doze and doesn't change again + // when the screen turns on, which causes the dream to not start underneath the hub. + not(keyguardInteractor.isDreamingAny), // TODO(b/362830856): Remove this workaround. keyguardInteractor.isKeyguardShowing, not(communalSceneInteractor.isLaunchingWidget), 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 f77dd587dca3..f0f7ca522c70 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 @@ constructor( } _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/CommunalSceneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt index c7538bb4f696..905eda14e2d5 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt @@ -87,7 +87,9 @@ constructor( */ private val nextKeyguardStateInternal = combine( - keyguardInteractor.isAbleToDream, + // Don't use delayed dreaming signal as otherwise we might go to occluded or lock + // screen when closing hub if dream just started under the hub. + keyguardInteractor.isDreamingWithOverlay, keyguardInteractor.isKeyguardOccluded, keyguardInteractor.isKeyguardGoingAway, keyguardInteractor.isKeyguardShowing, @@ -156,7 +158,7 @@ constructor( private suspend fun handleIdle( prevTransition: ObservableTransitionState, - idle: ObservableTransitionState.Idle + idle: ObservableTransitionState.Idle, ) { if ( prevTransition is ObservableTransitionState.Transition && @@ -186,7 +188,7 @@ constructor( internalTransitionInteractor.updateTransition( currentTransitionId!!, 1f, - TransitionState.FINISHED + TransitionState.FINISHED, ) resetTransitionData() } @@ -204,7 +206,7 @@ constructor( internalTransitionInteractor.updateTransition( currentTransitionId!!, 1f, - TransitionState.FINISHED + TransitionState.FINISHED, ) resetTransitionData() } @@ -217,7 +219,7 @@ constructor( private suspend fun handleTransition( prevTransition: ObservableTransitionState, - transition: ObservableTransitionState.Transition + transition: ObservableTransitionState.Transition, ) { if ( prevTransition.isTransitioning(from = transition.fromContent, to = transition.toContent) @@ -295,7 +297,7 @@ constructor( internalTransitionInteractor.updateTransition( currentTransitionId!!, progress.coerceIn(0f, 1f), - TransitionState.RUNNING + TransitionState.RUNNING, ) } } 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 7453368d0ee7..f7cd2ab89140 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 com.android.systemui.util.time.SystemClock 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 @@ constructor( 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 @@ constructor( * 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/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java index 79f4568d73be..5c075c240caf 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java @@ -69,6 +69,7 @@ import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.DozeServiceHost; import com.android.systemui.statusbar.phone.HeadsUpModule; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; +import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule; import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentStartableModule; import com.android.systemui.statusbar.policy.AospPolicyModule; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -136,6 +137,7 @@ import javax.inject.Named; RotationLockModule.class, RotationLockNewModule.class, ScreenDecorationsModule.class, + StatusBarPhoneModule.class, SystemActionsModule.class, ShadeModule.class, StartCentralSurfacesModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractor.kt index 28db3b861278..f90f02aad892 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractor.kt @@ -70,7 +70,14 @@ constructor( ) { private val keyguardOccludedByApp: Flow<Boolean> = if (KeyguardWmStateRefactor.isEnabled) { - keyguardTransitionInteractor.currentKeyguardState.map { it == KeyguardState.OCCLUDED } + combine( + keyguardTransitionInteractor.currentKeyguardState, + communalSceneInteractor.isIdleOnCommunal, + ::Pair, + ) + .map { (currentState, isIdleOnCommunal) -> + currentState == KeyguardState.OCCLUDED && !isIdleOnCommunal + } } else { combine( keyguardInteractor.isKeyguardOccluded, @@ -120,7 +127,7 @@ constructor( // On fingerprint success when the screen is on and not dreaming, go to the home screen fingerprintUnlockSuccessEvents .sample( - combine(powerInteractor.isInteractive, keyguardInteractor.isDreaming, ::Pair), + combine(powerInteractor.isInteractive, keyguardInteractor.isDreaming, ::Pair) ) .collect { (interactive, dreaming) -> if (interactive && !dreaming) { @@ -148,7 +155,7 @@ constructor( } }, /* cancel= */ null, - /* afterKeyguardGone */ false + /* afterKeyguardGone */ false, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt index a327e4a76c49..e68aba5360d0 100644 --- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt @@ -45,6 +45,7 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterIsInstance +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach @@ -73,6 +74,14 @@ interface DisplayRepository { /** Whether the default display is currently off. */ val defaultDisplayOff: Flow<Boolean> + /** + * Given a display ID int, return the corresponding Display object, or null if none exist. + * + * This method is guaranteed to not result in any binder call. + */ + suspend fun getDisplay(displayId: Int): Display? = + displays.first().firstOrNull { it.displayId == displayId } + /** Represents a connected display that has not been enabled yet. */ interface PendingDisplay { /** Id of the pending display. */ @@ -135,7 +144,9 @@ constructor( allDisplayEvents.filterIsInstance<DisplayEvent.Changed>().map { event -> event.displayId } override val displayAdditionEvent: Flow<Display?> = - allDisplayEvents.filterIsInstance<DisplayEvent.Added>().map { getDisplay(it.displayId) } + allDisplayEvents.filterIsInstance<DisplayEvent.Added>().map { + getDisplayFromDisplayManager(it.displayId) + } // This is necessary because there might be multiple displays, and we could // have missed events for those added before this process or flow started. @@ -160,7 +171,8 @@ constructor( .debugLog("enabledDisplayIds") private val defaultDisplay by lazy { - getDisplay(Display.DEFAULT_DISPLAY) ?: error("Unable to get default display.") + getDisplayFromDisplayManager(Display.DEFAULT_DISPLAY) + ?: error("Unable to get default display.") } /** @@ -170,7 +182,7 @@ constructor( */ private val enabledDisplays: Flow<Set<Display>> = enabledDisplayIds - .mapElementsLazily { displayId -> getDisplay(displayId) } + .mapElementsLazily { displayId -> getDisplayFromDisplayManager(displayId) } .onEach { if (it.isEmpty()) Log.wtf(TAG, "No enabled displays. This should never happen.") } @@ -269,7 +281,7 @@ constructor( private fun getDisplayType(displayId: Int): Int? = traceSection("$TAG#getDisplayType") { displayManager.getDisplay(displayId)?.type } - private fun getDisplay(displayId: Int): Display? = + private fun getDisplayFromDisplayManager(displayId: Int): Display? = traceSection("$TAG#getDisplay") { displayManager.getDisplay(displayId) } /** @@ -354,8 +366,8 @@ constructor( * Maps a set of T to a set of V, minimizing the number of `createValue` calls taking into * account the diff between each root flow emission. * - * This is needed to minimize the number of [getDisplay] in this class. Note that if the - * [createValue] returns a null element, it will not be added in the output set. + * This is needed to minimize the number of [getDisplayFromDisplayManager] in this class. Note + * that if the [createValue] returns a null element, it will not be added in the output set. */ private fun <T, V> Flow<Set<T>>.mapElementsLazily(createValue: (T) -> V?): Flow<Set<V>> { data class State<T, V>( 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 77c54ec1eac3..3992c3fb70b0 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.SupervisorJob 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 @@ constructor( ) : 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 7e2c9f89fa67..4caf95b707b1 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 @@ interface ContextualEducationModule { 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/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt index b27135674fb1..f32c94b2bc01 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 android.graphics.PorterDuffColorFilter 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.fillMaxSize 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 @@ import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionSta 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 @@ fun ActionTutorialContent( 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 @@ fun TutorialDescription( @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 TutorialDescription( fun TutorialAnimation( actionState: TutorialActionState, config: TutorialScreenConfig, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, ) { Box(modifier = modifier.fillMaxWidth()) { AnimatedContent( @@ -152,18 +157,18 @@ fun TutorialAnimation( // 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 @@ fun TutorialAnimation( @Composable private fun FrozenSuccessAnimation( @RawRes successAnimationId: Int, - animationProperties: LottieDynamicProperties + animationProperties: LottieDynamicProperties, ) { val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(successAnimationId)) LottieAnimation( @@ -188,7 +193,7 @@ private fun FrozenSuccessAnimation( @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 @@ private fun EducationAnimation( @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 @@ private fun SuccessAnimation( @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 93cd1cf487b0..5e05dab3d6cd 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 @@ -403,7 +403,7 @@ private fun ShortcutSubCategorySinglePane(searchQuery: String, subCategory: Shor SubCategoryTitle(subCategory.label) subCategory.shortcuts.fastForEachIndexed { index, shortcut -> if (index > 0) { - HorizontalDivider() + HorizontalDivider(color = MaterialTheme.colorScheme.surfaceContainerHigh) } ShortcutView(Modifier.padding(vertical = 24.dp), searchQuery, shortcut) } @@ -482,7 +482,7 @@ private fun SubCategoryContainerDualPane(searchQuery: String, subCategory: Short Spacer(Modifier.height(8.dp)) subCategory.shortcuts.fastForEachIndexed { index, shortcut -> if (index > 0) { - HorizontalDivider() + HorizontalDivider(color = MaterialTheme.colorScheme.surfaceContainerHigh) } ShortcutView(Modifier.padding(vertical = 16.dp), searchQuery, shortcut) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index ba23eb341b89..0a38ce07a798 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -3314,7 +3314,11 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, setShowingLocked(false, "onKeyguardExitFinished: " + reason); mWakeAndUnlocking = false; - mDismissCallbackRegistry.notifyDismissSucceeded(); + + if (!KeyguardWmStateRefactor.isEnabled()) { + mDismissCallbackRegistry.notifyDismissSucceeded(); + } + resetKeyguardDonePendingLocked(); mHideAnimationRun = false; adjustStatusBarLocked(); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt index 49303e089036..130242f55600 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt @@ -58,6 +58,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.mapLatest @@ -486,19 +487,34 @@ constructor( override val isDreaming: MutableStateFlow<Boolean> = MutableStateFlow(false) - override val linearDozeAmount: Flow<Float> = conflatedCallbackFlow { - val callback = - object : StatusBarStateController.StateListener { - override fun onDozeAmountChanged(linear: Float, eased: Float) { - trySendWithFailureLogging(linear, TAG, "updated dozeAmount") - } - } + private val _preSceneLinearDozeAmount: Flow<Float> = + if (SceneContainerFlag.isEnabled) { + emptyFlow() + } else { + conflatedCallbackFlow { + val callback = + object : StatusBarStateController.StateListener { + override fun onDozeAmountChanged(linear: Float, eased: Float) { + trySendWithFailureLogging(linear, TAG, "updated dozeAmount") + } + } - statusBarStateController.addCallback(callback) - trySendWithFailureLogging(statusBarStateController.dozeAmount, TAG, "initial dozeAmount") + statusBarStateController.addCallback(callback) + trySendWithFailureLogging( + statusBarStateController.dozeAmount, + TAG, + "initial dozeAmount" + ) - awaitClose { statusBarStateController.removeCallback(callback) } - } + awaitClose { statusBarStateController.removeCallback(callback) } + } + } + + override val linearDozeAmount: Flow<Float> + get() { + SceneContainerFlag.assertInLegacyMode() + return _preSceneLinearDozeAmount + } override val dozeTransitionModel: Flow<DozeTransitionModel> = conflatedCallbackFlow { val callback = 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 b0820a747e17..8c7fe5f87a3f 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 @@ -150,7 +150,9 @@ constructor( if (!SceneContainerFlag.isEnabled) { startTransitionTo(KeyguardState.GLANCEABLE_HUB) } - } else if (isCommunalAvailable && dreamManager.canStartDreaming(true)) { + } else if (isCommunalAvailable && dreamManager.canStartDreaming(false)) { + // Using false for isScreenOn as canStartDreaming returns false if any + // dream, including doze, is active. // This case handles tapping the power button to transition through // dream -> off -> hub. if (!SceneContainerFlag.isEnabled) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt index 2434b29c0cdd..9a0a85823929 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt @@ -17,9 +17,12 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator +import android.annotation.SuppressLint +import android.app.DreamManager import com.android.app.animation.Interpolators import com.android.app.tracing.coroutines.launch 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.model.CommunalScenes @@ -60,10 +63,12 @@ constructor( @Main mainDispatcher: CoroutineDispatcher, keyguardInteractor: KeyguardInteractor, private val glanceableHubTransitions: GlanceableHubTransitions, + private val communalInteractor: CommunalInteractor, private val communalSceneInteractor: CommunalSceneInteractor, private val communalSettingsInteractor: CommunalSettingsInteractor, powerInteractor: PowerInteractor, keyguardOcclusionInteractor: KeyguardOcclusionInteractor, + private val dreamManager: DreamManager, private val deviceEntryInteractor: DeviceEntryInteractor, ) : TransitionInteractor( @@ -76,6 +81,7 @@ constructor( keyguardInteractor = keyguardInteractor, ) { + @SuppressLint("MissingPermission") override fun start() { listenForDreamingToAlternateBouncer() listenForDreamingToOccluded() @@ -86,6 +92,8 @@ constructor( listenForTransitionToCamera(scope, keyguardInteractor) if (!communalSceneKtfRefactor()) { listenForDreamingToGlanceableHub() + } else { + listenForDreamingToGlanceableHubFromPowerButton() } listenForDreamingToPrimaryBouncer() } @@ -112,6 +120,34 @@ constructor( } } + /** + * Normally when pressing power button from the dream, the devices goes from DREAMING to DOZING, + * then [FromDozingTransitionInteractor] handles the transition to GLANCEABLE_HUB. However if + * the power button is pressed quickly, we may need to go directly from DREAMING to + * GLANCEABLE_HUB as the transition to DOZING has not occurred yet. + */ + @SuppressLint("MissingPermission") + private fun listenForDreamingToGlanceableHubFromPowerButton() { + if (!communalSettingsInteractor.isCommunalFlagEnabled()) return + if (SceneContainerFlag.isEnabled) return + scope.launch { + powerInteractor.isAwake + .debounce(50L) + .filterRelevantKeyguardStateAnd { isAwake -> isAwake } + .sample(communalInteractor.isCommunalAvailable) + .collect { isCommunalAvailable -> + if (isCommunalAvailable && dreamManager.canStartDreaming(false)) { + // This case handles tapping the power button to transition through + // dream -> off -> hub. + communalSceneInteractor.snapToScene( + newScene = CommunalScenes.Communal, + loggingReason = "from dreaming to hub", + ) + } + } + } + } + private fun listenForDreamingToPrimaryBouncer() { // TODO(b/336576536): Check if adaptation for scene framework is needed if (SceneContainerFlag.isEnabled) return @@ -144,7 +180,7 @@ constructor( } else { startTransitionTo( KeyguardState.LOCKSCREEN, - ownerReason = "Dream has ended and device is awake" + ownerReason = "Dream has ended and device is awake", ) } } @@ -158,15 +194,14 @@ constructor( scope.launch { combine( keyguardInteractor.isKeyguardOccluded, - keyguardInteractor.isAbleToDream - // Debounce the dreaming signal since there is a race condition between - // the occluded and dreaming signals. We therefore add a small delay - // to give enough time for occluded to flip to false when the dream - // ends, to avoid transitioning to OCCLUDED erroneously when exiting - // the dream. - .debounce(100.milliseconds), - ::Pair + keyguardInteractor.isDreaming, + ::Pair, ) + // Debounce signals since there is a race condition between the occluded and + // dreaming signals when starting or stopping dreaming. We therefore add a small + // delay to give enough time for occluded to flip to false when the dream + // ends, to avoid transitioning to OCCLUDED erroneously when exiting the dream. + .debounce(100.milliseconds) .filterRelevantKeyguardStateAnd { (isOccluded, isDreaming) -> isOccluded && !isDreaming } @@ -194,12 +229,12 @@ constructor( if (dismissable) { startTransitionTo( KeyguardState.GONE, - ownerReason = "No longer dreaming; dismissable" + ownerReason = "No longer dreaming; dismissable", ) } else { startTransitionTo( KeyguardState.LOCKSCREEN, - ownerReason = "No longer dreaming" + ownerReason = "No longer dreaming", ) } } 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 7759298cb32a..6b6a3dce630a 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 @@ -202,15 +202,15 @@ constructor( scope.launch { combine( keyguardInteractor.isKeyguardOccluded, - keyguardInteractor.isAbleToDream - // Debounce the dreaming signal since there is a race condition between - // the occluded and dreaming signals. We therefore add a small delay - // to give enough time for occluded to flip to false when the dream - // ends, to avoid transitioning to OCCLUDED erroneously when exiting - // the dream. - .debounce(100.milliseconds), + keyguardInteractor.isDreaming, ::Pair, ) + // Debounce signals since there is a race condition between the occluded and + // dreaming signals when starting or stopping dreaming. We therefore add a small + // delay to give enough time for occluded to flip to false when the dream + // ends, to avoid transitioning to OCCLUDED erroneously when exiting the dream + // or when the dream starts underneath the hub. + .debounce(200.milliseconds) .sampleFilter( // When launching activities from widgets on the hub, we have a // custom occlusion animation. 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 eb9b07add12d..ea80911335fa 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 @@ constructor( powerInteractor: PowerInteractor, alternateBouncerInteractor: AlternateBouncerInteractor, shadeInteractor: Lazy<ShadeInteractor>, + keyguardInteractor: Lazy<KeyguardInteractor>, ) { val dismissAction: Flow<DismissAction> = repository.dismissAction @@ -111,9 +112,9 @@ constructor( } 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/domain/interactor/KeyguardDismissInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt index 4457f1dfaf09..9b9bdd1bde9b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt @@ -23,12 +23,10 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.DismissCallbackRegistry -import com.android.systemui.keyguard.KeyguardWmStateRefactor import com.android.systemui.keyguard.data.repository.KeyguardRepository import com.android.systemui.keyguard.data.repository.TrustRepository import com.android.systemui.keyguard.shared.model.DismissAction import com.android.systemui.keyguard.shared.model.KeyguardDone -import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.kotlin.Utils.Companion.toQuad @@ -37,7 +35,6 @@ import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map @@ -59,7 +56,6 @@ constructor( trustRepository: TrustRepository, alternateBouncerInteractor: AlternateBouncerInteractor, powerInteractor: PowerInteractor, - keyguardTransitionInteractor: KeyguardTransitionInteractor, ) { /* * Updates when a biometric has authenticated the device and is requesting to dismiss @@ -165,14 +161,4 @@ constructor( } } } - - init { - if (KeyguardWmStateRefactor.isEnabled) { - scope.launch { - keyguardTransitionInteractor.currentKeyguardState - .filter { it == KeyguardState.GONE } - .collect { dismissCallbackRegistry.notifyDismissSucceeded() } - } - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt index e444092bd175..e6ee11215595 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt @@ -140,12 +140,6 @@ constructor( _notificationPlaceholderBounds.value = position } - /** - * The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at - * all. - */ - val dozeAmount: Flow<Float> = repository.linearDozeAmount - /** Whether the system is in doze mode. */ val isDozing: StateFlow<Boolean> = repository.isDozing @@ -155,6 +149,23 @@ constructor( /** Whether Always-on Display mode is available. */ val isAodAvailable: StateFlow<Boolean> = repository.isAodAvailable + /** + * The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at + * all. + */ + val dozeAmount: Flow<Float> = + if (SceneContainerFlag.isEnabled) { + isAodAvailable.flatMapLatest { isAodAvailable -> + if (isAodAvailable) { + keyguardTransitionInteractor.transitionValue(AOD) + } else { + keyguardTransitionInteractor.transitionValue(DOZING) + } + } + } else { + repository.linearDozeAmount + } + /** Doze transition information. */ val dozeTransitionModel: Flow<DozeTransitionModel> = repository.dozeTransitionModel @@ -164,8 +175,8 @@ constructor( val isDreamingWithOverlay: Flow<Boolean> = repository.isDreamingWithOverlay /** - * Whether the system is dreaming. [isDreaming] will be always be true when [isDozing] is true, - * but not vice-versa. Also accounts for [isDreamingWithOverlay] + * Whether the system is dreaming. [KeyguardRepository.isDreaming] will be always be true when + * [isDozing] is true, but not vice-versa. Also accounts for [isDreamingWithOverlay]. */ val isDreaming: StateFlow<Boolean> = merge(repository.isDreaming, repository.isDreamingWithOverlay) @@ -175,6 +186,9 @@ constructor( initialValue = false, ) + /** Whether any dreaming is running, including the doze dream. */ + val isDreamingAny: Flow<Boolean> = repository.isDreaming + /** Whether the system is dreaming and the active dream is hosted in lockscreen */ val isActiveDreamLockscreenHosted: StateFlow<Boolean> = repository.isActiveDreamLockscreenHosted diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt index 7fd348b8b40e..6fe4ff5122d0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.domain.interactor +import android.app.trust.TrustManager import android.os.DeadObjectException import android.os.RemoteException import com.android.internal.policy.IKeyguardStateCallback @@ -24,6 +25,7 @@ import com.android.systemui.bouncer.domain.interactor.SimBouncerInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.KeyguardWmStateRefactor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.scene.shared.flag.SceneContainerFlag @@ -32,7 +34,6 @@ import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -53,6 +54,9 @@ constructor( private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val trustInteractor: TrustInteractor, private val simBouncerInteractor: SimBouncerInteractor, + private val dismissCallbackRegistry: DismissCallbackRegistry, + private val wmLockscreenVisibilityInteractor: WindowManagerLockscreenVisibilityInteractor, + private val trustManager: TrustManager, ) : CoreStartable { private val callbacks = mutableListOf<IKeyguardStateCallback>() @@ -62,28 +66,31 @@ constructor( } applicationScope.launch { - combine( - selectedUserInteractor.selectedUser, - keyguardTransitionInteractor.currentKeyguardState, - keyguardTransitionInteractor.startedKeyguardTransitionStep, - ::Triple, - ) - .collectLatest { (selectedUser, _, _) -> - val iterator = callbacks.iterator() - withContext(backgroundDispatcher) { - while (iterator.hasNext()) { - val callback = iterator.next() - try { - callback.onShowingStateChanged(!isIdleInGone(), selectedUser) - callback.onInputRestrictedStateChanged(!isIdleInGone()) - } catch (e: RemoteException) { - if (e is DeadObjectException) { - iterator.remove() - } + wmLockscreenVisibilityInteractor.lockscreenVisibility.collectLatest { visible -> + val iterator = callbacks.iterator() + withContext(backgroundDispatcher) { + while (iterator.hasNext()) { + val callback = iterator.next() + try { + callback.onShowingStateChanged( + visible, + selectedUserInteractor.getSelectedUserId(), + ) + callback.onInputRestrictedStateChanged(visible) + + trustManager.reportKeyguardShowingChanged() + + if (!visible) { + dismissCallbackRegistry.notifyDismissSucceeded() + } + } catch (e: RemoteException) { + if (e is DeadObjectException) { + iterator.remove() } } } } + } } applicationScope.launch { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt index b89eb2723fab..cf9d60fff2c6 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt @@ -19,6 +19,7 @@ package com.android.systemui.keyguard.domain.interactor import com.android.keyguard.logging.KeyguardLogger import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.log.core.LogLevel.VERBOSE import com.android.systemui.power.domain.interactor.PowerInteractor @@ -44,6 +45,7 @@ constructor( private val powerInteractor: PowerInteractor, private val sharedNotificationContainerViewModel: SharedNotificationContainerViewModel, private val keyguardRootViewModel: KeyguardRootViewModel, + private val aodBurnInViewModel: AodBurnInViewModel, private val shadeInteractor: ShadeInteractor, private val keyguardOcclusionInteractor: KeyguardOcclusionInteractor, ) { @@ -132,7 +134,7 @@ constructor( } scope.launch { - keyguardRootViewModel.burnInModel.debounce(20L).collect { + aodBurnInViewModel.movement.debounce(20L).collect { logger.log(TAG, VERBOSE, "BurnInModel (debounced)", it) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt index ba9f01862e8e..5f76f643b2fe 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt @@ -32,6 +32,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.shared.model.ClockSize import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection +import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.lifecycle.repeatWhenAttached @@ -58,6 +59,7 @@ object KeyguardClockViewBinder { keyguardClockInteractor: KeyguardClockInteractor, blueprintInteractor: KeyguardBlueprintInteractor, rootViewModel: KeyguardRootViewModel, + aodBurnInViewModel: AodBurnInViewModel, ): DisposableHandle { val disposables = DisposableHandles() disposables += @@ -78,7 +80,7 @@ object KeyguardClockViewBinder { updateBurnInLayer( keyguardRootView, viewModel, - viewModel.clockSize.value + viewModel.clockSize.value, ) applyConstraints(clockSection, keyguardRootView, true) } @@ -114,7 +116,7 @@ object KeyguardClockViewBinder { if (!MigrateClocksToBlueprint.isEnabled) return@launch combine( viewModel.hasAodIcons, - rootViewModel.isNotifIconContainerVisible.map { it.value } + rootViewModel.isNotifIconContainerVisible.map { it.value }, ) { hasIcon, isVisible -> hasIcon && isVisible } @@ -130,13 +132,13 @@ object KeyguardClockViewBinder { launch { if (!MigrateClocksToBlueprint.isEnabled) return@launch - rootViewModel.burnInModel.collect { burnInModel -> + aodBurnInViewModel.movement.collect { burnInModel -> viewModel.currentClock.value?.let { it.largeClock.layout.applyAodBurnIn( AodClockBurnInModel( translationX = burnInModel.translationX.toFloat(), translationY = burnInModel.translationY.toFloat(), - scale = burnInModel.scale + scale = burnInModel.scale, ) ) } @@ -175,7 +177,7 @@ object KeyguardClockViewBinder { private fun cleanupClockViews( currentClock: ClockController?, rootView: ConstraintLayout, - burnInLayer: Layer? + burnInLayer: Layer?, ) { if (lastClock == currentClock) { return @@ -192,10 +194,7 @@ object KeyguardClockViewBinder { } @VisibleForTesting - fun addClockViews( - clockController: ClockController?, - rootView: ConstraintLayout, - ) { + fun addClockViews(clockController: ClockController?, rootView: ConstraintLayout) { // We'll collect the same clock when exiting wallpaper picker without changing clock // so we need to remove clock views from parent before addView again clockController?.let { clock -> 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 b5f6b418e322..ee2ee522cd0e 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 @@ -45,7 +45,6 @@ import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD import com.android.keyguard.AuthInteractionProperties import com.android.systemui.Flags import com.android.systemui.Flags.msdlFeedback -import com.android.systemui.Flags.newAodTransition import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.shared.model.Text import com.android.systemui.common.shared.model.TintedIcon @@ -261,10 +260,7 @@ object KeyguardRootViewBinder { -> 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") @@ -327,6 +323,9 @@ object KeyguardRootViewBinder { .getDimensionPixelSize(R.dimen.shelf_appear_translation) .stateIn(this) viewModel.isNotifIconContainerVisible.collect { isVisible -> + if (isVisible.value) { + blueprintViewModel.refreshBlueprint() + } childViews[aodNotificationIconContainerId] ?.setAodNotifIconContainerIsVisible( isVisible, @@ -382,7 +381,7 @@ object KeyguardRootViewBinder { if (msdlFeedback()) { msdlPlayer?.playToken( MSDLToken.UNLOCK, - authInteractionProperties + authInteractionProperties, ) } else { vibratorHelper.performHapticFeedback( @@ -398,7 +397,7 @@ object KeyguardRootViewBinder { if (msdlFeedback()) { msdlPlayer?.playToken( MSDLToken.FAILURE, - authInteractionProperties + authInteractionProperties, ) } else { vibratorHelper.performHapticFeedback( @@ -414,7 +413,10 @@ object KeyguardRootViewBinder { if (MigrateClocksToBlueprint.isEnabled) { burnInParams.update { current -> - current.copy(translationY = { childViews[burnInLayerId]?.translationY }) + current.copy( + translationX = { childViews[burnInLayerId]?.translationX }, + translationY = { childViews[burnInLayerId]?.translationY }, + ) } } @@ -425,7 +427,7 @@ object KeyguardRootViewBinder { blueprintViewModel, clockViewModel, childViews, - burnInParams + burnInParams, ) ) @@ -464,11 +466,7 @@ object KeyguardRootViewBinder { */ 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, @@ -499,7 +497,7 @@ object KeyguardRootViewBinder { oldLeft: Int, oldTop: Int, oldRight: Int, - oldBottom: Int + oldBottom: Int, ) { // After layout, ensure the notifications are positioned correctly childViews[nsslPlaceholderId]?.let { notificationListPlaceholder -> @@ -515,7 +513,7 @@ object KeyguardRootViewBinder { viewModel.onNotificationContainerBoundsChanged( notificationListPlaceholder.top.toFloat(), notificationListPlaceholder.bottom.toFloat(), - animate = shouldAnimate + animate = shouldAnimate, ) } @@ -531,7 +529,7 @@ object KeyguardRootViewBinder { Int.MAX_VALUE } else { view.getTop() - } + }, ) } } else { @@ -597,7 +595,7 @@ object KeyguardRootViewBinder { View.INVISIBLE } } - newAodTransition() -> { + else -> { animateInIconTranslation() if (isVisible.value) { CrossFadeHelper.fadeIn(this, animatorListener) @@ -605,52 +603,6 @@ object KeyguardRootViewBinder { CrossFadeHelper.fadeOut(this, animatorListener) } } - !isVisible.value -> { - // Let's make sure the icon are translated to 0, since we cancelled it above - animateInIconTranslation() - CrossFadeHelper.fadeOut(this, animatorListener) - } - visibility != View.VISIBLE -> { - // No fading here, let's just appear the icons instead! - visibility = View.VISIBLE - alpha = 1f - appearIcons( - animate = screenOffAnimationController.shouldAnimateAodIcons(), - iconsAppearTranslationPx, - animatorListener, - ) - } - else -> { - // Let's make sure the icons are translated to 0, since we cancelled it above - animateInIconTranslation() - // We were fading out, let's fade in instead - CrossFadeHelper.fadeIn(this, animatorListener) - } - } - } - - private fun View.appearIcons( - animate: Boolean, - iconAppearTranslation: Int, - animatorListener: Animator.AnimatorListener, - ) { - if (animate) { - if (!MigrateClocksToBlueprint.isEnabled) { - translationY = -iconAppearTranslation.toFloat() - } - alpha = 0f - animate() - .alpha(1f) - .setInterpolator(Interpolators.LINEAR) - .setDuration(AOD_ICONS_APPEAR_DURATION) - .apply { if (MigrateClocksToBlueprint.isEnabled) animateInIconTranslation() } - .setListener(animatorListener) - .start() - } else { - alpha = 1.0f - if (!MigrateClocksToBlueprint.isEnabled) { - translationY = 0f - } } } 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 0b8f7417a49d..cef9a4eaf2bd 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 @@ constructor( 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/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt index be6b0eb79afe..ff848264db68 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt @@ -37,6 +37,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteract import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.keyguard.ui.binder.KeyguardClockViewBinder +import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel @@ -49,25 +50,17 @@ import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.DisposableHandle -internal fun ConstraintSet.setVisibility( - views: Iterable<View>, - visibility: Int, -) = views.forEach { view -> this.setVisibility(view.id, visibility) } +internal fun ConstraintSet.setVisibility(views: Iterable<View>, visibility: Int) = + views.forEach { view -> this.setVisibility(view.id, visibility) } -internal fun ConstraintSet.setAlpha( - views: Iterable<View>, - alpha: Float, -) = views.forEach { view -> this.setAlpha(view.id, alpha) } +internal fun ConstraintSet.setAlpha(views: Iterable<View>, alpha: Float) = + views.forEach { view -> this.setAlpha(view.id, alpha) } -internal fun ConstraintSet.setScaleX( - views: Iterable<View>, - alpha: Float, -) = views.forEach { view -> this.setScaleX(view.id, alpha) } +internal fun ConstraintSet.setScaleX(views: Iterable<View>, alpha: Float) = + views.forEach { view -> this.setScaleX(view.id, alpha) } -internal fun ConstraintSet.setScaleY( - views: Iterable<View>, - alpha: Float, -) = views.forEach { view -> this.setScaleY(view.id, alpha) } +internal fun ConstraintSet.setScaleY(views: Iterable<View>, alpha: Float) = + views.forEach { view -> this.setScaleY(view.id, alpha) } @SysUISingleton class ClockSection @@ -79,6 +72,7 @@ constructor( val smartspaceViewModel: KeyguardSmartspaceViewModel, val blueprintInteractor: Lazy<KeyguardBlueprintInteractor>, private val rootViewModel: KeyguardRootViewModel, + private val aodBurnInViewModel: AodBurnInViewModel, ) : KeyguardSection() { private var disposableHandle: DisposableHandle? = null @@ -97,6 +91,7 @@ constructor( clockInteractor, blueprintInteractor.get(), rootViewModel, + aodBurnInViewModel, ) } @@ -120,7 +115,7 @@ constructor( private fun buildConstraints( clock: ClockController, - constraintSet: ConstraintSet + constraintSet: ConstraintSet, ): ConstraintSet { // Add constraint between rootView and clockContainer applyDefaultConstraints(constraintSet) @@ -136,8 +131,8 @@ constructor( if (!keyguardClockViewModel.isLargeClockVisible.value) { connect(sharedR.id.bc_smartspace_view, TOP, sharedR.id.date_smartspace_view, BOTTOM) } else { - setScaleX(getTargetClockFace(clock).views, rootViewModel.burnInModel.value.scale) - setScaleY(getTargetClockFace(clock).views, rootViewModel.burnInModel.value.scale) + setScaleX(getTargetClockFace(clock).views, aodBurnInViewModel.movement.value.scale) + setScaleY(getTargetClockFace(clock).views, aodBurnInViewModel.movement.value.scale) } } } @@ -156,7 +151,7 @@ constructor( R.id.weather_clock_bc_smartspace_bottom, Barrier.BOTTOM, getDimen(ENHANCED_SMARTSPACE_HEIGHT), - (custR.id.weather_clock_time) + (custR.id.weather_clock_time), ) if ( rootViewModel.isNotifIconContainerVisible.value.value && @@ -168,15 +163,15 @@ constructor( 0, *intArrayOf( R.id.aod_notification_icon_container, - R.id.weather_clock_bc_smartspace_bottom - ) + R.id.weather_clock_bc_smartspace_bottom, + ), ) } else { createBarrier( R.id.weather_clock_date_and_icons_barrier_bottom, Barrier.BOTTOM, 0, - *intArrayOf(R.id.weather_clock_bc_smartspace_bottom) + *intArrayOf(R.id.weather_clock_bc_smartspace_bottom), ) } } @@ -204,7 +199,7 @@ constructor( constrainWidth(R.id.lockscreen_clock_view, WRAP_CONTENT) constrainHeight( R.id.lockscreen_clock_view, - context.resources.getDimensionPixelSize(custR.dimen.small_clock_height) + context.resources.getDimensionPixelSize(custR.dimen.small_clock_height), ) connect( R.id.lockscreen_clock_view, @@ -212,7 +207,7 @@ constructor( PARENT_ID, START, context.resources.getDimensionPixelSize(custR.dimen.clock_padding_start) + - context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal) + context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal), ) val smallClockTopMargin = keyguardClockViewModel.getSmallClockTopMargin() create(R.id.small_clock_guideline_top, ConstraintSet.HORIZONTAL_GUIDELINE) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt index 62b47827fe8a..c78e0c9f5266 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt @@ -23,6 +23,7 @@ import android.util.MathUtils import com.android.app.animation.Interpolators import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.keyguard.domain.interactor.BurnInInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor @@ -34,13 +35,17 @@ import com.android.systemui.keyguard.ui.StateToValue import com.android.systemui.res.R import javax.inject.Inject import kotlin.math.max +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn /** * Models UI state for elements that need to apply anti-burn-in tactics when showing in AOD @@ -50,6 +55,7 @@ import kotlinx.coroutines.flow.onStart class AodBurnInViewModel @Inject constructor( + @Application private val applicationScope: CoroutineScope, private val burnInInteractor: BurnInInteractor, private val configurationInteractor: ConfigurationInteractor, private val keyguardInteractor: KeyguardInteractor, @@ -61,91 +67,109 @@ constructor( private val keyguardClockViewModel: KeyguardClockViewModel, ) { private val TAG = "AodBurnInViewModel" + private val burnInParams = MutableStateFlow(BurnInParameters()) - /** All burn-in movement: x,y,scale, to shift items and prevent burn-in */ - fun movement( - burnInParams: BurnInParameters, - ): Flow<BurnInModel> { - val params = - if (burnInParams.minViewY < burnInParams.topInset) { + fun updateBurnInParams(params: BurnInParameters) { + burnInParams.value = + if (params.minViewY < params.topInset) { // minViewY should never be below the inset. Correct it if needed - Log.w(TAG, "minViewY is below topInset: $burnInParams") - burnInParams.copy(minViewY = burnInParams.topInset) + Log.w(TAG, "minViewY is below topInset: $params") + params.copy(minViewY = params.topInset) } else { - burnInParams + params } - return configurationInteractor - .dimensionPixelSize( - setOf( - R.dimen.keyguard_enter_from_top_translation_y, - R.dimen.keyguard_enter_from_side_translation_x, - ) - ) - .flatMapLatest { dimens -> - combine( - keyguardInteractor.keyguardTranslationY.onStart { emit(0f) }, - burnIn(params).onStart { emit(BurnInModel()) }, - goneToAodTransitionViewModel - .enterFromTopTranslationY( - dimens[R.dimen.keyguard_enter_from_top_translation_y]!! - ) - .onStart { emit(StateToValue()) }, - goneToAodTransitionViewModel - .enterFromSideTranslationX( - dimens[R.dimen.keyguard_enter_from_side_translation_x]!! - ) - .onStart { emit(StateToValue()) }, - lockscreenToAodTransitionViewModel - .enterFromSideTranslationX( - dimens[R.dimen.keyguard_enter_from_side_translation_x]!! + } + + /** All burn-in movement: x,y,scale, to shift items and prevent burn-in */ + val movement: StateFlow<BurnInModel> = + burnInParams + .flatMapLatest { params -> + configurationInteractor + .dimensionPixelSize( + setOf( + R.dimen.keyguard_enter_from_top_translation_y, + R.dimen.keyguard_enter_from_side_translation_x, ) - .onStart { emit(StateToValue()) }, - occludedToLockscreenTransitionViewModel.lockscreenTranslationY.onStart { - emit(0f) - }, - aodToLockscreenTransitionViewModel.translationY(params.translationY).onStart { - emit(StateToValue()) - }, - ) { flows -> - val keyguardTranslationY = flows[0] as Float - val burnInModel = flows[1] as BurnInModel - val goneToAodTranslationY = flows[2] as StateToValue - val goneToAodTranslationX = flows[3] as StateToValue - val lockscreenToAodTranslationX = flows[4] as StateToValue - val occludedToLockscreen = flows[5] as Float - val aodToLockscreen = flows[6] as StateToValue + ) + .flatMapLatest { dimens -> + combine( + keyguardInteractor.keyguardTranslationY.onStart { emit(0f) }, + burnIn(params).onStart { emit(BurnInModel()) }, + goneToAodTransitionViewModel + .enterFromTopTranslationY( + dimens[R.dimen.keyguard_enter_from_top_translation_y]!! + ) + .onStart { emit(StateToValue()) }, + goneToAodTransitionViewModel + .enterFromSideTranslationX( + dimens[R.dimen.keyguard_enter_from_side_translation_x]!! + ) + .onStart { emit(StateToValue()) }, + lockscreenToAodTransitionViewModel + .enterFromSideTranslationX( + dimens[R.dimen.keyguard_enter_from_side_translation_x]!! + ) + .onStart { emit(StateToValue()) }, + occludedToLockscreenTransitionViewModel.lockscreenTranslationY.onStart { + emit(0f) + }, + aodToLockscreenTransitionViewModel + .translationX(params.translationX) + .onStart { emit(StateToValue()) }, + aodToLockscreenTransitionViewModel + .translationY(params.translationY) + .onStart { emit(StateToValue()) }, + ) { flows -> + val keyguardTranslationY = flows[0] as Float + val burnInModel = flows[1] as BurnInModel + val goneToAodTranslationY = flows[2] as StateToValue + val goneToAodTranslationX = flows[3] as StateToValue + val lockscreenToAodTranslationX = flows[4] as StateToValue + val occludedToLockscreen = flows[5] as Float + val aodToLockscreenTranslationX = flows[6] as StateToValue + val aodToLockscreenTranslationY = flows[7] as StateToValue - val translationY = - if (aodToLockscreen.transitionState.isTransitioning()) { - aodToLockscreen.value ?: 0f - } else if (goneToAodTranslationY.transitionState.isTransitioning()) { - (goneToAodTranslationY.value ?: 0f) + burnInModel.translationY - } else { - burnInModel.translationY + occludedToLockscreen + keyguardTranslationY + val translationY = + if (aodToLockscreenTranslationY.transitionState.isTransitioning()) { + aodToLockscreenTranslationY.value ?: 0f + } else if ( + goneToAodTranslationY.transitionState.isTransitioning() + ) { + (goneToAodTranslationY.value ?: 0f) + burnInModel.translationY + } else { + burnInModel.translationY + + occludedToLockscreen + + keyguardTranslationY + } + val translationX = + if (aodToLockscreenTranslationX.transitionState.isTransitioning()) { + aodToLockscreenTranslationX.value ?: 0f + } else { + burnInModel.translationX + + (goneToAodTranslationX.value ?: 0f) + + (lockscreenToAodTranslationX.value ?: 0f) + } + burnInModel.copy( + translationX = translationX.toInt(), + translationY = translationY.toInt(), + ) } - val translationX = - burnInModel.translationX + - (goneToAodTranslationX.value ?: 0f) + - (lockscreenToAodTranslationX.value ?: 0f) - burnInModel.copy( - translationX = translationX.toInt(), - translationY = translationY.toInt(), - ) - } + } } - .distinctUntilChanged() - } + .stateIn( + scope = applicationScope, + started = SharingStarted.WhileSubscribed(), + initialValue = BurnInModel(), + ) - private fun burnIn( - params: BurnInParameters, - ): Flow<BurnInModel> { + private fun burnIn(params: BurnInParameters): Flow<BurnInModel> { return combine( keyguardTransitionInteractor.transitionValue(KeyguardState.AOD).map { Interpolators.FAST_OUT_SLOW_IN.getInterpolation(it) }, burnInInteractor.burnIn( xDimenResourceId = R.dimen.burn_in_prevention_offset_x, - yDimenResourceId = R.dimen.burn_in_prevention_offset_y + yDimenResourceId = R.dimen.burn_in_prevention_offset_y, ), ) { interpolated, burnIn -> val useAltAod = @@ -168,7 +192,7 @@ constructor( translationX = MathUtils.lerp(0, burnIn.translationX, interpolated).toInt(), translationY = translationY, scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolated), - scaleClockOnly = useScaleOnly + scaleClockOnly = useScaleOnly, ) } } @@ -181,7 +205,9 @@ data class BurnInParameters( /** The min y-value of the visible elements on lockscreen */ val minViewY: Int = Int.MAX_VALUE, /** The current y translation of the view */ - val translationY: () -> Float? = { null } + val translationY: () -> Float? = { null }, + /** The current x translation of the view */ + val translationX: () -> Float? = { null }, ) /** diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt index 6b22c0f07908..6eeab8db2a45 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt @@ -39,10 +39,8 @@ import kotlinx.coroutines.flow.Flow @SysUISingleton class AodToLockscreenTransitionViewModel @Inject -constructor( - shadeInteractor: ShadeInteractor, - animationFlow: KeyguardTransitionAnimationFlow, -) : DeviceEntryIconTransition { +constructor(shadeInteractor: ShadeInteractor, animationFlow: KeyguardTransitionAnimationFlow) : + DeviceEntryIconTransition { private val transitionAnimation = animationFlow.setup( @@ -54,7 +52,7 @@ constructor( /** * Begin the transition from wherever the y-translation value is currently. This helps ensure a - * smooth transition if a transition in canceled. + * smooth transition if the prior transition was canceled. */ fun translationY(currentTranslationY: () -> Float?): Flow<StateToValue> { var startValue = 0f @@ -65,6 +63,19 @@ constructor( ) } + /** + * Begin the transition from wherever the x-translation value is currently. This helps ensure a + * smooth transition if the prior transition was canceled. + */ + fun translationX(currentTranslationX: () -> Float?): Flow<StateToValue> { + var startValue = 0f + return transitionAnimation.sharedFlowWithState( + duration = 500.milliseconds, + onStart = { startValue = currentTranslationX() ?: 0f }, + onStep = { MathUtils.lerp(startValue, 0f, FAST_OUT_SLOW_IN.getInterpolation(it)) }, + ) + } + /** Ensure alpha is set to be visible */ fun lockscreenAlpha(viewState: ViewStateAccessor): Flow<Float> { var startAlpha = 1f diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModel.kt index aee34e1e713b..1e42e196bbc7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModel.kt @@ -26,6 +26,7 @@ import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition import com.android.systemui.scene.shared.model.Scenes import javax.inject.Inject import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf @SysUISingleton class DozingToGlanceableHubTransitionViewModel @@ -35,10 +36,16 @@ constructor(animationFlow: KeyguardTransitionAnimationFlow) : DeviceEntryIconTra animationFlow .setup( duration = TO_GLANCEABLE_HUB_DURATION, - edge = Edge.create(DOZING, Scenes.Communal) + edge = Edge.create(DOZING, Scenes.Communal), ) .setupWithoutSceneContainer(edge = Edge.create(DOZING, GLANCEABLE_HUB)) override val deviceEntryParentViewAlpha: Flow<Float> = transitionAnimation.immediatelyTransitionTo(1f) + + /** + * Hide notifications when transitioning directly from dozing to hub, such as when pressing + * power button when dozing and docked. + */ + val notificationAlpha: Flow<Float> = flowOf(0f) } 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 c6efcfad8da7..4cf3c4e7f6d0 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,20 +25,18 @@ import androidx.constraintlayout.widget.ConstraintLayout 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, - keyguardBlueprintInteractor: KeyguardBlueprintInteractor, + private val keyguardBlueprintInteractor: KeyguardBlueprintInteractor, ) { val blueprint = keyguardBlueprintInteractor.blueprint val blueprintId = keyguardBlueprintInteractor.blueprintId @@ -76,6 +74,9 @@ constructor( } } + fun refreshBlueprint(type: Type = Type.NoTransition) = + keyguardBlueprintInteractor.refreshBlueprint(type) + fun updateTransitions(data: TransitionData?, mutate: MutableSet<Transition>.() -> Unit) { runningTransitions.mutate() @@ -95,7 +96,7 @@ constructor( Log.w( TAG, "runTransition: skipping ${transition::class.simpleName}: " + - "currentPriority=$currentPriority; config=$config" + "currentPriority=$currentPriority; config=$config", ) } apply() @@ -106,7 +107,7 @@ constructor( 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/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt index 4b62eab08775..0d55709e94d6 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt @@ -179,14 +179,6 @@ constructor( } else { button(KeyguardQuickAffordancePosition.BOTTOM_START) } - .stateIn( - scope = applicationScope, - started = SharingStarted.Eagerly, - initialValue = - KeyguardQuickAffordanceViewModel( - slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId() - ), - ) /** An observable for the view-model of the "end button" quick affordance. */ val endButton: Flow<KeyguardQuickAffordanceViewModel> = @@ -200,14 +192,6 @@ constructor( } else { button(KeyguardQuickAffordancePosition.BOTTOM_END) } - .stateIn( - scope = applicationScope, - started = SharingStarted.Eagerly, - initialValue = - KeyguardQuickAffordanceViewModel( - slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId() - ), - ) /** * Notifies that a slot with the given ID has been selected in the preview experience that is diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt index 38ca888eee38..10a2e5c04b00 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt @@ -21,7 +21,6 @@ import android.graphics.Point import android.util.MathUtils import android.view.View.VISIBLE import com.android.app.tracing.coroutines.launch -import com.android.systemui.Flags.newAodTransition import com.android.systemui.common.shared.model.NotificationContainerBounds import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.dagger.SysUISingleton @@ -29,7 +28,6 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor -import com.android.systemui.keyguard.shared.model.BurnInModel import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.KeyguardState.AOD @@ -45,6 +43,7 @@ import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.ui.viewmodel.NotificationShadeWindowModel import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor +import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel import com.android.systemui.statusbar.phone.DozeParameters import com.android.systemui.statusbar.phone.ScreenOffAnimationController import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf @@ -58,12 +57,9 @@ import javax.inject.Inject import kotlin.math.max import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combineTransform import kotlinx.coroutines.flow.distinctUntilChanged @@ -86,6 +82,7 @@ constructor( private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor, notificationShadeWindowModel: NotificationShadeWindowModel, + private val aodNotificationIconViewModel: NotificationIconContainerAlwaysOnDisplayViewModel, private val alternateBouncerToAodTransitionViewModel: AlternateBouncerToAodTransitionViewModel, private val alternateBouncerToGoneTransitionViewModel: AlternateBouncerToGoneTransitionViewModel, @@ -127,10 +124,6 @@ constructor( private val aodAlphaViewModel: AodAlphaViewModel, private val shadeInteractor: ShadeInteractor, ) { - private var burnInJob: Job? = null - private val _burnInModel = MutableStateFlow(BurnInModel()) - val burnInModel = _burnInModel.asStateFlow() - val burnInLayerVisibility: Flow<Int> = keyguardTransitionInteractor.startedKeyguardTransitionStep .filter { it.to == AOD || it.to == LOCKSCREEN } @@ -139,7 +132,7 @@ constructor( val goneToAodTransition = keyguardTransitionInteractor.transition( edge = Edge.create(Scenes.Gone, AOD), - edgeWithoutSceneContainer = Edge.create(GONE, AOD) + edgeWithoutSceneContainer = Edge.create(GONE, AOD), ) private val goneToAodTransitionRunning: Flow<Boolean> = @@ -192,7 +185,7 @@ constructor( /* rangeMax = */ 1f, /* valueMin = */ 0f, /* valueMax = */ 0.2f, - /* value = */ max(qsExpansion, shadeExpansion) + /* value = */ max(qsExpansion, shadeExpansion), ) emit(alpha) } @@ -263,7 +256,7 @@ constructor( primaryBouncerToGoneTransitionViewModel.lockscreenAlpha, primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha(viewState), ) - .onStart { emit(1f) } + .onStart { emit(1f) }, ) { hideKeyguard, alpha -> if (hideKeyguard) { 0f @@ -283,30 +276,24 @@ constructor( /** For elements that appear and move during the animation -> AOD */ val burnInLayerAlpha: Flow<Float> = aodAlphaViewModel.alpha - val translationY: Flow<Float> = burnInModel.map { it.translationY.toFloat() } + val translationY: Flow<Float> = aodBurnInViewModel.movement.map { it.translationY.toFloat() } val translationX: Flow<StateToValue> = merge( - burnInModel.map { StateToValue(to = AOD, value = it.translationX.toFloat()) }, + aodBurnInViewModel.movement.map { + StateToValue(to = AOD, value = it.translationX.toFloat()) + }, lockscreenToGlanceableHubTransitionViewModel.keyguardTranslationX, glanceableHubToLockscreenTransitionViewModel.keyguardTranslationX, ) fun updateBurnInParams(params: BurnInParameters) { - burnInJob?.cancel() - - burnInJob = - applicationScope.launch("$TAG#aodBurnInViewModel") { - aodBurnInViewModel.movement(params).collect { _burnInModel.value = it } - } + aodBurnInViewModel.updateBurnInParams(params) } val scale: Flow<BurnInScaleViewModel> = - burnInModel.map { - BurnInScaleViewModel( - scale = it.scale, - scaleClockOnly = it.scaleClockOnly, - ) + aodBurnInViewModel.movement.map { + BurnInScaleViewModel(scale = it.scale, scaleClockOnly = it.scaleClockOnly) } /** Is the notification icon container visible? */ @@ -319,11 +306,12 @@ constructor( .onStart { emit(false) }, keyguardTransitionInteractor.isFinishedIn( scene = Scenes.Gone, - stateWithoutSceneContainer = GONE + stateWithoutSceneContainer = GONE, ), deviceEntryInteractor.isBypassEnabled, areNotifsFullyHiddenAnimated(), isPulseExpandingAnimated(), + aodNotificationIconViewModel.icons.map { it.visibleIcons.isNotEmpty() }, ) { flows -> val goneToAodTransitionRunning = flows[0] as Boolean val isOnLockscreen = flows[1] as Boolean @@ -331,6 +319,7 @@ constructor( val isBypassEnabled = flows[3] as Boolean val notifsFullyHidden = flows[4] as AnimatedValue<Boolean> val pulseExpanding = flows[5] as AnimatedValue<Boolean> + val hasAodIcons = flows[6] as Boolean when { // Hide the AOD icons if we're not in the KEYGUARD state unless the screen off @@ -342,9 +331,10 @@ constructor( else -> zip(notifsFullyHidden, pulseExpanding) { areNotifsFullyHidden, - isPulseExpanding, - -> + isPulseExpanding -> when { + // If there are no notification icons to show, then it can be hidden + !hasAodIcons -> false // If we're bypassing, then we're visible isBypassEnabled -> true // If we are pulsing (and not bypassing), then we are hidden @@ -396,10 +386,7 @@ constructor( !dozeParameters.alwaysOn -> false // Don't animate when going to AOD if the display needs blanking. dozeParameters.displayNeedsBlanking -> false - // We only want the appear animations to happen when the notifications - // get fully hidden, since otherwise the un-hide animation overlaps. - newAodTransition() -> true - else -> fullyHidden + else -> true } AnimatableEvent(fullyHidden, animate) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt index 75e38714f1fa..c5909ed24c50 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt @@ -107,8 +107,6 @@ constructor( } } - // TODO(b/365182034): move to interactor, add as dependency of SideFpsOverlayInteractor when - // rest to unlock feature is implemented val isVisible: Flow<Boolean> = _visible.asStateFlow() val progress: Flow<Float> = _progress.asStateFlow() diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt index c2b5d98699b4..555969859a1f 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.LifecycleOwner 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.collectLatest 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 @@ private fun createLifecycleOwnerAndRun( ): ViewLifecycleOwner { return ViewLifecycleOwner(view).apply { onCreate() - lifecycleScope.launch(nameForTrace, coroutineContext) { block(view) } + lifecycleScope.launch(coroutineContext) { traceCoroutine(nameForTrace) { block(view) } } } } @@ -367,7 +368,8 @@ private val ViewTreeObserver.isWindowVisible * 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/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt index bb9517a14142..a0fb0bf25c7b 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 @@ -110,6 +110,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @@ -174,19 +175,21 @@ constructor( * The desired location where we'll be at the end of the transformation. Usually this matches * the end location, except when we're still waiting on a state update call. */ - @MediaLocation private var desiredLocation: Int = -1 + @MediaLocation private var desiredLocation: Int = MediaHierarchyManager.LOCATION_UNKNOWN /** * The ending location of the view where it ends when all animations and transitions have * finished */ - @MediaLocation @VisibleForTesting var currentEndLocation: Int = -1 + @MediaLocation + @VisibleForTesting + var currentEndLocation: Int = MediaHierarchyManager.LOCATION_UNKNOWN /** * The ending location of the view where it ends when all animations and transitions have * finished */ - @MediaLocation private var currentStartLocation: Int = -1 + @MediaLocation private var currentStartLocation: Int = MediaHierarchyManager.LOCATION_UNKNOWN /** The progress of the transition or 1.0 if there is no transition happening */ private var currentTransitionProgress: Float = 1.0f @@ -726,6 +729,13 @@ constructor( ) DiffUtil.calculateDiff(diffUtilCallback).dispatchUpdatesTo(listUpdateCallback) setNewViewModelsList(it) + + // Update host visibility when media changes. + merge( + mediaCarouselViewModel.hasAnyMediaOrRecommendations, + mediaCarouselViewModel.hasActiveMediaOrRecommendations, + ) + .collect { updateHostVisibility() } } } } 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 8bec46abd504..70ca82492775 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 @@ public class MediaControlPanel { /** 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 @@ public class MediaControlPanel { // 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 @@ public class MediaControlPanel { // 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/controller/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt index 38cea5b23f78..745ab12c27d6 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt @@ -64,7 +64,6 @@ import com.android.systemui.util.settings.SecureSettings import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged @@ -161,10 +160,10 @@ constructor( private var animationStartAlpha = 0.0f /** The starting location of the cross fade if an animation is running right now. */ - @MediaLocation private var crossFadeAnimationStartLocation = -1 + @MediaLocation private var crossFadeAnimationStartLocation = LOCATION_UNKNOWN /** The end location of the cross fade if an animation is running right now. */ - @MediaLocation private var crossFadeAnimationEndLocation = -1 + @MediaLocation private var crossFadeAnimationEndLocation = LOCATION_UNKNOWN private var targetBounds: Rect = Rect() private val mediaFrame get() = mediaCarouselController.mediaFrame @@ -191,7 +190,7 @@ constructor( animationStartBounds, targetBounds, boundsProgress, - result = currentBounds + result = currentBounds, ) resolveClipping(currentClipping) applyState(currentBounds, currentAlpha, clipBounds = currentClipping) @@ -233,16 +232,16 @@ constructor( * The last location where this view was at before going to the desired location. This is useful * for guided transitions. */ - @MediaLocation private var previousLocation = -1 + @MediaLocation private var previousLocation = LOCATION_UNKNOWN /** The desired location where the view will be at the end of the transition. */ - @MediaLocation private var desiredLocation = -1 + @MediaLocation private var desiredLocation = LOCATION_UNKNOWN /** * The current attachment location where the view is currently attached. Usually this matches * the desired location except for animations whenever a view moves to the new desired location, * during which it is in [IN_OVERLAY]. */ - @MediaLocation private var currentAttachmentLocation = -1 + @MediaLocation private var currentAttachmentLocation = LOCATION_UNKNOWN private var inSplitShade = false @@ -627,7 +626,7 @@ constructor( secureSettings.getBoolForUser( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, true, - UserHandle.USER_CURRENT + UserHandle.USER_CURRENT, ) } } @@ -635,7 +634,7 @@ constructor( secureSettings.registerContentObserverForUserSync( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, settingsObserver, - UserHandle.USER_ALL + UserHandle.USER_ALL, ) // Listen to the communal UI state. Make sure that communal UI is showing and hub itself is @@ -651,7 +650,7 @@ constructor( shadeInteractor.shadeExpansion .mapLatest { it < EXPANSION_THRESHOLD } .distinctUntilChanged(), - ::Triple + ::Triple, ) .collectLatest { (communalShowing, isDreaming, isShadeExpanding) -> isCommunalShowing = communalShowing @@ -689,10 +688,10 @@ constructor( if (mediaObject.location == desiredLocation) { // In case we are overriding a view that is already visible, make sure we attach it // to this new host view in the below call - desiredLocation = -1 + desiredLocation = LOCATION_UNKNOWN } if (mediaObject.location == currentAttachmentLocation) { - currentAttachmentLocation = -1 + currentAttachmentLocation = LOCATION_UNKNOWN } updateDesiredLocation() return viewHost @@ -734,7 +733,7 @@ constructor( */ private fun updateDesiredLocation( forceNoAnimation: Boolean = false, - forceStateUpdate: Boolean = false + forceStateUpdate: Boolean = false, ) = traceSection("MediaHierarchyManager#updateDesiredLocation") { val desiredLocation = calculateLocation() @@ -758,7 +757,7 @@ constructor( previousLocation = LOCATION_QQS } } - val isNewView = this.desiredLocation == -1 + val isNewView = this.desiredLocation == LOCATION_UNKNOWN this.desiredLocation = desiredLocation // Let's perform a transition val animate = @@ -774,7 +773,7 @@ constructor( host, animate, animDuration, - delay + delay, ) } performTransitionToNewLocation(isNewView, animate) @@ -868,7 +867,7 @@ constructor( private fun shouldAnimateTransition( @MediaLocation currentLocation: Int, - @MediaLocation previousLocation: Int + @MediaLocation previousLocation: Int, ): Boolean { if (isCurrentlyInGuidedTransformation()) { return false @@ -990,7 +989,7 @@ constructor( startBounds: Rect, endBounds: Rect, progress: Float, - result: Rect? = null + result: Rect? = null, ): Rect { val left = MathUtils.lerp(startBounds.left.toFloat(), endBounds.left.toFloat(), progress).toInt() @@ -1014,7 +1013,7 @@ constructor( } private fun hasValidStartAndEndLocations(): Boolean { - return previousLocation != -1 && desiredLocation != -1 + return previousLocation != LOCATION_UNKNOWN && desiredLocation != LOCATION_UNKNOWN } /** Calculate the transformation type for the current animation */ @@ -1099,21 +1098,21 @@ constructor( bounds: Rect, alpha: Float, immediately: Boolean = false, - clipBounds: Rect = EMPTY_RECT + clipBounds: Rect = EMPTY_RECT, ) = traceSection("MediaHierarchyManager#applyState") { currentBounds.set(bounds) currentClipping = clipBounds carouselAlpha = if (isCurrentlyFading()) alpha else 1.0f val onlyUseEndState = !isCurrentlyInGuidedTransformation() || isCurrentlyFading() - val startLocation = if (onlyUseEndState) -1 else previousLocation + val startLocation = if (onlyUseEndState) LOCATION_UNKNOWN else previousLocation val progress = if (onlyUseEndState) 1.0f else getTransformationProgress() val endLocation = resolveLocationForFading() mediaCarouselController.setCurrentState( startLocation, endLocation, progress, - immediately + immediately, ) updateHostAttachment() if (currentAttachmentLocation == IN_OVERLAY) { @@ -1125,7 +1124,7 @@ constructor( currentBounds.left, currentBounds.top, currentBounds.right, - currentBounds.bottom + currentBounds.bottom, ) } } @@ -1186,7 +1185,7 @@ constructor( mediaCarouselController.onDesiredLocationChanged( newLocation, getHost(newLocation), - animate = false + animate = false, ) } } @@ -1201,7 +1200,7 @@ constructor( if (isCrossFadeAnimatorRunning) { // When animating between two hosts with a fade, let's keep ourselves in the old // location for the first half, and then switch over to the end location - if (animationCrossFadeProgress > 0.5 || previousLocation == -1) { + if (animationCrossFadeProgress > 0.5 || previousLocation == LOCATION_UNKNOWN) { return crossFadeAnimationEndLocation } else { return crossFadeAnimationStartLocation @@ -1364,6 +1363,9 @@ constructor( /** Attached at the root of the hierarchy in an overlay */ const val IN_OVERLAY = -1000 + /** Not attached to any view */ + const val LOCATION_UNKNOWN = -1 + /** * The default transformation type where the hosts transform into each other using a direct * transition @@ -1388,8 +1390,8 @@ private val EMPTY_RECT = Rect() value = [ MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION, - MediaHierarchyManager.TRANSFORMATION_TYPE_FADE - ] + MediaHierarchyManager.TRANSFORMATION_TYPE_FADE, + ], ) @Retention(AnnotationRetention.SOURCE) private annotation class TransformationType @@ -1403,7 +1405,8 @@ private annotation class TransformationType MediaHierarchyManager.LOCATION_LOCKSCREEN, MediaHierarchyManager.LOCATION_DREAM_OVERLAY, MediaHierarchyManager.LOCATION_COMMUNAL_HUB, - ] + MediaHierarchyManager.LOCATION_UNKNOWN, + ], ) @Retention(AnnotationRetention.SOURCE) annotation class MediaLocation diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt index e57de09f1063..3928a711f840 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt @@ -91,7 +91,7 @@ constructor( */ enum class TYPE { PLAYER, - RECOMMENDATION + RECOMMENDATION, } companion object { @@ -120,7 +120,7 @@ constructor( * finished */ @MediaLocation - var currentEndLocation: Int = -1 + var currentEndLocation: Int = MediaHierarchyManager.LOCATION_UNKNOWN set(value) { if (field != value) { field = value @@ -130,7 +130,7 @@ constructor( } /** The starting location of the view where it starts for all animations and transitions */ - @MediaLocation private var currentStartLocation: Int = -1 + @MediaLocation private var currentStartLocation: Int = MediaHierarchyManager.LOCATION_UNKNOWN /** The progress of the transition or 1.0 if there is no transition happening */ private var currentTransitionProgress: Float = 1.0f @@ -294,14 +294,14 @@ constructor( object : MediaHostStatesManager.Callback { override fun onHostStateChanged( @MediaLocation location: Int, - mediaHostState: MediaHostState + mediaHostState: MediaHostState, ) { if (location == currentEndLocation || location == currentStartLocation) { setCurrentState( currentStartLocation, currentEndLocation, currentTransitionProgress, - applyImmediately = false + applyImmediately = false, ) } } @@ -442,7 +442,7 @@ constructor( /** Apply squishFraction to a copy of viewState such that the cached version is untouched. */ internal fun squishViewState( viewState: TransitionViewState, - squishFraction: Float + squishFraction: Float, ): TransitionViewState { val squishedViewState = viewState.copy() val squishedHeight = (squishedViewState.measureHeight * squishFraction).toInt() @@ -458,13 +458,13 @@ constructor( MediaViewHolder.expandedBottomActionIds, squishedViewState.measureHeight.toFloat(), squishedViewState, - squishFraction + squishFraction, ) calculateWidgetGroupAlphaForSquishiness( MediaViewHolder.detailIds, squishedViewState.measureHeight.toFloat(), squishedViewState, - squishFraction + squishFraction, ) // recommendation card val titlesTop = @@ -472,13 +472,13 @@ constructor( RecommendationViewHolder.mediaTitlesAndSubtitlesIds, squishedViewState.measureHeight.toFloat(), squishedViewState, - squishFraction + squishFraction, ) calculateWidgetGroupAlphaForSquishiness( RecommendationViewHolder.mediaContainersIds, titlesTop, squishedViewState, - squishFraction + squishFraction, ) return squishedViewState } @@ -517,7 +517,7 @@ constructor( widgetGroupIds: Set<Int>, groupEndPosition: Float, squishedViewState: TransitionViewState, - squishFraction: Float + squishFraction: Float, ): Float { val nonsquishedHeight = squishedViewState.measureHeight var groupTop = squishedViewState.measureHeight.toFloat() @@ -547,7 +547,7 @@ constructor( calculateAlpha( squishFraction, startPosition / nonsquishedHeight, - endPosition / nonsquishedHeight + endPosition / nonsquishedHeight, ) } } @@ -562,10 +562,10 @@ constructor( @VisibleForTesting fun obtainViewState( state: MediaHostState?, - isGutsAnimation: Boolean = false + isGutsAnimation: Boolean = false, ): TransitionViewState? { if (SceneContainerFlag.isEnabled) { - return obtainSceneContainerViewState() + return obtainSceneContainerViewState(state) } if (state == null || state.measurementInput == null) { @@ -606,7 +606,7 @@ constructor( transitionLayout!!.calculateViewState( state.measurementInput!!, constraintSetForExpansion(state.expansion), - TransitionViewState() + TransitionViewState(), ) setGutsViewState(result) @@ -653,7 +653,7 @@ constructor( logger.logMediaLocation("attach $type", currentStartLocation, currentEndLocation) this.transitionLayout = transitionLayout layoutController.attach(transitionLayout) - if (currentEndLocation == -1) { + if (currentEndLocation == MediaHierarchyManager.LOCATION_UNKNOWN) { return } // Set the previously set state immediately to the view, now that it's finally attached @@ -661,7 +661,7 @@ constructor( startLocation = currentStartLocation, endLocation = currentEndLocation, transitionProgress = currentTransitionProgress, - applyImmediately = true + applyImmediately = true, ) } @@ -695,7 +695,7 @@ constructor( Interpolators.EMPHASIZED_DECELERATE, titleText, artistText, - explicitIndicator + explicitIndicator, ) val exit = loadAnimator( @@ -704,7 +704,7 @@ constructor( Interpolators.EMPHASIZED_ACCELERATE, titleText, artistText, - explicitIndicator + explicitIndicator, ) metadataAnimationHandler = MetadataAnimationHandler(exit, enter) @@ -713,7 +713,7 @@ constructor( mediaCard.context, mediaViewHolder, multiRippleController, - turbulenceNoiseController + turbulenceNoiseController, ) // For Turbulence noise. @@ -728,7 +728,7 @@ constructor( object : LoadingEffect.AnimationStateChangedCallback { override fun onStateChanged( oldState: LoadingEffect.AnimationState, - newState: LoadingEffect.AnimationState + newState: LoadingEffect.AnimationState, ) { if (newState === LoadingEffect.AnimationState.NOT_PLAYING) { loadingEffectView.visibility = View.INVISIBLE @@ -755,12 +755,12 @@ constructor( MediaControlViewBinder.setVisibleAndAlpha( expandedLayout, it.scrubbingTotalTimeView.id, - isTimeVisible + isTimeVisible, ) MediaControlViewBinder.setVisibleAndAlpha( expandedLayout, it.scrubbingElapsedTimeView.id, - isTimeVisible + isTimeVisible, ) } @@ -788,7 +788,7 @@ constructor( collapsedLayout, isButtonVisible, notVisibleValue, - showInCollapsed = true + showInCollapsed = true, ) } } @@ -822,7 +822,7 @@ constructor( createTurbulenceNoiseConfig( it.loadingEffectView, it.turbulenceNoiseView, - colorSchemeTransition + colorSchemeTransition, ) } if (Flags.shaderlibLoadingEffectRefactor()) { @@ -832,23 +832,23 @@ constructor( TurbulenceNoiseShader.Companion.Type.SIMPLEX_NOISE, turbulenceNoiseAnimationConfig, noiseDrawCallback, - stateChangedCallback + stateChangedCallback, ) } colorSchemeTransition.loadingEffect = loadingEffect loadingEffect.play() mainExecutor.executeDelayed( loadingEffect::finish, - MediaControlViewModel.TURBULENCE_NOISE_PLAY_MS_DURATION + MediaControlViewModel.TURBULENCE_NOISE_PLAY_MS_DURATION, ) } else { turbulenceNoiseController.play( TurbulenceNoiseShader.Companion.Type.SIMPLEX_NOISE, - turbulenceNoiseAnimationConfig + turbulenceNoiseAnimationConfig, ) mainExecutor.executeDelayed( turbulenceNoiseController::finish, - MediaControlViewModel.TURBULENCE_NOISE_PLAY_MS_DURATION + MediaControlViewModel.TURBULENCE_NOISE_PLAY_MS_DURATION, ) } } @@ -920,7 +920,7 @@ constructor( startViewState, startHostState.disappearParameters, transitionProgress, - tmpState + tmpState, ) } } else if (startHostState != null && !startHostState.visible) { @@ -931,7 +931,7 @@ constructor( endViewState, endHostState.disappearParameters, 1.0f - transitionProgress, - tmpState + tmpState, ) } else if (transitionProgress == 1.0f || startViewState == null) { // We're at the end. Let's use that state @@ -945,13 +945,13 @@ constructor( startViewState, endViewState, transitionProgress, - tmpState + tmpState, ) } logger.logMediaSize( "setCurrentState (progress $transitionProgress)", result.width, - result.height + result.height, ) layoutController.setState( result, @@ -966,7 +966,7 @@ constructor( private fun updateViewStateSize( viewState: TransitionViewState?, location: Int, - outState: TransitionViewState + outState: TransitionViewState, ): TransitionViewState? { var result = viewState?.copy(outState) ?: return null val state = mediaHostStatesManager.mediaHostStates[location] @@ -1020,15 +1020,19 @@ constructor( } /** Get a view state based on the width and height set by the scene */ - private fun obtainSceneContainerViewState(): TransitionViewState? { + private fun obtainSceneContainerViewState(state: MediaHostState?): TransitionViewState? { logger.logMediaSize("scene container", widthInSceneContainerPx, heightInSceneContainerPx) + if (state?.measurementInput == null) { + return null + } + // Similar to obtainViewState: Let's create a new measurement val result = transitionLayout?.calculateViewState( MeasurementInput(widthInSceneContainerPx, heightInSceneContainerPx), - expandedLayout, - TransitionViewState() + if (state.expansion > 0) expandedLayout else collapsedLayout, + TransitionViewState(), ) result?.let { // And then ensure the guts visibility is set correctly @@ -1049,7 +1053,7 @@ constructor( private fun obtainViewStateForLocation(@MediaLocation location: Int): TransitionViewState? { val mediaHostState = mediaHostStatesManager.mediaHostStates[location] ?: return null if (SceneContainerFlag.isEnabled) { - return obtainSceneContainerViewState() + return obtainSceneContainerViewState(mediaHostState) } val viewState = obtainViewState(mediaHostState) @@ -1080,9 +1084,10 @@ constructor( fun refreshState() = traceSection("MediaViewController#refreshState") { if (SceneContainerFlag.isEnabled) { + val hostState = mediaHostStatesManager.mediaHostStates[currentEndLocation] // We don't need to recreate measurements for scene container, since it's a known // size. Just get the view state and update the layout controller - obtainSceneContainerViewState()?.let { + obtainSceneContainerViewState(hostState)?.let { // Get scene container state, then setCurrentState layoutController.setState( state = it, @@ -1106,7 +1111,7 @@ constructor( currentStartLocation, currentEndLocation, currentTransitionProgress, - applyImmediately = true + applyImmediately = true, ) } @@ -1115,7 +1120,7 @@ constructor( context: Context, animId: Int, motionInterpolator: Interpolator?, - vararg targets: View? + vararg targets: View?, ): AnimatorSet { val animators = ArrayList<Animator>() for (target in targets) { @@ -1132,7 +1137,7 @@ constructor( private fun createTurbulenceNoiseConfig( loadingEffectView: LoadingEffectView, turbulenceNoiseView: TurbulenceNoiseView, - colorSchemeTransition: ColorSchemeTransition + colorSchemeTransition: ColorSchemeTransition, ): TurbulenceNoiseAnimationConfig { val targetView: View = if (Flags.shaderlibLoadingEffectRefactor()) { @@ -1163,7 +1168,7 @@ constructor( targetView.context.resources.displayMetrics.density, lumaMatteBlendFactor = 0.26f, lumaMatteOverallBrightness = 0.09f, - shouldInverseNoiseLuminosity = false + shouldInverseNoiseLuminosity = false, ) } @@ -1185,5 +1190,5 @@ private data class CacheKey( var widthMeasureSpec: Int = -1, var heightMeasureSpec: Int = -1, var expansion: Float = 0.0f, - var gutsVisible: Boolean = false + var gutsVisible: Boolean = false, ) diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt index e7f7171d5be3..b2137afa05e6 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt @@ -56,6 +56,9 @@ constructor( private val mediaLogger: MediaLogger, ) { + val hasAnyMediaOrRecommendations: StateFlow<Boolean> = interactor.hasAnyMediaOrRecommendation + val hasActiveMediaOrRecommendations: StateFlow<Boolean> = + interactor.hasActiveMediaOrRecommendation val mediaItems: StateFlow<List<MediaCommonViewModel>> = interactor.currentMedia .map { sortedItems -> @@ -114,7 +117,7 @@ constructor( qsExpanded: Boolean, visibleIndex: Int, location: Int, - isUpdate: Boolean = false + isUpdate: Boolean = false, ) { // Skip logging if on LS or QQS, and there is no active media card if (!qsExpanded && !interactor.hasActiveMediaOrRecommendation()) return @@ -127,7 +130,7 @@ constructor( val instanceId = commonModel.mediaLoadedModel.instanceId return mediaControlByInstanceId[instanceId]?.copy( immediatelyUpdateUi = commonModel.mediaLoadedModel.immediatelyUpdateUi, - updateTime = commonModel.updateTime + updateTime = commonModel.updateTime, ) ?: MediaCommonViewModel.MediaControl( instanceId = instanceId, @@ -144,7 +147,7 @@ constructor( }, onUpdated = { onMediaControlAddedOrUpdated(it, commonModel) }, isMediaFromRec = commonModel.isMediaFromRec, - updateTime = commonModel.updateTime + updateTime = commonModel.updateTime, ) .also { mediaControlByInstanceId[instanceId] = it } } @@ -165,7 +168,7 @@ constructor( return mediaRecs?.copy( key = commonModel.recsLoadingModel.key, loadingEnabled = - interactor.isRecommendationActive() || mediaFlags.isPersistentSsCardEnabled() + interactor.isRecommendationActive() || mediaFlags.isPersistentSsCardEnabled(), ) ?: MediaCommonViewModel.MediaRecommendations( key = commonModel.recsLoadingModel.key, @@ -195,7 +198,7 @@ constructor( private fun onMediaControlAddedOrUpdated( commonViewModel: MediaCommonViewModel, - commonModel: MediaCommonModel.MediaControl + commonModel: MediaCommonModel.MediaControl, ) { if (commonModel.canBeRemoved && !Utils.useMediaResumption(applicationContext)) { // This media control is due for removal as it is now paused + timed out, and resumption @@ -222,7 +225,7 @@ constructor( private fun onMediaRecommendationRemoved( commonModel: MediaCommonModel.MediaRecommendations, - immediatelyRemove: Boolean + immediatelyRemove: Boolean, ) { mediaLogger.logMediaRecommendationCardRemoved(commonModel.recsLoadingModel.key) if (immediatelyRemove || isReorderingAllowed()) { 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 f07f2de08537..4173d2aa272e 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,6 +33,8 @@ import com.android.systemui.media.controls.domain.pipeline.interactor.MediaContr 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.controller.MediaHierarchyManager +import com.android.systemui.media.controls.ui.controller.MediaLocation 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 @@ -70,7 +72,7 @@ class MediaControlViewModel( private var isPlaying = false private var isAnyButtonClicked = false - private var location = -1 + @MediaLocation private var location = MediaHierarchyManager.LOCATION_UNKNOWN private var playerViewModel: MediaPlayerViewModel? = null fun isNewPlayer(viewModel: MediaPlayerViewModel): Boolean { 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 a7bce7772270..6bc6b10a1dfd 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 @@ -31,6 +31,8 @@ import com.android.systemui.media.controls.domain.pipeline.interactor.MediaRecom 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.controller.MediaHierarchyManager +import com.android.systemui.media.controls.ui.controller.MediaLocation import com.android.systemui.media.controls.ui.controller.MediaViewController.Companion.GUTS_ANIMATION_DURATION import com.android.systemui.media.controls.util.MediaDataUtils import com.android.systemui.media.controls.util.MediaSmartspaceLogger.Companion.SMARTSPACE_CARD_CLICK_EVENT @@ -66,7 +68,7 @@ constructor( .distinctUntilChanged() .flowOn(backgroundDispatcher) - private var location = -1 + @MediaLocation private var location = MediaHierarchyManager.LOCATION_UNKNOWN /** * Called whenever the recommendation has been expired or removed by the user. This method 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 64402052c984..544dbddeb3f0 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 @@ interface MediaProjectionAppSelectorModule { @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/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java index b3c697e06a92..1216a8879751 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 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, } @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/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt index c174038aafe4..c8079600e980 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,12 @@ import android.view.ViewGroup 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.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.togetherWith import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -88,11 +93,12 @@ import com.android.systemui.qs.composefragment.ui.quickQuickSettingsToQuickSetti 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.EditMode import com.android.systemui.qs.panels.ui.compose.QuickQuickSettings import com.android.systemui.qs.shared.ui.ElementKeys +import com.android.systemui.qs.ui.composable.QuickSettingsLayout 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 import com.android.systemui.util.LifecycleFragment import com.android.systemui.util.asIndenting @@ -200,36 +206,70 @@ constructor( } .graphicsLayer { elevation = 4.dp.toPx() }, ) { - val sceneState = remember { - MutableSceneTransitionLayoutState( - viewModel.expansionState.value.toIdleSceneKey(), - transitions = - transitions { - from(QuickQuickSettings, QuickSettings) { - quickQuickSettingsToQuickSettings() - } - }, - ) + val isEditing by + viewModel.containerViewModel.editModeViewModel.isEditing + .collectAsStateWithLifecycle() + val animationSpecEditMode = tween<Float>(EDIT_MODE_TIME_MILLIS) + AnimatedContent( + targetState = isEditing, + transitionSpec = { + fadeIn(animationSpecEditMode) togetherWith + fadeOut(animationSpecEditMode) + }, + label = "EditModeAnimatedContent", + ) { editing -> + if (editing) { + val qqsPadding by + viewModel.qqsHeaderHeight.collectAsStateWithLifecycle() + EditMode( + viewModel = viewModel.containerViewModel.editModeViewModel, + modifier = + Modifier.fillMaxWidth() + .padding(top = { qqsPadding }) + .padding( + horizontal = { + QuickSettingsShade.Dimensions.Padding + .roundToPx() + } + ), + ) + } else { + CollapsableQuickSettingsSTL() + } } + } + } + } + } + } - LaunchedEffect(Unit) { - synchronizeQsState( - sceneState, - viewModel.expansionState.map { it.progress }, - ) + /** + * STL that contains both QQS (tiles) and QS (brightness, tiles, footer actions), but no Edit + * mode. It tracks [QSFragmentComposeViewModel.expansionState] to drive the transition between + * [SceneKeys.QuickQuickSettings] and [SceneKeys.QuickSettings]. + */ + @Composable + private fun CollapsableQuickSettingsSTL() { + val sceneState = remember { + MutableSceneTransitionLayoutState( + viewModel.expansionState.value.toIdleSceneKey(), + transitions = + transitions { + from(QuickQuickSettings, QuickSettings) { + quickQuickSettingsToQuickSettings() } + }, + ) + } - SceneTransitionLayout( - state = sceneState, - modifier = Modifier.fillMaxSize(), - ) { - scene(QuickSettings) { QuickSettingsElement() } + LaunchedEffect(Unit) { + synchronizeQsState(sceneState, viewModel.expansionState.map { it.progress }) + } - scene(QuickQuickSettings) { QuickQuickSettingsElement() } - } - } - } - } + SceneTransitionLayout(state = sceneState, modifier = Modifier.fillMaxSize()) { + scene(QuickSettings) { QuickSettingsElement() } + + scene(QuickQuickSettings) { QuickQuickSettingsElement() } } } @@ -445,7 +485,7 @@ constructor( qsContainerController, viewModel.containerViewModel.editModeViewModel.isEditing, ) { - setCustomizerShowing(it) + setCustomizerShowing(it, EDIT_MODE_TIME_MILLIS.toLong()) } } } @@ -519,7 +559,10 @@ constructor( Spacer( modifier = Modifier.height { qqsPadding + qsExtraPadding.roundToPx() } ) - ShadeBody(viewModel = viewModel.containerViewModel) + QuickSettingsLayout( + viewModel = viewModel.containerViewModel, + modifier = Modifier.sysuiResTag("quick_settings_panel"), + ) } } QuickSettingsTheme { @@ -717,3 +760,5 @@ private class ExpansionTransition(currentProgress: Float) : finishCompletable.complete(Unit) } } + +private const val EDIT_MODE_TIME_MILLIS = 500 diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt index 02a607db0a64..fc59a50e88ad 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt @@ -40,7 +40,7 @@ constructor( private val currentTilesInteractor: CurrentTilesInteractor, private val preferencesInteractor: QSPreferencesInteractor, @PanelsLog private val logBuffer: LogBuffer, - @Application private val applicationScope: CoroutineScope + @Application private val applicationScope: CoroutineScope, ) { val largeTilesSpecs = @@ -64,14 +64,15 @@ constructor( fun isIconTile(spec: TileSpec): Boolean = !largeTilesSpecs.value.contains(spec) - fun resize(spec: TileSpec) { + fun resize(spec: TileSpec, toIcon: Boolean) { if (!isCurrent(spec)) { return } - if (largeTilesSpecs.value.contains(spec)) { + val isIcon = !largeTilesSpecs.value.contains(spec) + if (toIcon && !isIcon) { preferencesInteractor.setLargeTilesSpecs(largeTilesSpecs.value - spec) - } else { + } else if (!toIcon && isIcon) { preferencesInteractor.setLargeTilesSpecs(largeTilesSpecs.value + spec) } } @@ -85,7 +86,7 @@ constructor( LOG_BUFFER_LARGE_TILES_SPECS_CHANGE_TAG, LogLevel.DEBUG, { str1 = specs.toString() }, - { "Large tiles change: $str1" } + { "Large tiles change: $str1" }, ) } 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 a4f977b08b70..770fd785723a 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 @@ -60,10 +60,37 @@ class EditTileListState(tiles: List<SizedTile<EditTileViewModel>>, private val c return _tiles.filterIsInstance<TileGridCell>().map { it.tile.tileSpec } } - fun indexOf(tileSpec: TileSpec): Int { + private fun indexOf(tileSpec: TileSpec): Int { return _tiles.indexOfFirst { it is TileGridCell && it.tile.tileSpec == tileSpec } } + /** + * Whether the tile with this [TileSpec] is currently an icon in the [EditTileListState] + * + * @return true if the tile is an icon, false if it's large, null if the tile isn't in the list + */ + fun isIcon(tileSpec: TileSpec): Boolean? { + val index = indexOf(tileSpec) + return if (index != -1) { + val cell = _tiles[index] + cell as TileGridCell + return cell.isIcon + } else { + null + } + } + + /** Toggle the size of the tile corresponding to the [TileSpec] */ + fun toggleSize(tileSpec: TileSpec) { + val fromIndex = indexOf(tileSpec) + if (fromIndex != -1) { + val cell = _tiles.removeAt(fromIndex) + cell as TileGridCell + _tiles.add(fromIndex, cell.copy(width = if (cell.isIcon) 2 else 1)) + regenerateGrid(fromIndex) + } + } + override fun isMoving(tileSpec: TileSpec): Boolean { return _draggedCell.value?.let { it.tile.tileSpec == tileSpec } ?: false } @@ -71,8 +98,8 @@ class EditTileListState(tiles: List<SizedTile<EditTileViewModel>>, private val c override fun onStarted(cell: SizedTile<EditTileViewModel>) { _draggedCell.value = cell - // Add visible spacers to the grid to indicate where the user can move a tile - regenerateGrid(includeSpacers = true) + // Add spacers to the grid to indicate where the user can move a tile + regenerateGrid() } override fun onMoved(target: Int, insertAfter: Boolean) { @@ -86,7 +113,7 @@ class EditTileListState(tiles: List<SizedTile<EditTileViewModel>>, private val c val insertionIndex = if (insertAfter) target + 1 else target if (fromIndex != -1) { val cell = _tiles.removeAt(fromIndex) - regenerateGrid(includeSpacers = true) + regenerateGrid() _tiles.add(insertionIndex.coerceIn(0, _tiles.size), cell) } else { // Add the tile with a temporary row which will get reassigned when @@ -94,7 +121,7 @@ class EditTileListState(tiles: List<SizedTile<EditTileViewModel>>, private val c _tiles.add(insertionIndex.coerceIn(0, _tiles.size), TileGridCell(draggedTile, 0)) } - regenerateGrid(includeSpacers = true) + regenerateGrid() } override fun movedOutOfBounds() { @@ -109,12 +136,27 @@ class EditTileListState(tiles: List<SizedTile<EditTileViewModel>>, private val c _draggedCell.value = null // Remove the spacers - regenerateGrid(includeSpacers = false) + regenerateGrid() + } + + /** Regenerate the list of [GridCell] with their new potential rows */ + private fun regenerateGrid() { + _tiles.filterIsInstance<TileGridCell>().toGridCells(columns).let { + _tiles.clear() + _tiles.addAll(it) + } } - private fun regenerateGrid(includeSpacers: Boolean) { - _tiles.filterIsInstance<TileGridCell>().toGridCells(columns, includeSpacers).let { + /** + * Regenerate the list of [GridCell] with their new potential rows from [fromIndex], leaving + * cells before that untouched. + */ + private fun regenerateGrid(fromIndex: Int) { + val fromRow = _tiles[fromIndex].row + val (pre, post) = _tiles.partition { it.row < fromRow } + post.filterIsInstance<TileGridCell>().toGridCells(columns, startingRow = fromRow).let { _tiles.clear() + _tiles.addAll(pre) _tiles.addAll(it) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PagerDots.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PagerDots.kt index 7de221612161..331aabb532a5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PagerDots.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PagerDots.kt @@ -31,9 +31,11 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.DrawScope +import androidx.compose.ui.graphics.drawscope.scale import androidx.compose.ui.semantics.pageLeft import androidx.compose.ui.semantics.pageRight import androidx.compose.ui.semantics.semantics @@ -60,68 +62,64 @@ fun PagerDots( val inPageTransition by remember(pagerState) { derivedStateOf { - pagerState.currentPageOffsetFraction.absoluteValue > 0.01 && + pagerState.currentPageOffsetFraction.absoluteValue > 0.05 && !pagerState.isOverscrolling() } } val coroutineScope = rememberCoroutineScope() - Row( - modifier = - modifier - .wrapContentWidth() - .pagerDotsSemantics( - pagerState, - coroutineScope, + val doubleDotWidth = dotSize * 2 + spaceSize + val activeMarkerWidth by + animateDpAsState( + targetValue = if (inPageTransition) doubleDotWidth else dotSize, + label = "PagerDotsTransitionAnimation", + ) + val cornerRadius = dotSize / 2 + + fun DrawScope.drawDoubleRect(withPrevious: Boolean, width: Dp) { + drawRoundRect( + topLeft = + Offset( + if (withPrevious) { + dotSize.toPx() - width.toPx() + } else { + -(dotSize.toPx() + spaceSize.toPx()) + }, + 0f, ), + color = activeColor, + size = Size(width.toPx(), dotSize.toPx()), + cornerRadius = CornerRadius(cornerRadius.toPx()), + ) + } + + Row( + modifier = modifier.wrapContentWidth().pagerDotsSemantics(pagerState, coroutineScope), horizontalArrangement = spacedBy(spaceSize), - verticalAlignment = Alignment.CenterVertically + verticalAlignment = Alignment.CenterVertically, ) { - if (!inPageTransition) { - repeat(pagerState.pageCount) { i -> - // We use canvas directly to only invalidate the draw phase when the page is - // changing. - Canvas(Modifier.size(dotSize)) { - if (pagerState.currentPage == i) { - drawCircle(activeColor) - } else { - drawCircle(nonActiveColor) - } - } - } - } else { - val doubleDotWidth = dotSize * 2 + spaceSize - val cornerRadius = dotSize / 2 - val width by - animateDpAsState(targetValue = if (inPageTransition) doubleDotWidth else dotSize) - - fun DrawScope.drawDoubleRect() { - drawRoundRect( - color = activeColor, - size = Size(width.toPx(), dotSize.toPx()), - cornerRadius = CornerRadius(cornerRadius.toPx(), cornerRadius.toPx()) - ) - } - - repeat(pagerState.pageCount) { page -> - Canvas(Modifier.size(dotSize)) { - val withPrevious = pagerState.currentPageOffsetFraction < 0 - val ltr = layoutDirection == LayoutDirection.Ltr + // This means that the active rounded rect has to be drawn between the current page + // and the previous one (as we are animating back), or the current one if not transitioning + val withPrevious = pagerState.currentPageOffsetFraction <= 0 || pagerState.isOverscrolling() + repeat(pagerState.pageCount) { page -> + Canvas(Modifier.size(dotSize)) { + val rtl = layoutDirection == LayoutDirection.Rtl + scale(if (rtl) -1f else 1f, 1f, Offset(0f, center.y)) { + drawCircle(nonActiveColor) + // We always want to draw the rounded rect on the rightmost dot iteration, so + // the inactive dot is always drawn behind. + // This means that: + // * if we are scrolling back, we draw it when we are in the current page (so it + // extends between this page and the previous one). + // * if we are scrolling forward, we draw it when we are in the next page (so it + // extends between the next page and the current one). + // * if we are not scrolling, withPrevious is true (pageOffset 0) and we + // draw in the current page. + // drawDoubleRect calculates the offset based on the above. if ( - withPrevious && page == (pagerState.currentPage - 1) || - !withPrevious && page == pagerState.currentPage - ) { - if (ltr) { - drawDoubleRect() - } - } else if ( withPrevious && page == pagerState.currentPage || - !withPrevious && page == (pagerState.currentPage + 1) + (!withPrevious && page == pagerState.currentPage + 1) ) { - if (!ltr) { - drawDoubleRect() - } - } else { - drawCircle(nonActiveColor) + drawDoubleRect(withPrevious, activeMarkerWidth) } } } 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 0e76e18fab8e..30bafaece923 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 @@ -132,15 +132,23 @@ object TileType @Composable fun DefaultEditTileGrid( - currentListState: EditTileListState, + listState: EditTileListState, otherTiles: List<SizedTile<EditTileViewModel>>, columns: Int, modifier: Modifier, onRemoveTile: (TileSpec) -> Unit, onSetTiles: (List<TileSpec>) -> Unit, - onResize: (TileSpec) -> Unit, + onResize: (TileSpec, toIcon: Boolean) -> Unit, ) { - val selectionState = rememberSelectionState() + val currentListState by rememberUpdatedState(listState) + val selectionState = + rememberSelectionState( + onResize = { currentListState.toggleSize(it) }, + onResizeEnd = { spec -> + // Commit the size currently in the list + currentListState.isIcon(spec)?.let { onResize(spec, it) } + }, + ) CompositionLocalProvider(LocalOverscrollConfiguration provides null) { Column( @@ -149,11 +157,11 @@ fun DefaultEditTileGrid( modifier = modifier.fillMaxSize().verticalScroll(rememberScrollState()), ) { AnimatedContent( - targetState = currentListState.dragInProgress, + targetState = listState.dragInProgress, modifier = Modifier.wrapContentSize(), label = "", ) { dragIsInProgress -> - EditGridHeader(Modifier.dragAndDropRemoveZone(currentListState, onRemoveTile)) { + EditGridHeader(Modifier.dragAndDropRemoveZone(listState, onRemoveTile)) { if (dragIsInProgress) { RemoveTileTarget() } else { @@ -162,11 +170,11 @@ fun DefaultEditTileGrid( } } - CurrentTilesGrid(currentListState, selectionState, columns, onResize, onSetTiles) + CurrentTilesGrid(listState, selectionState, columns, onResize, onSetTiles) // Hide available tiles when dragging AnimatedVisibility( - visible = !currentListState.dragInProgress, + visible = !listState.dragInProgress, enter = fadeIn(), exit = fadeOut(), ) { @@ -177,7 +185,7 @@ fun DefaultEditTileGrid( ) { EditGridHeader { Text(text = "Hold and drag to add tiles.") } - AvailableTileGrid(otherTiles, selectionState, columns, currentListState) + AvailableTileGrid(otherTiles, selectionState, columns, listState) } } @@ -186,7 +194,7 @@ fun DefaultEditTileGrid( modifier = Modifier.fillMaxWidth() .weight(1f) - .dragAndDropRemoveZone(currentListState, onRemoveTile) + .dragAndDropRemoveZone(listState, onRemoveTile) ) } } @@ -229,7 +237,7 @@ private fun CurrentTilesGrid( listState: EditTileListState, selectionState: MutableSelectionState, columns: Int, - onResize: (TileSpec) -> Unit, + onResize: (TileSpec, toIcon: Boolean) -> Unit, onSetTiles: (List<TileSpec>) -> Unit, ) { val currentListState by rememberUpdatedState(listState) @@ -242,19 +250,6 @@ private fun CurrentTilesGrid( ) val gridState = rememberLazyGridState() var gridContentOffset by remember { mutableStateOf(Offset(0f, 0f)) } - var droppedSpec by remember { mutableStateOf<TileSpec?>(null) } - - // 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) - - // Reset droppedSpec in case a tile is dropped twice in a row - droppedSpec = null - } - } TileLazyGrid( state = gridState, @@ -270,14 +265,17 @@ private fun CurrentTilesGrid( ) .dragAndDropTileList(gridState, { gridContentOffset }, listState) { spec -> onSetTiles(currentListState.tileSpecs()) - droppedSpec = spec + selectionState.select(spec, manual = false) } .onGloballyPositioned { coordinates -> gridContentOffset = coordinates.positionInRoot() } .testTag(CURRENT_TILES_GRID_TEST_TAG), ) { - EditTiles(listState.tiles, listState, selectionState, onResize) + EditTiles(listState.tiles, listState, selectionState) { spec -> + // Toggle the current size of the tile + currentListState.isIcon(spec)?.let { onResize(spec, !it) } + } } } @@ -348,11 +346,19 @@ private fun GridCell.key(index: Int, dragAndDropState: DragAndDropState): Any { } } +/** + * Adds a list of [GridCell] to the lazy grid + * + * @param cells the list of [GridCell] + * @param dragAndDropState the [DragAndDropState] for this grid + * @param selectionState the [MutableSelectionState] for this grid + * @param onToggleSize the callback when a tile's size is toggled + */ fun LazyGridScope.EditTiles( cells: List<GridCell>, dragAndDropState: DragAndDropState, selectionState: MutableSelectionState, - onResize: (TileSpec) -> Unit, + onToggleSize: (spec: TileSpec) -> Unit, ) { items( count = cells.size, @@ -378,7 +384,7 @@ fun LazyGridScope.EditTiles( index = index, dragAndDropState = dragAndDropState, selectionState = selectionState, - onResize = onResize, + onToggleSize = onToggleSize, ) } is SpacerGridCell -> SpacerGridCell() @@ -392,16 +398,28 @@ private fun LazyGridItemScope.TileGridCell( index: Int, dragAndDropState: DragAndDropState, selectionState: MutableSelectionState, - onResize: (TileSpec) -> Unit, + onToggleSize: (spec: TileSpec) -> Unit, ) { - val selected = selectionState.isSelected(cell.tile.tileSpec) val stateDescription = stringResource(id = R.string.accessibility_qs_edit_position, index + 1) + var selected by remember { mutableStateOf(false) } val selectionAlpha by animateFloatAsState( targetValue = if (selected) 1f else 0f, label = "QSEditTileSelectionAlpha", ) + LaunchedEffect(selectionState.selection?.tileSpec) { + selectionState.selection?.let { + // A delay is introduced on automatic selections such as dragged tiles or reflow caused + // by resizing. This avoids clipping issues on the border and resizing handle, as well + // as letting the selection animation play correctly. + if (!it.manual) { + delay(250) + } + } + selected = selectionState.selection?.tileSpec == cell.tile.tileSpec + } + val modifier = Modifier.animateItem() .semantics(mergeDescendants = true) { @@ -411,7 +429,7 @@ private fun LazyGridItemScope.TileGridCell( listOf( // TODO(b/367748260): Add final accessibility actions CustomAccessibilityAction("Toggle size") { - onResize(cell.tile.tileSpec) + onToggleSize(cell.tile.tileSpec) true } ) @@ -438,11 +456,9 @@ private fun LazyGridItemScope.TileGridCell( 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, ) @@ -458,11 +474,9 @@ private fun LazyGridItemScope.TileGridCell( @Composable private fun SelectedTile( - tileSpec: TileSpec, isIcon: Boolean, selectionAlpha: () -> Float, selectionState: MutableSelectionState, - onResize: (TileSpec) -> Unit, modifier: Modifier = Modifier, content: @Composable () -> Unit, ) { @@ -492,9 +506,7 @@ private fun SelectedTile( selectionState = selectionState, transition = selectionAlpha, tileWidths = { tileWidths }, - ) { - onResize(tileSpec) - } + ) } Layout(contents = listOf(content, handle)) { 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 8a9606545fc3..e6edba513189 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 @@ -101,7 +101,7 @@ constructor( val (currentTiles, otherTiles) = sizedTiles.partition { it.tile.isCurrent } val currentListState = rememberEditListState(currentTiles, columns) DefaultEditTileGrid( - currentListState = currentListState, + listState = currentListState, otherTiles = otherTiles, columns = columns, modifier = modifier, 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 index 2ea32e640984..441d96289d86 100644 --- 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 @@ -27,28 +27,39 @@ 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() } +fun rememberSelectionState( + onResize: (TileSpec) -> Unit, + onResizeEnd: (TileSpec) -> Unit, +): MutableSelectionState { + return remember { MutableSelectionState(onResize, onResizeEnd) } } +/** + * Holds the selected [TileSpec] and whether the selection was manual, i.e. caused by a tap from the + * user. + */ +data class Selection(val tileSpec: TileSpec, val manual: Boolean) + /** Holds the state of the current selection. */ -class MutableSelectionState { - private var _selectedTile = mutableStateOf<TileSpec?>(null) +class MutableSelectionState( + val onResize: (TileSpec) -> Unit, + private val onResizeEnd: (TileSpec) -> Unit, +) { + private var _selection = mutableStateOf<Selection?>(null) private var _resizingState = mutableStateOf<ResizingState?>(null) + /** The [Selection] if a tile is selected, null if not. */ + val selection by _selection + /** 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 select(tileSpec: TileSpec, manual: Boolean) { + _selection.value = Selection(tileSpec, manual) } fun unSelect() { - _selectedTile.value = null + _selection.value = null onResizingDragEnd() } @@ -56,14 +67,21 @@ class MutableSelectionState { _resizingState.value?.onDrag(offset) } - fun onResizingDragStart(tileWidths: TileWidths, onResize: () -> Unit) { - if (_selectedTile.value == null) return - - _resizingState.value = ResizingState(tileWidths, onResize) + fun onResizingDragStart(tileWidths: TileWidths) { + _selection.value?.let { + _resizingState.value = ResizingState(tileWidths) { onResize(it.tileSpec) } + } } fun onResizingDragEnd() { _resizingState.value = null + _selection.value?.let { + onResizeEnd(it.tileSpec) + + // Mark the selection as automatic in case the tile ends up moving to a different + // row with its new size. + _selection.value = it.copy(manual = false) + } } } @@ -76,10 +94,10 @@ fun Modifier.selectableTile(tileSpec: TileSpec, selectionState: MutableSelection return pointerInput(Unit) { detectTapGestures( onTap = { - if (selectionState.isSelected(tileSpec)) { + if (selectionState.selection?.tileSpec == tileSpec) { selectionState.unSelect() } else { - selectionState.select(tileSpec) + selectionState.select(tileSpec, manual = true) } } ) 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 index e3acf3863254..7c62e5995ce8 100644 --- 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 @@ -45,7 +45,6 @@ fun ResizingHandle( 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 @@ -56,9 +55,7 @@ fun ResizingHandle( Modifier.size(minTouchTargetSize).pointerInput(Unit) { detectHorizontalDragGestures( onHorizontalDrag = { _, offset -> selectionState.onResizingDrag(offset) }, - onDragStart = { - tileWidths()?.let { selectionState.onResizingDragStart(it, onResize) } - }, + onDragStart = { tileWidths()?.let { selectionState.onResizingDragStart(it) } }, onDragEnd = selectionState::onResizingDragEnd, onDragCancel = selectionState::onResizingDragEnd, ) diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt index b16a7075607f..b1841c4c5ffa 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt @@ -27,6 +27,7 @@ import com.android.systemui.qs.shared.model.CategoryAndName sealed interface GridCell { val row: Int val span: GridItemSpan + val s: String } /** @@ -39,6 +40,7 @@ data class TileGridCell( override val row: Int, override val width: Int, override val span: GridItemSpan = GridItemSpan(width), + override val s: String = "${tile.tileSpec.spec}-$row-$width", ) : GridCell, SizedTile<EditTileViewModel>, CategoryAndName by tile { val key: String = "${tile.tileSpec.spec}-$row" @@ -53,22 +55,30 @@ data class TileGridCell( data class SpacerGridCell( override val row: Int, override val span: GridItemSpan = GridItemSpan(1), + override val s: String = "spacer", ) : GridCell +/** + * Generates a list of [GridCell] from a list of [SizedTile] + * + * Builds rows based on the tiles' widths, and fill each hole with a [SpacerGridCell] + * + * @param startingRow The row index the grid is built from, used in cases where only end rows need + * to be regenerated + */ fun List<SizedTile<EditTileViewModel>>.toGridCells( columns: Int, - includeSpacers: Boolean = false, + startingRow: Int = 0, ): List<GridCell> { return splitInRowsSequence(this, columns) .flatMapIndexed { rowIndex, sizedTiles -> - val row: List<GridCell> = sizedTiles.map { TileGridCell(it, rowIndex) } + val correctedRowIndex = rowIndex + startingRow + val row: List<GridCell> = sizedTiles.map { TileGridCell(it, correctedRowIndex) } - if (includeSpacers) { - // Fill the incomplete rows with spacers - val numSpacers = columns - sizedTiles.sumOf { it.width } - row.toMutableList().apply { repeat(numSpacers) { add(SpacerGridCell(rowIndex)) } } - } else { - row + // Fill the incomplete rows with spacers + val numSpacers = columns - sizedTiles.sumOf { it.width } + row.toMutableList().apply { + repeat(numSpacers) { add(SpacerGridCell(correctedRowIndex)) } } } .toList() diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconTilesViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconTilesViewModel.kt index b604e18b1e76..4e698edf4e34 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconTilesViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconTilesViewModel.kt @@ -27,7 +27,7 @@ interface IconTilesViewModel { fun isIconTile(spec: TileSpec): Boolean - fun resize(spec: TileSpec) + fun resize(spec: TileSpec, toIcon: Boolean) } @SysUISingleton @@ -37,5 +37,5 @@ class IconTilesViewModelImpl @Inject constructor(private val interactor: IconTil override fun isIconTile(spec: TileSpec): Boolean = interactor.isIconTile(spec) - override fun resize(spec: TileSpec) = interactor.resize(spec) + override fun resize(spec: TileSpec, toIcon: Boolean) = interactor.resize(spec, toIcon) } 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 d0437a7210f1..b8f4ab40bb1d 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 @@ class QSTileCoroutineScopeFactory 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 246fe3883e19..ae56c2aad4e9 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 @@ constructor( } 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 cca947ff7e77..ac75932b8fee 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 @@ constructor( 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 b25c61cba2b7..468e180a6e41 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 @@ class DataSaverDialogDelegate( 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 b7e2cf23e3a8..286cac10fa05 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 @@ constructor( // 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/settings/brightness/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java index 8e539499cb14..649f8db89bc0 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java @@ -50,8 +50,12 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.systemui.Flags; +import com.android.systemui.brightness.shared.model.BrightnessLog; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.log.LogBuffer; +import com.android.systemui.log.core.LogLevel; +import com.android.systemui.log.core.LogMessage; import com.android.systemui.settings.DisplayTracker; import com.android.systemui.settings.UserTracker; import com.android.systemui.util.settings.SecureSettings; @@ -60,6 +64,8 @@ import dagger.assisted.Assisted; import dagger.assisted.AssistedFactory; import dagger.assisted.AssistedInject; +import kotlin.Unit; + import java.util.concurrent.Executor; public class BrightnessController implements ToggleSlider.Listener, MirroredBrightnessController { @@ -88,6 +94,7 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig private final Executor mMainExecutor; private final Handler mBackgroundHandler; private final BrightnessObserver mBrightnessObserver; + private final LogBuffer mLogBuffer; private final DisplayTracker.Callback mBrightnessListener = new DisplayTracker.Callback() { @Override @@ -308,6 +315,7 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig DisplayTracker displayTracker, DisplayManager displayManager, SecureSettings secureSettings, + @BrightnessLog LogBuffer logBuffer, @Nullable IVrManager iVrManager, @Main Executor mainExecutor, @Main Looper mainLooper, @@ -323,6 +331,7 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig mDisplayId = mContext.getDisplayId(); mDisplayManager = displayManager; mVrManager = iVrManager; + mLogBuffer = logBuffer; mMainHandler = new Handler(mainLooper, mHandlerCallback); mBrightnessObserver = new BrightnessObserver(mMainHandler); @@ -342,6 +351,7 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig @Override public void onChanged(boolean tracking, int value, boolean stopTracking) { + boolean starting = !mTrackingTouch && tracking; mTrackingTouch = tracking; if (mExternalChange) return; @@ -369,9 +379,13 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig } setBrightness(valFloat); + if (starting) { + logBrightnessChange(mDisplayId, valFloat, true); + } if (!tracking) { AsyncTask.execute(new Runnable() { public void run() { + logBrightnessChange(mDisplayId, valFloat, false); mDisplayManager.setBrightness(mDisplayId, valFloat); } }); @@ -474,4 +488,20 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig /** Create a {@link BrightnessController} */ BrightnessController create(ToggleSlider toggleSlider); } + + private void logBrightnessChange(int display, float value, boolean starting) { + mLogBuffer.log( + TAG, + LogLevel.DEBUG, + (LogMessage message) -> { + message.setInt1(display); + message.setDouble1(value); + message.setBool1(starting); + return Unit.INSTANCE; + }, + (LogMessage message) -> "%s brightness set in display %d to %.3f".formatted( + message.getBool1() ? "Starting" : "Finishing", message.getInt1(), + message.getDouble1()) + ); + } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt index 2e67277d8327..52cb8d6df7e1 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt @@ -289,6 +289,13 @@ constructor( ) } + private fun resetTouchMonitor() { + touchMonitor?.apply { + destroy() + touchMonitor = null + } + } + /** Override for testing. */ @VisibleForTesting internal fun initView(containerView: View): View { @@ -297,12 +304,13 @@ constructor( throw RuntimeException("Communal view has already been initialized") } - if (touchMonitor == null) { - touchMonitor = - ambientTouchComponentFactory.create(this, HashSet(), TAG).getTouchMonitor().apply { - init() - } - } + resetTouchMonitor() + + touchMonitor = + ambientTouchComponentFactory.create(this, HashSet(), TAG).getTouchMonitor().apply { + init() + } + lifecycleRegistry.addObserver(touchLifecycleLogger) lifecycleRegistry.currentState = Lifecycle.State.CREATED @@ -475,6 +483,8 @@ constructor( lifecycleRegistry.removeObserver(touchLifecycleLogger) + resetTouchMonitor() + logger.d("Hub container disposed") } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index f76c5fd4ca83..0c05dbde6117 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 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump @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 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump 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 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } 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/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index bf888073e002..5473af3b3fb5 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -59,7 +59,6 @@ import com.android.systemui.keyguard.shared.model.TransitionState; import com.android.systemui.keyguard.shared.model.TransitionStep; import com.android.systemui.res.R; import com.android.systemui.scene.shared.flag.SceneContainerFlag; -import com.android.systemui.scene.shared.model.Scenes; import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor; import com.android.systemui.shared.animation.DisableSubpixelTextTransitionListener; import com.android.systemui.statusbar.DragDownHelper; @@ -265,20 +264,21 @@ public class NotificationShadeWindowViewController implements Dumpable { } private void bindBouncer(BouncerViewBinder bouncerViewBinder) { + mBouncerParentView = mView.findViewById(R.id.keyguard_bouncer_container); + bouncerViewBinder.bind(mBouncerParentView); if (ComposeBouncerFlags.INSTANCE.isOnlyComposeBouncerEnabled()) { - collectFlow(mView, mKeyguardTransitionInteractor.isFinishedIn(Scenes.Gone, - KeyguardState.GONE), this::removeBouncerParentView); collectFlow(mView, mKeyguardTransitionInteractor.transition( - new Edge.StateToState(KeyguardState.GONE, null)), - this::handleGoneToAnyOtherStateTransition); + 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)); } - mBouncerParentView = mView.findViewById(R.id.keyguard_bouncer_container); - bouncerViewBinder.bind(mBouncerParentView); } - private void handleGoneToAnyOtherStateTransition(TransitionStep transitionStep) { + private void onTransitionToBouncer(TransitionStep transitionStep) { if (transitionStep.getTransitionState() == TransitionState.STARTED) { if (mView.indexOfChild(mBouncerParentView) != -1) { mView.removeView(mBouncerParentView); @@ -287,8 +287,8 @@ public class NotificationShadeWindowViewController implements Dumpable { } } - private void removeBouncerParentView(boolean isFinishedInGoneState) { - if (isFinishedInGoneState) { + private void onTransitionAwayFromBouncer(TransitionStep transitionStep) { + if (transitionStep.getTransitionState() == TransitionState.FINISHED) { mView.removeView(mBouncerParentView); } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java index 4ed4af647fdf..830649be2a98 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java @@ -42,7 +42,6 @@ import android.util.Log; import android.util.MathUtils; import android.view.MotionEvent; import android.view.VelocityTracker; -import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.WindowInsets; @@ -464,9 +463,6 @@ public class QuickSettingsControllerImpl implements QuickSettingsController, Dum mJavaAdapter.alwaysCollectFlow( mCommunalTransitionViewModelLazy.get().isUmoOnCommunal(), this::setShouldUpdateSquishinessOnMedia); - mJavaAdapter.alwaysCollectFlow( - mShadeInteractor.isAnyExpanded(), - this::onAnyExpandedChanged); } private void initNotificationStackScrollLayoutController() { @@ -486,10 +482,6 @@ public class QuickSettingsControllerImpl implements QuickSettingsController, Dum } } - private void onAnyExpandedChanged(boolean isAnyExpanded) { - mQsFrame.setVisibility(isAnyExpanded ? View.VISIBLE : View.INVISIBLE); - } - private void onNotificationScrolled(int newScrollPosition) { updateExpansionEnabledAmbient(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 5eef8ea1999d..769abafed69f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -207,8 +207,8 @@ public class KeyguardIndicationController { protected boolean mPowerPluggedInWireless; protected boolean mPowerPluggedInDock; protected int mChargingSpeed; + protected boolean mPowerCharged; - private boolean mPowerCharged; /** Whether the battery defender is triggered. */ private boolean mBatteryDefender; /** Whether the battery defender is triggered with the device plugged. */ @@ -1100,14 +1100,15 @@ public class KeyguardIndicationController { String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f); return mContext.getResources().getString( R.string.keyguard_plugged_in_incompatible_charger, percentage); - } else if (mPowerCharged) { - return mContext.getResources().getString(R.string.keyguard_charged); } return computePowerChargingStringIndication(); } protected String computePowerChargingStringIndication() { + if (mPowerCharged) { + return mContext.getResources().getString(R.string.keyguard_charged); + } final boolean hasChargingTime = mChargingTimeRemaining > 0; int chargingId; if (mPowerPluggedInWired) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index 7f5551274d55..8a6ec2aa27c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -50,8 +50,8 @@ import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteract import com.android.systemui.deviceentry.shared.model.DeviceUnlockStatus; import com.android.systemui.keyguard.MigrateClocksToBlueprint; import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor; +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; -import com.android.systemui.keyguard.shared.model.KeyguardState; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.res.R; import com.android.systemui.scene.data.model.SceneStack; @@ -115,6 +115,7 @@ public class StatusBarStateControllerImpl implements private final UiEventLogger mUiEventLogger; private final Lazy<InteractionJankMonitor> mInteractionJankMonitorLazy; private final JavaAdapter mJavaAdapter; + private final Lazy<KeyguardInteractor> mKeyguardInteractorLazy; private final Lazy<KeyguardTransitionInteractor> mKeyguardTransitionInteractorLazy; private final Lazy<ShadeInteractor> mShadeInteractorLazy; private final Lazy<DeviceUnlockedInteractor> mDeviceUnlockedInteractorLazy; @@ -185,6 +186,7 @@ public class StatusBarStateControllerImpl implements UiEventLogger uiEventLogger, Lazy<InteractionJankMonitor> interactionJankMonitorLazy, JavaAdapter javaAdapter, + Lazy<KeyguardInteractor> keyguardInteractor, Lazy<KeyguardTransitionInteractor> keyguardTransitionInteractor, Lazy<ShadeInteractor> shadeInteractorLazy, Lazy<DeviceUnlockedInteractor> deviceUnlockedInteractorLazy, @@ -195,6 +197,7 @@ public class StatusBarStateControllerImpl implements mUiEventLogger = uiEventLogger; mInteractionJankMonitorLazy = interactionJankMonitorLazy; mJavaAdapter = javaAdapter; + mKeyguardInteractorLazy = keyguardInteractor; mKeyguardTransitionInteractorLazy = keyguardTransitionInteractor; mShadeInteractorLazy = shadeInteractorLazy; mDeviceUnlockedInteractorLazy = deviceUnlockedInteractorLazy; @@ -233,8 +236,8 @@ public class StatusBarStateControllerImpl implements this::onStatusBarStateChanged); mJavaAdapter.alwaysCollectFlow( - mKeyguardTransitionInteractorLazy.get().transitionValue(KeyguardState.AOD), - this::onAodKeyguardStateTransitionValueChanged); + mKeyguardInteractorLazy.get().getDozeAmount(), + this::setDozeAmountInternal); } } @@ -404,6 +407,7 @@ public class StatusBarStateControllerImpl implements @Override public void setAndInstrumentDozeAmount(View view, float dozeAmount, boolean animated) { + SceneContainerFlag.assertInLegacyMode(); if (mDarkAnimator != null && mDarkAnimator.isRunning()) { if (animated && mDozeAmountTarget == dozeAmount) { return; @@ -439,6 +443,7 @@ public class StatusBarStateControllerImpl implements } private void startDozeAnimation() { + SceneContainerFlag.assertInLegacyMode(); if (mDozeAmount == 0f || mDozeAmount == 1f) { mDozeInterpolator = mIsDozing ? Interpolators.FAST_OUT_SLOW_IN @@ -457,6 +462,7 @@ public class StatusBarStateControllerImpl implements @VisibleForTesting protected ObjectAnimator createDarkAnimator() { + SceneContainerFlag.assertInLegacyMode(); ObjectAnimator darkAnimator = ObjectAnimator.ofFloat( this, SET_DARK_AMOUNT_PROPERTY, mDozeAmountTarget); darkAnimator.setInterpolator(Interpolators.LINEAR); @@ -710,14 +716,6 @@ public class StatusBarStateControllerImpl implements updateStateAndNotifyListeners(newState); } - private void onAodKeyguardStateTransitionValueChanged(float value) { - if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) { - return; - } - - setDozeAmountInternal(value); - } - private static final Map<SceneKey, Integer> sStatusBarStateByLockedSceneKey = Map.of( Scenes.Lockscreen, StatusBarState.KEYGUARD, Scenes.Bouncer, StatusBarState.KEYGUARD, 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 975b92e632b8..3ad76b719470 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.core import android.app.Fragment +import androidx.annotation.VisibleForTesting +import com.android.systemui.CoreStartable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.fragments.FragmentHostManager import com.android.systemui.res.R @@ -72,11 +74,38 @@ constructor( private val windowController: StatusBarWindowController, private val collapsedStatusBarFragmentProvider: Provider<CollapsedStatusBarFragment>, private val creationListeners: Set<@JvmSuppressWildcards OnStatusBarViewInitializedListener>, -) : StatusBarInitializer { +) : CoreStartable, StatusBarInitializer { + private var component: StatusBarFragmentComponent? = null + + @get:VisibleForTesting + var initialized = false + private set override var statusBarViewUpdatedListener: OnStatusBarViewUpdatedListener? = null + set(value) { + field = value + // If a listener is added after initialization, immediately call the callback + component?.let { component -> + field?.onStatusBarViewUpdated( + component.phoneStatusBarViewController, + component.phoneStatusBarTransitions, + ) + } + } + + override fun start() { + if (StatusBarSimpleFragment.isEnabled) { + doStart() + } + } override fun initializeStatusBar() { + StatusBarSimpleFragment.assertInLegacyMode() + doStart() + } + + private fun doStart() { + initialized = true windowController.fragmentHostManager .addTagListener( CollapsedStatusBarFragment.TAG, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesModule.java index c8f0b52b1214..525f3defa15c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesModule.java @@ -16,17 +16,28 @@ package com.android.systemui.statusbar.dagger; +import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.emergency.EmergencyGestureModule; import com.android.systemui.statusbar.notification.dagger.NotificationsModule; import com.android.systemui.statusbar.notification.row.NotificationRowModule; +import com.android.systemui.statusbar.phone.CentralSurfaces; +import com.android.systemui.statusbar.phone.CentralSurfacesImpl; import com.android.systemui.statusbar.phone.StatusBarNotificationPresenterModule; -import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule; +import dagger.Binds; import dagger.Module; -/** */ +/** + * Dagger Module providing {@link CentralSurfacesImpl}. + */ @Module(includes = {CentralSurfacesDependenciesModule.class, - StatusBarNotificationPresenterModule.class, StatusBarPhoneModule.class, + StatusBarNotificationPresenterModule.class, NotificationsModule.class, NotificationRowModule.class, EmergencyGestureModule.class}) public interface CentralSurfacesModule { + /** + * Provides our instance of CentralSurfaces which is considered optional. + */ + @Binds + @SysUISingleton + CentralSurfaces bindsCentralSurfaces(CentralSurfacesImpl impl); } 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 55943a527a8c..3903ff3c2b9b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt @@ -22,8 +22,6 @@ 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 @@ -63,8 +61,6 @@ abstract class StatusBarModule { @ClassKey(StatusBarSignalPolicy::class) abstract fun bindStatusBarSignalPolicy(impl: StatusBarSignalPolicy): CoreStartable - @Binds abstract fun statusBarInitializer(impl: StatusBarInitializerImpl): StatusBarInitializer - companion object { @Provides 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 2bb476523cb8..ce25cf5895c1 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 @@ package com.android.systemui.statusbar.disableflags.data.model 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 @@ import com.android.systemui.statusbar.disableflags.DisableFlagsLogger * 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 @@ data class DisableFlagsModel( 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 @@ data class DisableFlagsModel( }, { 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 13b74b493905..9004e5d12663 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 @@ constructor( // [QuickSettingsInteractor]-type class. However, that's out of // scope for the CentralSurfaces removal project. remoteInputQuickSettingsDisabler.adjustDisableFlags(state2), + animate, ) ) } @@ -82,5 +83,5 @@ constructor( .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 9b96931348d6..6907eefa8b56 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java @@ -106,7 +106,8 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements @VisibleForTesting public final ArraySet<NotificationEntry> mEntriesToRemoveWhenReorderingAllowed = new ArraySet<>(); - private boolean mIsExpanded; + private boolean mIsShadeOrQsExpanded; + private boolean mIsQsExpanded; private int mStatusBarState; private AnimationStateHandler mAnimationStateHandler; @@ -178,6 +179,10 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements }); javaAdapter.alwaysCollectFlow(shadeInteractor.isAnyExpanded(), this::onShadeOrQsExpanded); + if (SceneContainerFlag.isEnabled()) { + javaAdapter.alwaysCollectFlow(shadeInteractor.isQsExpanded(), + this::onQsExpanded); + } if (NotificationThrottleHun.isEnabled()) { mVisualStabilityProvider.addPersistentReorderingBannedListener( mOnReorderingBannedListener); @@ -287,14 +292,19 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements } private void onShadeOrQsExpanded(Boolean isExpanded) { - if (isExpanded != mIsExpanded) { - mIsExpanded = isExpanded; + if (isExpanded != mIsShadeOrQsExpanded) { + mIsShadeOrQsExpanded = isExpanded; if (!SceneContainerFlag.isEnabled() && isExpanded) { mHeadsUpAnimatingAway.setValue(false); } } } + private void onQsExpanded(Boolean isQsExpanded) { + if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return; + if (isQsExpanded != mIsQsExpanded) mIsQsExpanded = isQsExpanded; + } + /** * Set that we are exiting the headsUp pinned mode, but some notifications might still be * animating out. This is used to keep the touchable regions in a reasonable state. @@ -490,7 +500,10 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements @Override protected boolean shouldHeadsUpBecomePinned(NotificationEntry entry) { - boolean pin = mStatusBarState == StatusBarState.SHADE && !mIsExpanded; + boolean pin = mStatusBarState == StatusBarState.SHADE && !mIsShadeOrQsExpanded; + if (SceneContainerFlag.isEnabled()) { + pin |= mIsQsExpanded; + } if (mBypassController.getBypassEnabled()) { pin |= mStatusBarState == StatusBarState.KEYGUARD; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/view/EmptyShadeView.java index 2338be28d32c..850e9447beea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/view/EmptyShadeView.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,10 +11,10 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ -package com.android.systemui.statusbar; +package com.android.systemui.statusbar.notification.emptyshade.ui.view; import android.annotation.ColorInt; import android.annotation.DrawableRes; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index 560028cb5640..7b6a2cb62b14 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -444,11 +444,9 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView if (onFinishedRunnable != null) { onFinishedRunnable.run(); } - if (mRunWithoutInterruptions) { - enableAppearDrawing(false); - } // We need to reset the View state, even if the animation was cancelled + enableAppearDrawing(false); onAppearAnimationFinished(isAppearing); if (mRunWithoutInterruptions) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index 48796d8f8f2d..b1083888ca7f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -634,8 +634,10 @@ public class NotificationChildrenContainer extends ViewGroup } private View inflateDivider() { - return LayoutInflater.from(mContext).inflate( + View divider = LayoutInflater.from(mContext).inflate( R.layout.notification_children_divider, this, false); + divider.setAlpha(0f); + return divider; } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index e7c67f93eb78..cd3516dadbad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -22,7 +22,6 @@ import static android.view.MotionEvent.ACTION_UP; import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING; import static com.android.internal.jank.InteractionJankMonitor.CUJ_SHADE_CLEAR_ALL; -import static com.android.systemui.Flags.newAodTransition; import static com.android.systemui.Flags.notificationOverExpansionClippingFix; import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT; import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE; @@ -94,7 +93,6 @@ import com.android.systemui.res.R; import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.shade.QSHeaderBoundsProvider; import com.android.systemui.shade.TouchLogger; -import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.ColorUpdateLogger; @@ -106,6 +104,7 @@ import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; +import com.android.systemui.statusbar.notification.emptyshade.ui.view.EmptyShadeView; import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor; import com.android.systemui.statusbar.notification.footer.ui.view.FooterView; import com.android.systemui.statusbar.notification.logging.NotificationLogger; @@ -1260,6 +1259,7 @@ public class NotificationStackScrollLayout @Override public void setHeadsUpBottom(float headsUpBottom) { mAmbientState.setHeadsUpBottom(headsUpBottom); + mStateAnimator.setHeadsUpAppearHeightBottom(Math.round(headsUpBottom)); } @Override @@ -1548,15 +1548,6 @@ public class NotificationStackScrollLayout @VisibleForTesting public void updateInterpolatedStackHeight(float endHeight, float fraction) { - if (!newAodTransition()) { - // During the (AOD<=>LS) transition where dozeAmount is changing, - // apply dozeAmount to stack height instead of expansionFraction - // to unfurl notifications on AOD=>LS wakeup (and furl up on LS=>AOD sleep) - final float dozeAmount = mAmbientState.getDozeAmount(); - if (0f < dozeAmount && dozeAmount < 1f) { - fraction = 1f - dozeAmount; - } - } mAmbientState.setInterpolatedStackHeight( MathUtils.lerp(endHeight * StackScrollAlgorithm.START_FRACTION, endHeight, fraction)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index cccac4b479dd..9c0fd0e844b4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -31,9 +31,9 @@ import com.android.systemui.animation.ShadeInterpolation; import com.android.systemui.res.R; import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.shade.transition.LargeScreenShadeInterpolator; -import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.notification.SourceType; +import com.android.systemui.statusbar.notification.emptyshade.ui.view.EmptyShadeView; import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor; import com.android.systemui.statusbar.notification.footer.ui.view.FooterView; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; @@ -677,22 +677,30 @@ public class StackScrollAlgorithm { ); if (view instanceof FooterView) { if (FooterViewRefactor.isEnabled()) { - // TODO(b/333445519): shouldBeHidden should reflect whether the shade is closed - // already, so we shouldn't need to use ambientState here. However, currently it - // doesn't get updated quickly enough and can cause the footer to flash when - // closing the shade. As such, we temporarily also check the ambientState directly. - if (((FooterView) view).shouldBeHidden() || !ambientState.isShadeExpanded()) { - // Note: This is no longer necessary in flexiglass. - if (!SceneContainerFlag.isEnabled()) { - viewState.hidden = true; - } - } else { - final float footerEnd = algorithmState.mCurrentExpandedYPosition - + view.getIntrinsicHeight(); - final boolean noSpaceForFooter = footerEnd > ambientState.getStackEndHeight(); + if (SceneContainerFlag.isEnabled()) { + final float footerEnd = + stackTop + viewState.getYTranslation() + view.getIntrinsicHeight(); + final boolean noSpaceForFooter = footerEnd > ambientState.getStackCutoff(); ((FooterView.FooterViewState) viewState).hideContent = noSpaceForFooter || (ambientState.isClearAllInProgress() && !hasNonClearableNotifs(algorithmState)); + } else { + // TODO(b/333445519): shouldBeHidden should reflect whether the shade is closed + // already, so we shouldn't need to use ambientState here. However, + // currently it doesn't get updated quickly enough and can cause the footer to + // flash when closing the shade. As such, we temporarily also check the + // ambientState directly. + if (((FooterView) view).shouldBeHidden() || !ambientState.isShadeExpanded()) { + viewState.hidden = true; + } else { + final float footerEnd = algorithmState.mCurrentExpandedYPosition + + view.getIntrinsicHeight(); + final boolean noSpaceForFooter = + footerEnd > ambientState.getStackEndHeight(); + ((FooterView.FooterViewState) viewState).hideContent = + noSpaceForFooter || (ambientState.isClearAllInProgress() + && !hasNonClearableNotifs(algorithmState)); + } } } else { final boolean shadeClosed = !ambientState.isShadeExpanded(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt index 5ae5a3213954..b22143f03b44 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt @@ -16,16 +16,12 @@ package com.android.systemui.statusbar.notification.stack.ui.viewbinder -import android.view.View -import android.view.WindowInsets import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle -import com.android.systemui.common.ui.view.onApplyWindowInsets import com.android.systemui.common.ui.view.onLayoutChanged import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.keyguard.ui.viewmodel.ViewStateAccessor import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.scene.shared.flag.SceneContainerFlag @@ -39,9 +35,6 @@ import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.DisposableHandle import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch /** Binds the shared notification container to its view-model. */ @@ -85,7 +78,6 @@ constructor( } } - val burnInParams = MutableStateFlow(BurnInParameters()) val viewState = ViewStateAccessor(alpha = { controller.getAlpha() }) /* @@ -140,9 +132,7 @@ constructor( if (!SceneContainerFlag.isEnabled) { launch { - burnInParams - .flatMapLatest { params -> viewModel.translationY(params) } - .collect { y -> controller.setTranslationY(y) } + viewModel.translationY.collect { y -> controller.setTranslationY(y) } } } @@ -178,16 +168,6 @@ constructor( controller.setOnHeightChangedRunnable { viewModel.notificationStackChanged() } disposables += DisposableHandle { controller.setOnHeightChangedRunnable(null) } - - disposables += - view.onApplyWindowInsets { _: View, insets: WindowInsets -> - val insetTypes = WindowInsets.Type.systemBars() or WindowInsets.Type.displayCutout() - burnInParams.update { current -> - current.copy(topInset = insets.getInsetsIgnoringVisibility(insetTypes).top) - } - insets - } - disposables += view.onLayoutChanged { viewModel.notificationStackChanged() } return disposables diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt index e34eb61c5cbd..57be62932e59 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt @@ -44,7 +44,7 @@ import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.AodToGoneTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AodToOccludedTransitionViewModel -import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters +import com.android.systemui.keyguard.ui.viewmodel.DozingToGlanceableHubTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DozingToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DozingToOccludedTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel @@ -112,6 +112,7 @@ constructor( private val aodToGoneTransitionViewModel: AodToGoneTransitionViewModel, private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel, private val aodToOccludedTransitionViewModel: AodToOccludedTransitionViewModel, + dozingToGlanceableHubTransitionViewModel: DozingToGlanceableHubTransitionViewModel, private val dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel, private val dozingToOccludedTransitionViewModel: DozingToOccludedTransitionViewModel, private val dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel, @@ -506,6 +507,7 @@ constructor( merge( lockscreenToGlanceableHubTransitionViewModel.notificationAlpha, glanceableHubToLockscreenTransitionViewModel.notificationAlpha, + dozingToGlanceableHubTransitionViewModel.notificationAlpha, ) // Manually emit on start because [notificationAlpha] only starts emitting // when transitions start. @@ -533,20 +535,18 @@ constructor( * Under certain scenarios, such as swiping up on the lockscreen, the container will need to be * translated as the keyguard fades out. */ - fun translationY(params: BurnInParameters): Flow<Float> { - // with SceneContainer, x translation is handled by views, y is handled by compose - SceneContainerFlag.assertInLegacyMode() - return combine( - aodBurnInViewModel - .movement(params) - .map { it.translationY.toFloat() } - .onStart { emit(0f) }, + val translationY: Flow<Float> = + combine( + aodBurnInViewModel.movement.map { it.translationY.toFloat() }.onStart { emit(0f) }, isOnLockscreenWithoutShade, merge( keyguardInteractor.keyguardTranslationY, occludedToLockscreenTransitionViewModel.lockscreenTranslationY, ), ) { burnInY, isOnLockscreenWithoutShade, translationY -> + // with SceneContainer, x translation is handled by views, y is handled by compose + SceneContainerFlag.assertInLegacyMode() + if (isOnLockscreenWithoutShade) { burnInY + translationY } else { @@ -554,7 +554,6 @@ constructor( } } .dumpWhileCollecting("translationY") - } /** Horizontal translation to apply to the container. */ val translationX: Flow<Float> = 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 59533b343a57..1d3f0e1f6dc3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -29,7 +29,6 @@ import static androidx.lifecycle.Lifecycle.State.RESUMED; import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME; import static com.android.systemui.Flags.keyboardShortcutHelperRewrite; import static com.android.systemui.Flags.lightRevealMigration; -import static com.android.systemui.Flags.newAodTransition; import static com.android.systemui.Flags.relockWithPowerButtonImmediately; import static com.android.systemui.Flags.statusBarSignalPolicyRefactor; import static com.android.systemui.charging.WirelessChargingAnimation.UNKNOWN_BATTERY_LEVEL; @@ -206,6 +205,7 @@ import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.core.StatusBarInitializer; +import com.android.systemui.statusbar.core.StatusBarSimpleFragment; import com.android.systemui.statusbar.data.model.StatusBarMode; import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore; import com.android.systemui.statusbar.notification.NotificationActivityStarter; @@ -1204,7 +1204,10 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { setBouncerShowingForStatusBarComponents(mBouncerShowing); checkBarModes(); }); - mStatusBarInitializer.initializeStatusBar(); + // When the flag is on, we register the fragment as a core startable and this is not needed + if (!StatusBarSimpleFragment.isEnabled()) { + mStatusBarInitializer.initializeStatusBar(); + } mStatusBarTouchableRegionManager.setup(getNotificationShadeWindowView()); @@ -1509,7 +1512,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mNotificationShadeWindowController.fetchWindowRootView(); getNotificationShadeWindowViewController().setupExpandedStatusBar(); getNotificationShadeWindowViewController().setupCommunalHubLayout(); - mBackActionInteractor.setup(mQsController, mShadeSurface); } protected NotificationShadeWindowViewController getNotificationShadeWindowViewController() { @@ -2547,7 +2549,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> { mDeviceInteractive = true; - boolean isFlaggedOff = newAodTransition() && MigrateClocksToBlueprint.isEnabled(); + boolean isFlaggedOff = MigrateClocksToBlueprint.isEnabled(); if (!isFlaggedOff && shouldAnimateDozeWakeup()) { // If this is false, the power button must be physically pressed in order to // trigger fingerprint authentication. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java deleted file mode 100644 index 942d186e7005..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.phone.dagger; - -import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.statusbar.phone.CentralSurfaces; -import com.android.systemui.statusbar.phone.CentralSurfacesImpl; - -import dagger.Binds; -import dagger.Module; - -/** - * Dagger Module providing {@link CentralSurfacesImpl}. - */ -@Module -public interface StatusBarPhoneModule { - /** - * Provides our instance of CentralSurfaces which is considered optional. - */ - @Binds - @SysUISingleton - CentralSurfaces bindsCentralSurfaces(CentralSurfacesImpl impl); -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt new file mode 100644 index 000000000000..13b651e8c0be --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.phone.dagger + +import com.android.systemui.CoreStartable +import com.android.systemui.statusbar.core.StatusBarInitializer +import com.android.systemui.statusbar.core.StatusBarInitializerImpl +import dagger.Binds +import dagger.Module +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap + +/** Similar in purpose to [StatusBarModule], but scoped only to phones */ +@Module +interface StatusBarPhoneModule { + + /** Binds {@link StatusBarInitializer} as a {@link CoreStartable}. */ + @Binds + @IntoMap + @ClassKey(StatusBarInitializerImpl::class) + fun bindStatusBarInitializer(impl: StatusBarInitializerImpl): CoreStartable + + @Binds fun statusBarInitializer(impl: StatusBarInitializerImpl): StatusBarInitializer +} 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 658455688865..a8b4728bc982 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 @@ -56,7 +56,8 @@ import com.android.systemui.statusbar.OperatorNameView; import com.android.systemui.statusbar.OperatorNameViewController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.chips.ron.shared.StatusBarRonChips; -import com.android.systemui.statusbar.disableflags.DisableFlagsLogger.DisableState; +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 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue 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 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue 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 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mNotificationIconAreaInner = notificationIcons; mNicBindingDisposable = mNicViewBinder.bindWhileAttached(notificationIcons); - updateNotificationIconAreaAndOngoingActivityChip(/* animate= */ false); + if (!StatusBarSimpleFragment.isEnabled()) { + updateNotificationIconAreaAndOngoingActivityChip(/* animate= */ false); + } Trace.endSection(); } @@ -509,11 +516,17 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue 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 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue boolean hasPrimaryOngoingActivity, boolean hasSecondaryOngoingActivity, boolean shouldAnimate) { + if (StatusBarSimpleFragment.isEnabled()) { + return; + } mHasPrimaryOngoingActivity = hasPrimaryOngoingActivity; mHasSecondaryOngoingActivity = hasSecondaryOngoingActivity; updateStatusBarVisibilities(shouldAnimate); @@ -530,6 +546,9 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue @Override public void onIsHomeStatusBarAllowedBySceneChanged( boolean isHomeStatusBarAllowedByScene) { + if (StatusBarSimpleFragment.isEnabled()) { + return; + } mHomeStatusBarAllowedByScene = isHomeStatusBarAllowedByScene; updateStatusBarVisibilities(/* animate= */ true); } @@ -537,17 +556,22 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue @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 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue private StatusBarVisibilityModel calculateInternalModel( StatusBarVisibilityModel externalModel) { + StatusBarSimpleFragment.assertInLegacyMode(); + // TODO(b/328393714) use HeadsUpNotificationInteractor.showHeadsUpStatusBar instead. boolean headsUpVisible = mStatusBarFragmentComponent.getHeadsUpAppearanceController().shouldBeVisible(); @@ -639,6 +665,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue * mLastModifiedVisibility. */ private void updateNotificationIconAreaAndOngoingActivityChip(boolean animate) { + StatusBarSimpleFragment.assertInLegacyMode(); + StatusBarVisibilityModel visibilityModel = mLastModifiedVisibility; boolean disableNotifications = !visibilityModel.getShowNotificationIcons(); boolean hasOngoingActivity = visibilityModel.getShowPrimaryOngoingActivityChip(); @@ -674,6 +702,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue } private boolean shouldHideStatusBar() { + StatusBarSimpleFragment.assertInLegacyMode(); + if (!mShadeExpansionStateManager.isClosed() && mPanelExpansionInteractor.shouldHideStatusBarIconsWhenExpanded()) { return true; @@ -728,6 +758,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue } private void hideEndSideContent(boolean animate) { + StatusBarSimpleFragment.assertInLegacyMode(); if (!animate || !mAnimationsEnabled) { mEndSideAlphaController.setAlpha(/*alpha*/ 0f, SOURCE_OTHER); } else { @@ -737,6 +768,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue } private void showEndSideContent(boolean animate) { + StatusBarSimpleFragment.assertInLegacyMode(); if (!animate || !mAnimationsEnabled) { mEndSideAlphaController.setAlpha(1f, SOURCE_OTHER); return; @@ -753,15 +785,18 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue } 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 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue * 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 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue * 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 class CollapsedStatusBarFragment extends Fragment implements CommandQueue } 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 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue * 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 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue * Hides a view. */ private void animateHide(final View v, boolean animate) { + StatusBarSimpleFragment.assertInLegacyMode(); animateHiddenState(v, View.INVISIBLE, animate); } @@ -847,6 +892,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue * 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 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue 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 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue @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 c8836e4235dc..eaf15a8cbe17 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 android.view.View 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 @@ constructor(private val view: View, private val initialAlpha: Float = 1f) { 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 @@ constructor(private val view: View, private val initialAlpha: Float = 1f) { 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/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt index 68163b28dd09..4ef328cf1623 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt @@ -149,7 +149,7 @@ class MobileIconInteractorImpl( override val isForceHidden: Flow<Boolean>, connectionRepository: MobileConnectionRepository, private val context: Context, - val carrierIdOverrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl() + val carrierIdOverrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl(), ) : MobileIconInteractor { override val tableLogBuffer: TableLogBuffer = connectionRepository.tableLogBuffer @@ -182,7 +182,7 @@ class MobileIconInteractorImpl( .stateIn( scope, SharingStarted.WhileSubscribed(), - connectionRepository.networkName.value + connectionRepository.networkName.value, ) override val carrierName = @@ -198,7 +198,7 @@ class MobileIconInteractorImpl( .stateIn( scope, SharingStarted.WhileSubscribed(), - connectionRepository.carrierName.value.name + connectionRepository.carrierName.value.name, ) /** What the mobile icon would be before carrierId overrides */ @@ -219,10 +219,7 @@ class MobileIconInteractorImpl( .stateIn(scope, SharingStarted.WhileSubscribed(), defaultMobileIconGroup.value) override val networkTypeIconGroup = - combine( - defaultNetworkType, - carrierIdIconOverrideExists, - ) { networkType, overrideExists -> + combine(defaultNetworkType, carrierIdIconOverrideExists) { networkType, overrideExists -> // DefaultIcon comes out of the icongroup lookup, we check for overrides here if (overrideExists) { val iconOverride = @@ -316,30 +313,30 @@ class MobileIconInteractorImpl( /** Whether or not to show the error state of [SignalDrawable] */ private val showExclamationMark: StateFlow<Boolean> = - combine( - defaultSubscriptionHasDataEnabled, + combine(defaultSubscriptionHasDataEnabled, isDefaultConnectionFailed, isInService) { + isDefaultDataEnabled, isDefaultConnectionFailed, - isInService, - ) { isDefaultDataEnabled, isDefaultConnectionFailed, isInService -> + isInService -> !isDefaultDataEnabled || isDefaultConnectionFailed || !isInService } .stateIn(scope, SharingStarted.WhileSubscribed(), true) private val cellularShownLevel: StateFlow<Int> = - combine( + combine(level, isInService, connectionRepository.inflateSignalStrength) { level, isInService, - connectionRepository.inflateSignalStrength, - ) { level, isInService, inflate -> + inflate -> if (isInService) { if (inflate) level + 1 else level } else 0 } .stateIn(scope, SharingStarted.WhileSubscribed(), 0) - // Satellite level is unaffected by the isInService or inflateSignalStrength properties + // Satellite level is unaffected by the inflateSignalStrength property // See b/346904529 for details - private val satelliteShownLevel: StateFlow<Int> = level + private val satelliteShownLevel: StateFlow<Int> = + combine(level, isInService) { level, isInService -> if (isInService) level else 0 } + .stateIn(scope, SharingStarted.WhileSubscribed(), 0) private val cellularIcon: Flow<SignalIconModel.Cellular> = combine( @@ -362,7 +359,7 @@ class MobileIconInteractorImpl( level = it, icon = SatelliteIconModel.fromSignalStrength(it) - ?: SatelliteIconModel.fromSignalStrength(0)!! + ?: SatelliteIconModel.fromSignalStrength(0)!!, ) } @@ -383,11 +380,7 @@ class MobileIconInteractorImpl( } } .distinctUntilChanged() - .logDiffsForTable( - tableLogBuffer, - columnPrefix = "icon", - initialValue = initial, - ) + .logDiffsForTable(tableLogBuffer, columnPrefix = "icon", initialValue = initial) .stateIn(scope, SharingStarted.WhileSubscribed(), initial) } } 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 deae576662e3..bad6f80c3735 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.mobile.ui.view.ModernStatusBarMob 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 @@ constructor( 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 @@ constructor( 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 000000000000..9164da721e3a --- /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 000000000000..69e9746ee24f --- /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 49eabba5c2b0..eea4c212e40e 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.animation.AnimatorListenerAdapter 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.res.R 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 @@ -86,19 +89,30 @@ class CollapsedStatusBarViewBinderImpl @Inject constructor() : CollapsedStatusBa launch { viewModel.primaryOngoingActivityChip.collect { primaryChipModel -> OngoingActivityChipBinder.bind(primaryChipModel, primaryChipView) - when (primaryChipModel) { - is OngoingActivityChipModel.Shown -> - listener.onOngoingActivityStatusChanged( - hasPrimaryOngoingActivity = true, - hasSecondaryOngoingActivity = false, - shouldAnimate = true, - ) - is OngoingActivityChipModel.Hidden -> - listener.onOngoingActivityStatusChanged( - hasPrimaryOngoingActivity = false, - hasSecondaryOngoingActivity = false, - shouldAnimate = primaryChipModel.shouldAnimate, - ) + if (StatusBarSimpleFragment.isEnabled) { + when (primaryChipModel) { + is OngoingActivityChipModel.Shown -> + primaryChipView.show(shouldAnimateChange = true) + is OngoingActivityChipModel.Hidden -> + primaryChipView.hide( + shouldAnimateChange = primaryChipModel.shouldAnimate + ) + } + } else { + when (primaryChipModel) { + is OngoingActivityChipModel.Shown -> + listener.onOngoingActivityStatusChanged( + hasPrimaryOngoingActivity = true, + hasSecondaryOngoingActivity = false, + shouldAnimate = true, + ) + is OngoingActivityChipModel.Hidden -> + listener.onOngoingActivityStatusChanged( + hasPrimaryOngoingActivity = false, + hasSecondaryOngoingActivity = false, + shouldAnimate = primaryChipModel.shouldAnimate, + ) + } } } } @@ -115,14 +129,22 @@ class CollapsedStatusBarViewBinderImpl @Inject constructor() : CollapsedStatusBa // TODO(b/364653005): Don't show the secondary chip if there isn't // enough space for it. OngoingActivityChipBinder.bind(chips.secondary, secondaryChipView) - listener.onOngoingActivityStatusChanged( - hasPrimaryOngoingActivity = - chips.primary is OngoingActivityChipModel.Shown, - hasSecondaryOngoingActivity = - chips.secondary is OngoingActivityChipModel.Shown, - // TODO(b/364653005): Figure out the animation story here. - shouldAnimate = true, - ) + + if (StatusBarSimpleFragment.isEnabled) { + primaryChipView.adjustVisibility(chips.primary.toVisibilityModel()) + secondaryChipView.adjustVisibility( + chips.secondary.toVisibilityModel() + ) + } else { + listener.onOngoingActivityStatusChanged( + hasPrimaryOngoingActivity = + chips.primary is OngoingActivityChipModel.Shown, + hasSecondaryOngoingActivity = + chips.secondary is OngoingActivityChipModel.Shown, + // TODO(b/364653005): Figure out the animation story here. + shouldAnimate = true, + ) + } } } } @@ -134,10 +156,42 @@ class CollapsedStatusBarViewBinderImpl @Inject constructor() : CollapsedStatusBa } } } + + 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. + } + } + } } } } + private fun OngoingActivityChipModel.toVisibilityModel(): + CollapsedStatusBarViewModel.VisibilityModel { + return CollapsedStatusBarViewModel.VisibilityModel( + visibility = if (this is OngoingActivityChipModel.Shown) View.VISIBLE else View.GONE, + // TODO(b/364653005): Figure out the animation story here. + shouldAnimateChange = true, + ) + } + private fun animateLightsOutView(view: View, visible: Boolean) { view.animate().cancel() @@ -167,6 +221,54 @@ class CollapsedStatusBarViewBinderImpl @Inject constructor() : CollapsedStatusBa ) .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 9cce2b8fb72b..366ea3516965 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,16 @@ interface CollapsedStatusBarViewModel { /** * 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> + /** * 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 +106,26 @@ interface CollapsedStatusBarViewModel { * [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 +170,59 @@ constructor( } .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 1127f6fe3614..caf09a3b638e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt @@ -216,7 +216,7 @@ constructor( ) return } - var stateAfter: String + val stateAfter: String if (entry in nextMap) { if (entry in nextMap) nextMap.remove(entry) if (entry in nextList) nextList.remove(entry) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt index 27bc6d36c1e6..76389f39e484 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt @@ -71,7 +71,7 @@ fun ModeTile(viewModel: ModeTileViewModel) { .semantics { stateDescription = viewModel.stateDescription }, verticalAlignment = Alignment.CenterVertically, horizontalArrangement = - Arrangement.spacedBy(space = 8.dp, alignment = Alignment.Start), + Arrangement.spacedBy(space = 12.dp, alignment = Alignment.Start), ) { Icon(icon = viewModel.icon, modifier = Modifier.size(24.dp)) Column { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt index 5953ea598929..5392e38823c6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt @@ -26,7 +26,6 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.android.systemui.Flags import com.android.systemui.statusbar.policy.ui.dialog.viewmodel.ModesDialogViewModel @Composable @@ -34,8 +33,8 @@ fun ModeTileGrid(viewModel: ModesDialogViewModel) { val tiles by viewModel.tiles.collectAsStateWithLifecycle(initialValue = emptyList()) LazyVerticalGrid( - columns = GridCells.Fixed(if (Flags.modesDialogSingleRows()) 1 else 2), - modifier = Modifier.fillMaxWidth().heightIn(max = 300.dp), + columns = GridCells.Fixed(1), + modifier = Modifier.fillMaxWidth().heightIn(max = 320.dp), verticalArrangement = Arrangement.spacedBy(8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), ) { 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 fa9c6b2c8151..1a1a592e60be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt @@ -32,13 +32,14 @@ import javax.inject.Inject * A centralized class maintaining the state of the status bar window. * * @deprecated use - * [com.android.systemui.statusbar.window.data.repository.StatusBarWindowStateRepository] instead. + * [com.android.systemui.statusbar.window.data.repository.StatusBarWindowStateRepositoryStore.defaultDisplay] + * repo 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 -@Deprecated("Use StatusBarWindowRepository instead") +@Deprecated("Use StatusBarWindowStateRepositoryStore.defaultDisplay instead") class StatusBarWindowStateController @Inject constructor(@DisplayId private val thisDisplayId: Int, commandQueue: CommandQueue) { 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/StatusBarWindowStatePerDisplayRepository.kt index 678576d1b450..bef8c84be5c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStatePerDisplayRepository.kt @@ -22,13 +22,13 @@ 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 dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.SharingStarted @@ -40,16 +40,23 @@ import kotlinx.coroutines.flow.stateIn * * 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]. + * + * Each concrete implementation of this class will be for a specific display ID. Use + * [StatusBarWindowStateRepositoryStore] to fetch a concrete implementation for a certain display. */ -@SysUISingleton -class StatusBarWindowStateRepository -@Inject +interface StatusBarWindowStatePerDisplayRepository { + /** Emits the current window state for the status bar on this specific display. */ + val windowState: StateFlow<StatusBarWindowState> +} + +class StatusBarWindowStatePerDisplayRepositoryImpl +@AssistedInject constructor( + @Assisted private val thisDisplayId: Int, private val commandQueue: CommandQueue, - @DisplayId private val thisDisplayId: Int, @Application private val scope: CoroutineScope, -) { - val windowState: StateFlow<StatusBarWindowState> = +) : StatusBarWindowStatePerDisplayRepository { + override val windowState: StateFlow<StatusBarWindowState> = conflatedCallbackFlow { val callback = object : CommandQueue.Callbacks { @@ -84,3 +91,8 @@ constructor( } } } + +@AssistedFactory +interface StatusBarWindowStatePerDisplayRepositoryFactory { + fun create(@Assisted displayId: Int): StatusBarWindowStatePerDisplayRepositoryImpl +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStore.kt new file mode 100644 index 000000000000..0e33326508f7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStore.kt @@ -0,0 +1,60 @@ +/* + * 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 com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.DisplayId +import java.lang.ref.WeakReference +import javax.inject.Inject + +/** + * Singleton class to create instances of [StatusBarWindowStatePerDisplayRepository] for a specific + * display. + * + * Repository instances for a specific display should be cached so that if multiple classes request + * a repository for the same display ID, we only create the repository once. + */ +interface StatusBarWindowStateRepositoryStore { + val defaultDisplay: StatusBarWindowStatePerDisplayRepository + + fun forDisplay(displayId: Int): StatusBarWindowStatePerDisplayRepository +} + +@SysUISingleton +class StatusBarWindowStateRepositoryStoreImpl +@Inject +constructor( + @DisplayId private val displayId: Int, + private val factory: StatusBarWindowStatePerDisplayRepositoryFactory, +) : StatusBarWindowStateRepositoryStore { + // Use WeakReferences to store the repositories so that the repositories are kept around so long + // as some UI holds a reference to them, but the repositories are cleaned up once no UI is using + // them anymore. + // See Change-Id Ib490062208506d646add2fe7e5e5d4df5fb3e66e for similar behavior in + // MobileConnectionsRepositoryImpl. + private val repositoryCache = + mutableMapOf<Int, WeakReference<StatusBarWindowStatePerDisplayRepository>>() + + override val defaultDisplay = factory.create(displayId) + + override fun forDisplay(displayId: Int): StatusBarWindowStatePerDisplayRepository { + synchronized(repositoryCache) { + return repositoryCache[displayId]?.get() + ?: factory.create(displayId).also { repositoryCache[displayId] = WeakReference(it) } + } + } +} 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 8ecf250e2bbd..2af84c7e46f0 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 @@ class GlobalCoroutinesModule { @Application fun applicationScope( @Main dispatcherContext: CoroutineContext, - ): CoroutineScope = CoroutineScope(dispatcherContext) + ): CoroutineScope = CoroutineScope(dispatcherContext + createCoroutineTracingContext("ApplicationScope")) @Provides @Singleton @@ -51,15 +51,7 @@ class GlobalCoroutinesModule { @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 a03221e03467..3c0682822564 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 @@ class SysUICoroutinesModule { @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 @@ class SysUICoroutinesModule { @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 82f41a7fd154..4d9aaa6dc6b0 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 @@ interface SettingsProxy { */ @AnyThread fun registerContentObserverAsync(name: String, settingsObserver: ContentObserver) = - CoroutineScope(backgroundDispatcher).launch { + CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-A")).launch { registerContentObserverSync(getUriFor(name), settingsObserver) } @@ -110,7 +111,7 @@ interface SettingsProxy { settingsObserver: ContentObserver, @WorkerThread registered: Runnable ) = - CoroutineScope(backgroundDispatcher).launch { + CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-B")).launch { registerContentObserverSync(getUriFor(name), settingsObserver) registered.run() } @@ -143,7 +144,7 @@ interface SettingsProxy { */ @AnyThread fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) = - CoroutineScope(backgroundDispatcher).launch { + CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-C")).launch { registerContentObserverSync(uri, settingsObserver) } @@ -160,7 +161,7 @@ interface SettingsProxy { settingsObserver: ContentObserver, @WorkerThread registered: Runnable ) = - CoroutineScope(backgroundDispatcher).launch { + CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-D")).launch { registerContentObserverSync(uri, settingsObserver) registered.run() } @@ -205,7 +206,7 @@ interface SettingsProxy { notifyForDescendants: Boolean, settingsObserver: ContentObserver ) = - CoroutineScope(backgroundDispatcher).launch { + CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-E")).launch { registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver) } @@ -223,7 +224,7 @@ interface SettingsProxy { 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 @@ interface SettingsProxy { notifyForDescendants: Boolean, settingsObserver: ContentObserver ) = - CoroutineScope(backgroundDispatcher).launch { + CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-G")).launch { registerContentObserverSync(uri, notifyForDescendants, settingsObserver) } @@ -292,7 +293,7 @@ interface SettingsProxy { settingsObserver: ContentObserver, @WorkerThread registered: Runnable ) = - CoroutineScope(backgroundDispatcher).launch { + CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-H")).launch { registerContentObserverSync(uri, notifyForDescendants, settingsObserver) registered.run() } @@ -329,7 +330,7 @@ interface SettingsProxy { */ @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 8e3b813a2a82..c820c07b61b1 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 @@ interface UserSettingsProxy : SettingsProxy { } override fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) = - CoroutineScope(backgroundDispatcher).launch { + CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-A")).launch { registerContentObserverForUserSync(uri, settingsObserver, userId) } @@ -112,7 +113,7 @@ interface UserSettingsProxy : SettingsProxy { notifyForDescendants: Boolean, settingsObserver: ContentObserver ) = - CoroutineScope(backgroundDispatcher).launch { + CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-B")).launch { registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId) } @@ -157,7 +158,7 @@ interface UserSettingsProxy : SettingsProxy { settingsObserver: ContentObserver, userHandle: Int ) = - CoroutineScope(backgroundDispatcher).launch { + CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-C")).launch { registerContentObserverForUserSync(getUriFor(name), settingsObserver, userHandle) } @@ -198,7 +199,7 @@ interface UserSettingsProxy : SettingsProxy { settingsObserver: ContentObserver, userHandle: Int ) = - CoroutineScope(backgroundDispatcher).launch { + CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-D")).launch { registerContentObserverForUserSync(uri, settingsObserver, userHandle) } @@ -215,7 +216,7 @@ interface UserSettingsProxy : SettingsProxy { userHandle: Int, @WorkerThread registered: Runnable ) = - CoroutineScope(backgroundDispatcher).launch { + CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-E")).launch { registerContentObserverForUserSync(uri, settingsObserver, userHandle) registered.run() } @@ -274,7 +275,7 @@ interface UserSettingsProxy : SettingsProxy { settingsObserver: ContentObserver, userHandle: Int ) { - CoroutineScope(backgroundDispatcher).launch { + CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-F")).launch { registerContentObserverForUserSync( getUriFor(name), notifyForDescendants, @@ -338,7 +339,7 @@ interface UserSettingsProxy : SettingsProxy { settingsObserver: ContentObserver, userHandle: Int ) = - CoroutineScope(backgroundDispatcher).launch { + CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-G")).launch { registerContentObserverForUserSync( uri, notifyForDescendants, diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt index a94ef36bda29..c7b707d02cb3 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt @@ -17,11 +17,16 @@ package com.android.keyguard import android.content.BroadcastReceiver import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import android.provider.Settings import android.view.View import android.view.ViewTreeObserver import android.widget.FrameLayout import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.settingslib.notification.modes.TestModeBuilder.MANUAL_DND_ACTIVE +import com.android.settingslib.notification.modes.TestModeBuilder.MANUAL_DND_INACTIVE +import com.android.systemui.Flags as AConfigFlags import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.flags.Flags @@ -36,6 +41,7 @@ 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.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope import com.android.systemui.log.core.LogLevel import com.android.systemui.log.core.LogcatOnlyMessageBuffer import com.android.systemui.plugins.clocks.ClockAnimations @@ -46,9 +52,15 @@ import com.android.systemui.plugins.clocks.ClockFaceController import com.android.systemui.plugins.clocks.ClockFaceEvents import com.android.systemui.plugins.clocks.ClockMessageBuffers import com.android.systemui.plugins.clocks.ClockTickRate +import com.android.systemui.plugins.clocks.ZenData +import com.android.systemui.plugins.clocks.ZenData.ZenMode +import com.android.systemui.res.R import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ZenModeController +import com.android.systemui.statusbar.policy.data.repository.fakeZenModeRepository +import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor +import com.android.systemui.testKosmos import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor @@ -57,9 +69,12 @@ import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import java.util.TimeZone import java.util.concurrent.Executor +import java.util.concurrent.TimeUnit import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest import kotlinx.coroutines.yield import org.junit.Assert.assertEquals import org.junit.Before @@ -73,15 +88,26 @@ import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.times import org.mockito.Mockito.verify -import org.mockito.junit.MockitoJUnit -import com.android.systemui.Flags as AConfigFlags import org.mockito.Mockito.`when` as whenever +import org.mockito.junit.MockitoJUnit @RunWith(AndroidJUnit4::class) @SmallTest +@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) class ClockEventControllerTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val zenModeRepository = kosmos.fakeZenModeRepository + private val testScope = kosmos.testScope + @JvmField @Rule val mockito = MockitoJUnit.rule() + + private val mainExecutor = ImmediateExecutor() + private lateinit var repository: FakeKeyguardRepository + private val messageBuffer = LogcatOnlyMessageBuffer(LogLevel.DEBUG) + private val clockBuffers = ClockMessageBuffers(messageBuffer, messageBuffer, messageBuffer) + private lateinit var underTest: ClockEventController + @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher @Mock private lateinit var batteryController: BatteryController @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @@ -89,7 +115,6 @@ class ClockEventControllerTest : SysuiTestCase() { @Mock private lateinit var animations: ClockAnimations @Mock private lateinit var events: ClockEvents @Mock private lateinit var clock: ClockController - @Mock private lateinit var mainExecutor: DelayableExecutor @Mock private lateinit var bgExecutor: Executor @Mock private lateinit var smallClockController: ClockFaceController @Mock private lateinit var smallClockView: View @@ -102,12 +127,10 @@ class ClockEventControllerTest : SysuiTestCase() { @Mock private lateinit var smallClockEvents: ClockFaceEvents @Mock private lateinit var largeClockEvents: ClockFaceEvents @Mock private lateinit var parentView: View - private lateinit var repository: FakeKeyguardRepository @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor - private val messageBuffer = LogcatOnlyMessageBuffer(LogLevel.DEBUG) - private val clockBuffers = ClockMessageBuffers(messageBuffer, messageBuffer, messageBuffer) - private lateinit var underTest: ClockEventController + @Mock private lateinit var zenModeController: ZenModeController + private var zenModeControllerCallback: ZenModeController.Callback? = null @Before fun setUp() { @@ -129,12 +152,11 @@ class ClockEventControllerTest : SysuiTestCase() { whenever(largeClockController.config) .thenReturn(ClockFaceConfig(tickRate = ClockTickRate.PER_MINUTE)) + zenModeRepository.addMode(MANUAL_DND_INACTIVE) + repository = FakeKeyguardRepository() - val withDeps = - KeyguardInteractorFactory.create( - repository = repository, - ) + val withDeps = KeyguardInteractorFactory.create(repository = repository) withDeps.featureFlags.apply { set(Flags.REGION_SAMPLING, false) } underTest = @@ -151,7 +173,8 @@ class ClockEventControllerTest : SysuiTestCase() { bgExecutor, clockBuffers, withDeps.featureFlags, - zenModeController + zenModeController, + kosmos.zenModeInteractor, ) underTest.clock = clock @@ -161,6 +184,10 @@ class ClockEventControllerTest : SysuiTestCase() { repository.setIsDozing(true) repository.setDozeAmount(1f) } + + val zenCallbackCaptor = argumentCaptor<ZenModeController.Callback>() + verify(zenModeController).addCallback(zenCallbackCaptor.capture()) + zenModeControllerCallback = zenCallbackCaptor.value } @Test @@ -349,17 +376,12 @@ class ClockEventControllerTest : SysuiTestCase() { fun listenForTransitionToAodFromGone_updatesClockDozeAmountToOne() = runBlocking(IMMEDIATE) { val transitionStep = MutableStateFlow(TransitionStep()) - whenever(keyguardTransitionInteractor - .transition(Edge.create(to = AOD))) + whenever(keyguardTransitionInteractor.transition(Edge.create(to = AOD))) .thenReturn(transitionStep) val job = underTest.listenForAnyStateToAodTransition(this) transitionStep.value = - TransitionStep( - from = GONE, - to = AOD, - transitionState = TransitionState.STARTED, - ) + TransitionStep(from = GONE, to = AOD, transitionState = TransitionState.STARTED) yield() verify(animations, times(2)).doze(1f) @@ -371,8 +393,7 @@ class ClockEventControllerTest : SysuiTestCase() { fun listenForTransitionToLSFromOccluded_updatesClockDozeAmountToZero() = runBlocking(IMMEDIATE) { val transitionStep = MutableStateFlow(TransitionStep()) - whenever(keyguardTransitionInteractor - .transition(Edge.create(to = LOCKSCREEN))) + whenever(keyguardTransitionInteractor.transition(Edge.create(to = LOCKSCREEN))) .thenReturn(transitionStep) val job = underTest.listenForAnyStateToLockscreenTransition(this) @@ -393,8 +414,7 @@ class ClockEventControllerTest : SysuiTestCase() { fun listenForTransitionToAodFromLockscreen_neverUpdatesClockDozeAmount() = runBlocking(IMMEDIATE) { val transitionStep = MutableStateFlow(TransitionStep()) - whenever(keyguardTransitionInteractor - .transition(Edge.create(to = AOD))) + whenever(keyguardTransitionInteractor.transition(Edge.create(to = AOD))) .thenReturn(transitionStep) val job = underTest.listenForAnyStateToAodTransition(this) @@ -415,8 +435,7 @@ class ClockEventControllerTest : SysuiTestCase() { fun listenForAnyStateToLockscreenTransition_neverUpdatesClockDozeAmount() = runBlocking(IMMEDIATE) { val transitionStep = MutableStateFlow(TransitionStep()) - whenever(keyguardTransitionInteractor - .transition(Edge.create(to = LOCKSCREEN))) + whenever(keyguardTransitionInteractor.transition(Edge.create(to = LOCKSCREEN))) .thenReturn(transitionStep) val job = underTest.listenForAnyStateToLockscreenTransition(this) @@ -437,8 +456,7 @@ class ClockEventControllerTest : SysuiTestCase() { fun listenForAnyStateToDozingTransition_UpdatesClockDozeAmountToOne() = runBlocking(IMMEDIATE) { val transitionStep = MutableStateFlow(TransitionStep()) - whenever(keyguardTransitionInteractor - .transition(Edge.create(to = DOZING))) + whenever(keyguardTransitionInteractor.transition(Edge.create(to = DOZING))) .thenReturn(transitionStep) val job = underTest.listenForAnyStateToDozingTransition(this) @@ -498,7 +516,57 @@ class ClockEventControllerTest : SysuiTestCase() { verify(smallClockFrame.viewTreeObserver).removeOnGlobalLayoutListener(any()) } + @Test + @EnableFlags(android.app.Flags.FLAG_MODES_UI) + fun listenForDnd_onDndChange_updatesClockZenMode() = + testScope.runTest { + underTest.listenForDnd(testScope.backgroundScope) + + zenModeRepository.replaceMode(MANUAL_DND_INACTIVE.id, MANUAL_DND_ACTIVE) + runCurrent() + + verify(events) + .onZenDataChanged( + eq(ZenData(ZenMode.IMPORTANT_INTERRUPTIONS, R.string::dnd_is_on.name)) + ) + + zenModeRepository.replaceMode(MANUAL_DND_ACTIVE.id, MANUAL_DND_INACTIVE) + runCurrent() + + verify(events).onZenDataChanged(eq(ZenData(ZenMode.OFF, R.string::dnd_is_off.name))) + } + + @Test + @DisableFlags(android.app.Flags.FLAG_MODES_UI) + fun zenModeControllerCallback_onDndChange_updatesClockZenMode() = + runBlocking(IMMEDIATE) { + zenModeControllerCallback!!.onZenChanged( + Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS + ) + + verify(events) + .onZenDataChanged( + eq(ZenData(ZenMode.IMPORTANT_INTERRUPTIONS, R.string::dnd_is_on.name)) + ) + + zenModeControllerCallback!!.onZenChanged(Settings.Global.ZEN_MODE_OFF) + + verify(events).onZenDataChanged(eq(ZenData(ZenMode.OFF, R.string::dnd_is_off.name))) + } + companion object { private val IMMEDIATE = Dispatchers.Main.immediate } } + +private class ImmediateExecutor : DelayableExecutor { + override fun execute(runnable: Runnable) { + runnable.run() + } + + override fun executeDelayed(runnable: Runnable, delay: Long, unit: TimeUnit) = + runnable.apply { run() } + + override fun executeAtTime(runnable: Runnable, uptimeMillis: Long, unit: TimeUnit) = + runnable.apply { run() } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt index d63e728cf443..d63e728cf443 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt index e444db4895d4..5fe5cb3fe43c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt @@ -76,6 +76,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.UserSwitcherController import com.android.systemui.testKosmos import com.android.systemui.user.domain.interactor.SelectedUserInteractor +import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.kotlin.JavaAdapter import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argThat @@ -84,6 +85,7 @@ import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.GlobalSettings +import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth import junit.framework.Assert import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -172,6 +174,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { @Mock private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor private lateinit var sceneTransitionStateFlow: MutableStateFlow<ObservableTransitionState> private lateinit var fakeSceneDataSource: FakeSceneDataSource + private val executor = FakeExecutor(FakeSystemClock()) private lateinit var underTest: KeyguardSecurityContainerController @@ -210,13 +213,9 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { featureFlags = FakeFeatureFlags() featureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false) - mSetFlagsRule.enableFlags( - AConfigFlags.FLAG_REVAMPED_BOUNCER_MESSAGES, - ) + mSetFlagsRule.enableFlags(AConfigFlags.FLAG_REVAMPED_BOUNCER_MESSAGES) if (!SceneContainerFlag.isEnabled) { - mSetFlagsRule.disableFlags( - AConfigFlags.FLAG_KEYGUARD_WM_STATE_REFACTOR, - ) + mSetFlagsRule.disableFlags(AConfigFlags.FLAG_KEYGUARD_WM_STATE_REFACTOR) } keyguardPasswordViewController = @@ -239,7 +238,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { mSelectedUserInteractor, keyguardKeyboardInteractor, null, - mUserActivityNotifier + mUserActivityNotifier, ) kosmos = testKosmos() @@ -283,6 +282,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { devicePolicyManager, kosmos.keyguardDismissTransitionInteractor, { primaryBouncerInteractor }, + executor, ) { deviceEntryInteractor } @@ -298,7 +298,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { eq(falsingManager), eq(userSwitcherController), any(), - eq(falsingA11yDelegate) + eq(falsingA11yDelegate), ) } @@ -334,7 +334,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { eq(falsingManager), eq(userSwitcherController), any(), - eq(falsingA11yDelegate) + eq(falsingA11yDelegate), ) // Update rotation. Should trigger update @@ -347,7 +347,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { eq(falsingManager), eq(userSwitcherController), any(), - eq(falsingA11yDelegate) + eq(falsingA11yDelegate), ) } @@ -359,7 +359,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { MotionEvent.ACTION_DOWN, /* x= */ 0f, /* y= */ 0f, - /* metaState= */ 0 + /* metaState= */ 0, ) ) } @@ -386,7 +386,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { eq(falsingManager), eq(userSwitcherController), any(), - eq(falsingA11yDelegate) + eq(falsingA11yDelegate), ) } @@ -401,7 +401,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { eq(falsingManager), eq(userSwitcherController), any(), - eq(falsingA11yDelegate) + eq(falsingA11yDelegate), ) } @@ -416,7 +416,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { eq(falsingManager), eq(userSwitcherController), any(), - eq(falsingA11yDelegate) + eq(falsingA11yDelegate), ) } @@ -431,7 +431,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { eq(falsingManager), eq(userSwitcherController), any(), - eq(falsingA11yDelegate) + eq(falsingA11yDelegate), ) } @@ -446,7 +446,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { eq(falsingManager), eq(userSwitcherController), any(), - eq(falsingA11yDelegate) + eq(falsingA11yDelegate), ) } @@ -462,7 +462,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { .showMessage( /* message= */ context.getString(R.string.keyguard_unlock_to_continue), /* colorState= */ null, - /* animated= */ true + /* animated= */ true, ) } @@ -496,7 +496,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { /* authenticated= */ true, TARGET_USER_ID, /* bypassSecondaryLockScreen= */ true, - SecurityMode.SimPin + SecurityMode.SimPin, ) // THEN the next security method of None will dismiss keyguard. @@ -514,7 +514,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { /* authenticated= */ true, TARGET_USER_ID, /* bypassSecondaryLockScreen= */ true, - SecurityMode.SimPin + SecurityMode.SimPin, ) // THEN no action has happened, which will not dismiss the security screens @@ -539,7 +539,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { /* authenticated= */ true, TARGET_USER_ID, /* bypassSecondaryLockScreen= */ true, - SecurityMode.SimPin + SecurityMode.SimPin, ) // THEN the next security method of None will dismiss keyguard. @@ -564,7 +564,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { /* authenticated= */ true, TARGET_USER_ID, /* bypassSecondaryLockScreen= */ true, - SecurityMode.SimPin + SecurityMode.SimPin, ) // THEN the next security method of None will dismiss keyguard. @@ -589,7 +589,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { /* authenticated= */ true, TARGET_USER_ID, /* bypassSecondaryLockScreen= */ true, - SecurityMode.SimPin + SecurityMode.SimPin, ) // THEN we will not show the password screen. @@ -615,7 +615,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { /* authenticated= */ true, TARGET_USER_ID, /* bypassSecondaryLockScreen= */ true, - SecurityMode.SimPin + SecurityMode.SimPin, ) // THEN we will not show the password screen. @@ -717,7 +717,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { // Now simulate a config change testableResources.addOverride( R.integer.keyguard_host_view_gravity, - Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM + Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM, ) underTest.updateResources() verify(view).layoutParams = any() @@ -728,7 +728,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { testableResources.addOverride(R.integer.keyguard_host_view_gravity, Gravity.CENTER) testableResources.addOverride( R.integer.keyguard_host_view_one_handed_gravity, - Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM + Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM, ) // Start disabled. @@ -948,7 +948,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { /* expiringUserId = */ mainUserId, /* mainUserId = */ mainUserId, /* remainingBeforeWipe = */ 1, - /* failedAttempts = */ 1 + /* failedAttempts = */ 1, ) verify(view) @@ -965,14 +965,14 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { /* expiringUserId = */ secondaryUserId, /* mainUserId = */ mainUserId, /* remainingBeforeWipe = */ 1, - /* failedAttempts = */ 1 + /* failedAttempts = */ 1, ) verify(view) .showAlmostAtWipeDialog( any(), any(), - eq(KeyguardSecurityContainer.USER_TYPE_SECONDARY_USER) + eq(KeyguardSecurityContainer.USER_TYPE_SECONDARY_USER), ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java index 7bb6ef1c8895..7bb6ef1c8895 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/biometrics/OWNERS index 5420c377be39..58ae2b2fa6df 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/OWNERS +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/OWNERS @@ -3,3 +3,4 @@ set noparent # Bug component: 879035 include /services/core/java/com/android/server/biometrics/OWNERS beverlyt@google.com +include /packages/SystemUI/TEST_OWNERS diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt index 48505102eba5..55fd3440ea07 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt @@ -54,7 +54,6 @@ import com.android.systemui.biometrics.data.repository.biometricStatusRepository import com.android.systemui.biometrics.data.repository.fakeFingerprintPropertyRepository import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor import com.android.systemui.biometrics.domain.interactor.promptSelectorInteractor -import com.android.systemui.biometrics.domain.interactor.sideFpsOverlayInteractor import com.android.systemui.biometrics.domain.interactor.udfpsOverlayInteractor import com.android.systemui.biometrics.extractAuthenticatorTypes import com.android.systemui.biometrics.faceSensorPropertiesInternal @@ -1454,15 +1453,11 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa @Test fun switch_to_credential_fallback() = runGenericTest { val size by collectLastValue(kosmos.promptViewModel.size) - val isShowingSfpsIndicator by collectLastValue(kosmos.sideFpsOverlayInteractor.isShowing) // TODO(b/251476085): remove Spaghetti, migrate logic, and update this test kosmos.promptViewModel.onSwitchToCredential() assertThat(size).isEqualTo(PromptSize.LARGE) - if (testCase.modalities.hasSfps) { - assertThat(isShowingSfpsIndicator).isFalse() - } } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/composable/BouncerPredictiveBackTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/composable/BouncerPredictiveBackTest.kt index 22946c8e6ad0..71afa62df3e0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/composable/BouncerPredictiveBackTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/composable/BouncerPredictiveBackTest.kt @@ -72,6 +72,7 @@ import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel import com.android.systemui.scene.ui.viewmodel.splitEdgeDetector import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.testKosmos +import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -115,11 +116,7 @@ class BouncerPredictiveBackTest : SysuiTestCase() { private val Kosmos.sceneKeys by Fixture { listOf(Scenes.Lockscreen, Scenes.Bouncer) } private val Kosmos.initialSceneKey by Fixture { Scenes.Bouncer } private val Kosmos.sceneContainerConfig by Fixture { - val navigationDistances = - mapOf( - Scenes.Lockscreen to 1, - Scenes.Bouncer to 0, - ) + val navigationDistances = mapOf(Scenes.Lockscreen to 1, Scenes.Bouncer to 0) SceneContainerConfig(sceneKeys, initialSceneKey, emptyList(), navigationDistances) } @@ -160,7 +157,7 @@ class BouncerPredictiveBackTest : SysuiTestCase() { BouncerScene( bouncerSceneActionsViewModelFactory, bouncerSceneContentViewModelFactory, - bouncerDialogFactory + bouncerDialogFactory, ) @Before @@ -175,7 +172,7 @@ class BouncerPredictiveBackTest : SysuiTestCase() { @Test fun bouncerPredictiveBackMotion() = - motionTestRule.runTest { + motionTestRule.runTest(timeout = 30.seconds) { val motion = recordMotion( content = { play -> @@ -189,11 +186,11 @@ class BouncerPredictiveBackTest : SysuiTestCase() { sceneByKey = mapOf( Scenes.Lockscreen to FakeLockscreen(), - Scenes.Bouncer to bouncerScene + Scenes.Bouncer to bouncerScene, ), initialSceneKey = Scenes.Bouncer, overlayByKey = emptyMap(), - dataSourceDelegator = kosmos.sceneDataSourceDelegator + dataSourceDelegator = kosmos.sceneDataSourceDelegator, ) } }, @@ -215,14 +212,14 @@ class BouncerPredictiveBackTest : SysuiTestCase() { feature( isElement(Bouncer.Elements.Content), positionInRoot, - "content_offset" + "content_offset", ) feature( isElement(Bouncer.Elements.Background), elementAlpha, - "background_alpha" + "background_alpha", ) - } + }, ) assertThat(motion).timeSeriesMatchesGolden() @@ -240,7 +237,7 @@ class BouncerPredictiveBackTest : SysuiTestCase() { } backProgress.animateTo( targetValue = 1f, - animationSpec = tween(durationMillis = 500) + animationSpec = tween(durationMillis = 500), ) { androidComposeTestRule.runOnUiThread { dispatcher.dispatchOnBackProgressed( @@ -309,10 +306,10 @@ class BouncerPredictiveBackTest : SysuiTestCase() { is JSONObject -> Offset( pivot.getDouble("x").toFloat(), - pivot.getDouble("y").toFloat() + pivot.getDouble("y").toFloat(), ) else -> throw UnknownTypeException() - } + }, ) } else -> throw UnknownTypeException() @@ -337,12 +334,12 @@ class BouncerPredictiveBackTest : SysuiTestCase() { put("x", it.pivot.x) put("y", it.pivot.y) } - } + }, ) } } } - } + }, ) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardModelTest.kt index 5d76e325bd3a..85e8ab43b2ee 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardModelTest.kt @@ -22,10 +22,12 @@ import android.content.Context import android.graphics.Bitmap import android.net.Uri import android.os.PersistableBundle +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.systemui.Flags.FLAG_CLIPBOARD_USE_DESCRIPTION_MIMETYPE import com.android.systemui.SysuiTestCase -import com.android.systemui.util.mockito.whenever import java.io.IOException import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse @@ -37,6 +39,7 @@ import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.any import org.mockito.Mock import org.mockito.MockitoAnnotations +import org.mockito.kotlin.whenever @SmallTest @RunWith(AndroidJUnit4::class) @@ -88,7 +91,8 @@ class ClipboardModelTest : SysuiTestCase() { @Test @Throws(IOException::class) - fun test_imageClipData() { + @DisableFlags(FLAG_CLIPBOARD_USE_DESCRIPTION_MIMETYPE) + fun test_imageClipData_legacy() { val testBitmap = Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888) whenever(mMockContext.contentResolver).thenReturn(mMockContentResolver) whenever(mMockContext.resources).thenReturn(mContext.resources) @@ -103,6 +107,21 @@ class ClipboardModelTest : SysuiTestCase() { @Test @Throws(IOException::class) + @EnableFlags(FLAG_CLIPBOARD_USE_DESCRIPTION_MIMETYPE) + fun test_imageClipData() { + val testBitmap = Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888) + whenever(mMockContext.contentResolver).thenReturn(mMockContentResolver) + whenever(mMockContext.resources).thenReturn(mContext.resources) + whenever(mMockContentResolver.loadThumbnail(any(), any(), any())).thenReturn(testBitmap) + whenever(mMockContentResolver.getType(any())).thenReturn("text") + val imageClipData = ClipData("Test", arrayOf("image/png"), ClipData.Item(Uri.parse("test"))) + val model = ClipboardModel.fromClipData(mMockContext, mClipboardUtils, imageClipData, "") + assertEquals(ClipboardModel.Type.IMAGE, model.type) + assertEquals(testBitmap, model.loadThumbnail(mMockContext)) + } + + @Test + @Throws(IOException::class) fun test_imageClipData_loadFailure() { whenever(mMockContext.contentResolver).thenReturn(mMockContentResolver) whenever(mMockContext.resources).thenReturn(mContext.resources) diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt index 633efd8bfffd..6c6de61c638a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt @@ -483,6 +483,16 @@ class DisplayRepositoryTest : SysuiTestCase() { assertThat(values.toIdSets()).containsExactly(setOf(0)) } + @Test + fun displayIdToId() = + testScope.runTest { + setDisplays(0, 1) + + assertThat(displayRepository.getDisplay(0)?.displayId).isEqualTo(0) + assertThat(displayRepository.getDisplay(1)?.displayId).isEqualTo(1) + assertThat(displayRepository.getDisplay(2)).isNull() + } + private fun Iterable<Display>.ids(): List<Int> = map { it.displayId } private fun Iterable<Set<Display>>.toIdSets(): List<Set<Int>> = map { it.ids().toSet() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt index 7dd717470153..a3314e8900ce 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt @@ -185,7 +185,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { dreamsComplicationComponent, dreamOverlayComponent, complicationComponent, - ambientTouchComponent + ambientTouchComponent, ) } @@ -194,7 +194,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { dreamsComplicationComponent, dreamOverlayComponent, complicationComponent, - ambientTouchComponent + ambientTouchComponent, ) } } @@ -204,7 +204,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { com.android.systemui.dreams.complication.dagger.ComplicationComponent.Factory, dreamOverlayComponentFactory: DreamOverlayComponent.Factory, complicationComponentFactory: ComplicationComponent.Factory, - ambientTouchComponentFactory: AmbientTouchComponent.Factory + ambientTouchComponentFactory: AmbientTouchComponent.Factory, ): EnvironmentComponents { val dreamOverlayComponent = mock<DreamOverlayComponent>() whenever(dreamOverlayComponent.getDreamOverlayContainerViewController()) @@ -241,7 +241,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { dreamComplicationComponent, dreamOverlayComponent, complicationComponent, - ambientTouchComponent + ambientTouchComponent, ) } @@ -259,7 +259,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamComplicationComponentFactory, mDreamOverlayComponentFactory, mComplicationComponentFactory, - mAmbientTouchComponentFactory + mAmbientTouchComponentFactory, ) whenever(mDreamOverlayContainerViewController.containerView) @@ -271,7 +271,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { ViewCaptureAwareWindowManager( mWindowManager, mLazyViewCapture, - isViewCaptureEnabled = false + isViewCaptureEnabled = false, ) mService = DreamOverlayService( @@ -295,7 +295,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallbackController, kosmos.keyguardInteractor, gestureInteractor, - WINDOW_NAME + WINDOW_NAME, ) } @@ -323,7 +323,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() verify(mUiEventLogger).log(DreamOverlayService.DreamOverlayEvent.DREAM_OVERLAY_ENTER_START) @@ -341,7 +341,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() verify(mWindowManager).addView(any(), any()) @@ -361,7 +361,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() verify(mWindowManager).addView(any(), any()) @@ -384,7 +384,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() verify(mDreamOverlayContainerViewController).init() @@ -403,7 +403,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() verify(mDreamOverlayContainerViewParent).removeView(mDreamOverlayContainerView) @@ -419,7 +419,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - true /*shouldShowComplication*/ + true, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() assertThat(mService.shouldShowComplications()).isTrue() @@ -435,7 +435,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - true /*shouldShowComplication*/ + true, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() @@ -448,7 +448,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - true /*shouldShowComplication*/ + true, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() @@ -476,7 +476,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, LOW_LIGHT_COMPONENT.flattenToString(), false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() assertThat(mService.dreamComponent).isEqualTo(LOW_LIGHT_COMPONENT) @@ -493,7 +493,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, HOME_CONTROL_PANEL_DREAM_COMPONENT.flattenToString(), false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() assertThat(mService.dreamComponent).isEqualTo(HOME_CONTROL_PANEL_DREAM_COMPONENT) @@ -510,7 +510,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, LOW_LIGHT_COMPONENT.flattenToString(), false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() @@ -545,7 +545,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) // Immediately end the dream. client.endDream() @@ -577,7 +577,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() @@ -597,7 +597,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, LOW_LIGHT_COMPONENT.flattenToString(), false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() @@ -649,7 +649,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() verify(mWindowManager, Mockito.never()).addView(any(), any()) @@ -673,7 +673,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() @@ -694,7 +694,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - true /*shouldShowComplication*/ + true, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() @@ -724,7 +724,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - true /*shouldShowComplication*/ + true, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() mService.onWakeUp() @@ -748,7 +748,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() val paramsCaptor = ArgumentCaptor.forClass(WindowManager.LayoutParams::class.java) @@ -774,7 +774,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() @@ -800,7 +800,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) // Set communal available, verify that overlay callback is informed. kosmos.setCommunalAvailable(true) @@ -829,7 +829,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - true /*shouldShowComplication*/ + true, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() @@ -850,7 +850,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - true /*shouldShowComplication*/ + true, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() @@ -870,7 +870,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - true /*shouldShowComplication*/ + true, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() @@ -894,14 +894,14 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() assertThat(lifecycleRegistry.mLifecycles) .containsExactly( Lifecycle.State.CREATED, Lifecycle.State.STARTED, - Lifecycle.State.RESUMED + Lifecycle.State.RESUMED, ) } @@ -925,7 +925,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) testScope.runCurrent() mMainExecutor.runAllReady() @@ -942,7 +942,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() mService.onDestroy() @@ -952,7 +952,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { Lifecycle.State.CREATED, Lifecycle.State.STARTED, Lifecycle.State.RESUMED, - Lifecycle.State.DESTROYED + Lifecycle.State.DESTROYED, ) } @@ -966,7 +966,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() assertThat(lifecycleRegistry.currentState).isEqualTo(Lifecycle.State.RESUMED) @@ -998,7 +998,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() assertThat(lifecycleRegistry.currentState).isEqualTo(Lifecycle.State.RESUMED) @@ -1030,7 +1030,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() assertThat(lifecycleRegistry.currentState).isEqualTo(Lifecycle.State.RESUMED) @@ -1066,7 +1066,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() assertThat(lifecycleRegistry.currentState).isEqualTo(Lifecycle.State.RESUMED) @@ -1101,7 +1101,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() @@ -1130,7 +1130,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, true /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() @@ -1148,7 +1148,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() @@ -1181,7 +1181,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() @@ -1214,7 +1214,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamComplicationComponentFactory, mDreamOverlayComponentFactory, mComplicationComponentFactory, - mAmbientTouchComponentFactory + mAmbientTouchComponentFactory, ) mService.onEndDream() @@ -1223,7 +1223,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamComplicationComponentFactory, mDreamOverlayComponentFactory, mComplicationComponentFactory, - mAmbientTouchComponentFactory + mAmbientTouchComponentFactory, ) client.startDream( @@ -1231,7 +1231,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mDreamOverlayCallback, DREAM_COMPONENT, false /*isPreview*/, - false /*shouldShowComplication*/ + false, /*shouldShowComplication*/ ) mMainExecutor.runAllReady() environmentComponents.verifyNoMoreInteractions() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadStatsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadStatsInteractorTest.kt index 98e09474d5f2..98e09474d5f2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadStatsInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadStatsInteractorTest.kt diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt index 6e381caf5124..0b944f04a6a2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt @@ -32,6 +32,7 @@ import com.android.systemui.keyguard.domain.interactor.keyguardBlueprintInteract import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor import com.android.systemui.keyguard.domain.interactor.keyguardSmartspaceInteractor import com.android.systemui.keyguard.shared.model.ClockSize +import com.android.systemui.keyguard.ui.viewmodel.aodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardSmartspaceViewModel @@ -120,6 +121,7 @@ class ClockSectionTest : SysuiTestCase() { keyguardSmartspaceViewModel, { keyguardBlueprintInteractor }, keyguardRootViewModel, + aodBurnInViewModel, ) } } @@ -313,7 +315,7 @@ class ClockSectionTest : SysuiTestCase() { referencedIds.contentEquals( intArrayOf( com.android.systemui.shared.R.id.bc_smartspace_view, - R.id.aod_notification_icon_container + R.id.aod_notification_icon_container, ) ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/HydratorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/HydratorTest.kt index ec6045ca0a68..b0e93fbecbb9 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/HydratorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/HydratorTest.kt @@ -59,11 +59,11 @@ class HydratorTest : SysuiTestCase() { Column { Text( "upstreamStateFlow=${viewModel.stateBackedByStateFlow}", - Modifier.testTag("upstreamStateFlow") + Modifier.testTag("upstreamStateFlow"), ) Text( "upstreamFlow=${viewModel.stateBackedByFlow}", - Modifier.testTag("upstreamFlow") + Modifier.testTag("upstreamFlow"), ) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt index 414974cc2941..414974cc2941 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt 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 6423d25cb88a..8d060e936cd9 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 @@ -60,13 +60,13 @@ class DragAndDropTest : SysuiTestCase() { onSetTiles: (List<TileSpec>) -> Unit, ) { DefaultEditTileGrid( - currentListState = listState, + listState = listState, otherTiles = listOf(), columns = 4, modifier = Modifier.fillMaxSize(), onRemoveTile = {}, onSetTiles = onSetTiles, - onResize = {}, + 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 index 682ed92cc593..ee1c0e99d6ac 100644 --- 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 @@ -25,7 +25,11 @@ 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.performClick import androidx.compose.ui.test.performCustomAccessibilityActionWithLabel +import androidx.compose.ui.test.performTouchInput +import androidx.compose.ui.test.swipeLeft +import androidx.compose.ui.test.swipeRight import androidx.compose.ui.text.AnnotatedString import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -43,15 +47,19 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +@OptIn(ExperimentalTestApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class ResizingTest : SysuiTestCase() { @get:Rule val composeRule = createComposeRule() @Composable - private fun EditTileGridUnderTest(listState: EditTileListState, onResize: (TileSpec) -> Unit) { + private fun EditTileGridUnderTest( + listState: EditTileListState, + onResize: (TileSpec, Boolean) -> Unit, + ) { DefaultEditTileGrid( - currentListState = listState, + listState = listState, otherTiles = listOf(), columns = 4, modifier = Modifier.fillMaxSize(), @@ -61,22 +69,12 @@ class ResizingTest : SysuiTestCase() { ) } - @OptIn(ExperimentalTestApi::class) @Test - fun resizedIcon_shouldBeLarge() { + fun toggleIconTile_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 - } - } - } + EditTileGridUnderTest(listState) { spec, toIcon -> tiles = tiles.resize(spec, toIcon) } } composeRule.waitForIdle() @@ -87,35 +85,74 @@ class ResizingTest : SysuiTestCase() { assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(2) } - @OptIn(ExperimentalTestApi::class) + @Test + fun toggleLargeTile_shouldBeIcon() { + var tiles by mutableStateOf(TestEditTiles) + val listState = EditTileListState(tiles, 4) + composeRule.setContent { + EditTileGridUnderTest(listState) { spec, toIcon -> tiles = tiles.resize(spec, toIcon) } + } + composeRule.waitForIdle() + + composeRule + .onNodeWithContentDescription("tileD_large") + .performCustomAccessibilityActionWithLabel("Toggle size") + + assertThat(tiles.find { it.tile.tileSpec.spec == "tileD_large" }?.width).isEqualTo(1) + } + @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 - } - } + EditTileGridUnderTest(listState) { spec, toIcon -> tiles = tiles.resize(spec, toIcon) } + } + composeRule.waitForIdle() + + composeRule + .onNodeWithContentDescription("tileA") + .performClick() // Select + .performTouchInput { // Resize down + swipeRight() } + composeRule.waitForIdle() + + assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(1) + } + + @Test + fun resizedIcon_shouldBeLarge() { + var tiles by mutableStateOf(TestEditTiles) + val listState = EditTileListState(tiles, 4) + composeRule.setContent { + EditTileGridUnderTest(listState) { spec, toIcon -> tiles = tiles.resize(spec, toIcon) } } composeRule.waitForIdle() composeRule .onNodeWithContentDescription("tileD_large") - .performCustomAccessibilityActionWithLabel("Toggle size") + .performClick() // Select + .performTouchInput { // Resize down + swipeLeft() + } + composeRule.waitForIdle() 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 List<SizedTile<EditTileViewModel>>.resize( + spec: TileSpec, + toIcon: Boolean, + ): List<SizedTile<EditTileViewModel>> { + return map { + if (it.tile.tileSpec == spec) { + SizedTileImpl(it.tile, width = if (toIcon) 1 else 2) + } else { + it + } + } } private fun createEditTile(tileSpec: String): SizedTile<EditTileViewModel> { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt index 62b6391ca54c..62b6391ca54c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt index 98260d88f389..41e2467f798b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt @@ -24,6 +24,7 @@ import android.testing.TestableLooper.RunWithLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.log.LogBuffer import com.android.systemui.settings.DisplayTracker import com.android.systemui.settings.UserTracker import com.android.systemui.util.concurrency.FakeExecutor @@ -51,6 +52,7 @@ class BrightnessControllerTest : SysuiTestCase() { @Mock private lateinit var displayTracker: DisplayTracker @Mock private lateinit var displayManager: DisplayManager @Mock private lateinit var iVrManager: IVrManager + @Mock private lateinit var logger: LogBuffer private lateinit var testableLooper: TestableLooper @@ -69,10 +71,11 @@ class BrightnessControllerTest : SysuiTestCase() { displayTracker, displayManager, secureSettings, + logger, iVrManager, executor, mock(), - Handler(testableLooper.looper) + Handler(testableLooper.looper), ) } 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 b4a0f23be9b1..859f84edda39 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt @@ -76,6 +76,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any +import org.mockito.kotlin.clearInvocations import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.never @@ -717,6 +718,15 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { } } + @Test + fun disposeView_destroysTouchMonitor() { + clearInvocations(touchMonitor) + + underTest.disposeView() + + verify(touchMonitor).destroy() + } + private fun initAndAttachContainerView() { val mockInsets = mock<WindowInsets> { diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index 4bd0c757543b..a6afd0e499f4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -453,6 +453,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mUiEventLogger, () -> mKosmos.getInteractionJankMonitor(), mJavaAdapter, + () -> mKeyguardInteractor, () -> mKeyguardTransitionInteractor, () -> mShadeInteractor, () -> mKosmos.getDeviceUnlockedInteractor(), @@ -611,6 +612,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { new UiEventLoggerFake(), () -> mKosmos.getInteractionJankMonitor(), mJavaAdapter, + () -> mKeyguardInteractor, () -> mKeyguardTransitionInteractor, () -> mShadeInteractor, () -> mKosmos.getDeviceUnlockedInteractor(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java index 7ddf7a31ad49..93ba8e1317fa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java @@ -35,7 +35,8 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.Plugin; import com.android.systemui.plugins.PluginLifecycleManager; import com.android.systemui.plugins.PluginListener; -import com.android.systemui.plugins.annotations.ProvidesInterface; +import com.android.systemui.plugins.PluginWrapper; +import com.android.systemui.plugins.TestPlugin; import com.android.systemui.plugins.annotations.Requires; import org.junit.Before; @@ -60,7 +61,7 @@ public class PluginInstanceTest extends SysuiTestCase { private FakeListener mPluginListener; private VersionInfo mVersionInfo; - private VersionInfo.InvalidVersionException mVersionException; + private boolean mVersionCheckResult = true; private PluginInstance.VersionChecker mVersionChecker; private RefCounter mCounter; @@ -83,14 +84,16 @@ public class PluginInstanceTest extends SysuiTestCase { mVersionInfo = new VersionInfo(); mVersionChecker = new PluginInstance.VersionChecker() { @Override - public <T extends Plugin> VersionInfo checkVersion( + public <T extends Plugin> boolean checkVersion( Class<T> instanceClass, Class<T> pluginClass, Plugin plugin ) { - if (mVersionException != null) { - throw mVersionException; - } + return mVersionCheckResult; + } + + @Override + public <T extends Plugin> VersionInfo getVersionInfo(Class<T> instanceClass) { return mVersionInfo; } }; @@ -117,21 +120,29 @@ public class PluginInstanceTest extends SysuiTestCase { } @Test - public void testCorrectVersion() { - assertNotNull(mPluginInstance); + public void testCorrectVersion_onCreateBuildsPlugin() { + mVersionCheckResult = true; + assertFalse(mPluginInstance.hasError()); + + mPluginInstance.onCreate(); + assertFalse(mPluginInstance.hasError()); + assertNotNull(mPluginInstance.getPlugin()); } - @Test(expected = VersionInfo.InvalidVersionException.class) - public void testIncorrectVersion() throws Exception { + @Test + public void testIncorrectVersion_destroysPluginInstance() throws Exception { ComponentName wrongVersionTestPluginComponentName = new ComponentName(PRIVILEGED_PACKAGE, TestPlugin.class.getName()); - mVersionException = new VersionInfo.InvalidVersionException("test", true); + mVersionCheckResult = false; + assertFalse(mPluginInstance.hasError()); mPluginInstanceFactory.create( mContext, mAppInfo, wrongVersionTestPluginComponentName, TestPlugin.class, mPluginListener); mPluginInstance.onCreate(); + assertTrue(mPluginInstance.hasError()); + assertNull(mPluginInstance.getPlugin()); } @Test @@ -139,7 +150,7 @@ public class PluginInstanceTest extends SysuiTestCase { mPluginInstance.onCreate(); assertEquals(1, mPluginListener.mAttachedCount); assertEquals(1, mPluginListener.mLoadCount); - assertEquals(mPlugin.get(), mPluginInstance.getPlugin()); + assertEquals(mPlugin.get(), unwrap(mPluginInstance.getPlugin())); assertInstances(1, 1); } @@ -176,6 +187,17 @@ public class PluginInstanceTest extends SysuiTestCase { } @Test + public void testLinkageError_caughtAndPluginDestroyed() { + mPluginInstance.onCreate(); + assertFalse(mPluginInstance.hasError()); + + Object result = mPluginInstance.getPlugin().methodThrowsError(); + assertNotNull(result); // Wrapper function should return non-null; + assertTrue(mPluginInstance.hasError()); + assertNull(mPluginInstance.getPlugin()); + } + + @Test public void testLoadUnloadSimultaneous_HoldsUnload() throws Throwable { final Semaphore loadLock = new Semaphore(1); final Semaphore unloadLock = new Semaphore(1); @@ -232,6 +254,13 @@ public class PluginInstanceTest extends SysuiTestCase { assertNull(mPluginInstance.getPlugin()); } + private static <T> T unwrap(T plugin) { + if (plugin instanceof PluginWrapper) { + return ((PluginWrapper<T>) plugin).getPlugin(); + } + return plugin; + } + private boolean getLock(Semaphore lock, long millis) { try { return lock.tryAcquire(millis, TimeUnit.MILLISECONDS); @@ -243,14 +272,6 @@ public class PluginInstanceTest extends SysuiTestCase { } } - // This target class doesn't matter, it just needs to have a Requires to hit the flow where - // the mock version info is called. - @ProvidesInterface(action = TestPlugin.ACTION, version = TestPlugin.VERSION) - public interface TestPlugin extends Plugin { - int VERSION = 1; - String ACTION = "testAction"; - } - private void assertInstances(int allocated, int created) { // If there are more than the expected number of allocated instances, then we run the // garbage collector to finalize and deallocate any outstanding non-referenced instances. @@ -300,6 +321,11 @@ public class PluginInstanceTest extends SysuiTestCase { public void onDestroy() { mCounter.mCreatedInstances.getAndDecrement(); } + + @Override + public Object methodThrowsError() { + throw new LinkageError(); + } } public class FakeListener implements PluginListener<TestPlugin> { @@ -337,7 +363,7 @@ public class PluginInstanceTest extends SysuiTestCase { mLoadCount++; TestPlugin expectedPlugin = PluginInstanceTest.this.mPlugin.get(); if (expectedPlugin != null) { - assertEquals(expectedPlugin, plugin); + assertEquals(expectedPlugin, unwrap(plugin)); } Context expectedContext = PluginInstanceTest.this.mPluginContext.get(); if (expectedContext != null) { @@ -357,7 +383,7 @@ public class PluginInstanceTest extends SysuiTestCase { mUnloadCount++; TestPlugin expectedPlugin = PluginInstanceTest.this.mPlugin.get(); if (expectedPlugin != null) { - assertEquals(expectedPlugin, plugin); + assertEquals(expectedPlugin, unwrap(plugin)); } assertEquals(PluginInstanceTest.this.mPluginInstance, manager); if (mOnUnload != null) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/statusbar/OWNERS index 1c52b8d25347..48a20ddf8ca3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/OWNERS +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/OWNERS @@ -1,3 +1,4 @@ set noparent include /packages/SystemUI/src/com/android/systemui/statusbar/OWNERS +include /packages/SystemUI/TEST_OWNERS diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt new file mode 100644 index 000000000000..9142972eabdd --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt @@ -0,0 +1,92 @@ +/* + * 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.core + +import android.app.FragmentManager +import android.app.FragmentTransaction +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.Flags +import com.android.systemui.SysuiTestCase +import com.android.systemui.fragments.FragmentHostManager +import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment +import com.android.systemui.statusbar.window.StatusBarWindowController +import com.google.common.truth.Truth.assertThat +import kotlin.test.Test +import org.junit.Assert.assertThrows +import org.junit.Before +import org.junit.runner.RunWith +import org.mockito.Mockito.mock +import org.mockito.kotlin.any +import org.mockito.kotlin.whenever + +@SmallTest +@RunWith(AndroidJUnit4::class) +class StatusBarInitializerTest : SysuiTestCase() { + val windowController = mock(StatusBarWindowController::class.java) + + @Before + fun setup() { + // TODO(b/364360986) this will go away once the fragment is deprecated. Hence, there is no + // need right now for moving this to kosmos + val transaction = mock(FragmentTransaction::class.java) + val fragmentManager = mock(FragmentManager::class.java) + val fragmentHostManager = mock(FragmentHostManager::class.java) + whenever(fragmentHostManager.addTagListener(any(), any())).thenReturn(fragmentHostManager) + whenever(fragmentHostManager.fragmentManager).thenReturn(fragmentManager) + whenever(fragmentManager.beginTransaction()).thenReturn(transaction) + whenever(transaction.replace(any(), any(), any())).thenReturn(transaction) + + whenever(windowController.fragmentHostManager).thenReturn(fragmentHostManager) + } + + val underTest = + StatusBarInitializerImpl( + windowController, + { mock(CollapsedStatusBarFragment::class.java) }, + setOf(), + ) + + @Test + @EnableFlags(Flags.FLAG_STATUS_BAR_SIMPLE_FRAGMENT) + fun simpleFragment_startsFromCoreStartable() { + underTest.start() + assertThat(underTest.initialized).isTrue() + } + + @Test + @EnableFlags(Flags.FLAG_STATUS_BAR_SIMPLE_FRAGMENT) + fun simpleFragment_throwsIfInitializeIsCalled() { + assertThrows(IllegalStateException::class.java) { underTest.initializeStatusBar() } + } + + @Test + @DisableFlags(Flags.FLAG_STATUS_BAR_SIMPLE_FRAGMENT) + fun flagOff_doesNotInitializeViaCoreStartable() { + underTest.start() + assertThat(underTest.initialized).isFalse() + } + + @Test + @DisableFlags(Flags.FLAG_STATUS_BAR_SIMPLE_FRAGMENT) + fun flagOff_doesNotThrowIfInitializeIsCalled() { + underTest.initializeStatusBar() + assertThat(underTest.initialized).isTrue() + } +} 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 d2dfc9257e7e..907c68440b55 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 @@ package com.android.systemui.statusbar.disableflags.data.repository 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 @@ class DisableFlagsRepositoryTest : SysuiTestCase() { @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 @@ class DisableFlagsRepositoryTest : SysuiTestCase() { 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 @@ class DisableFlagsRepositoryTest : SysuiTestCase() { 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 @@ class DisableFlagsRepositoryTest : SysuiTestCase() { 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/notification/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/OWNERS index 7f5384d1dbf3..1da700770d4e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/OWNERS +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/OWNERS @@ -1,3 +1,4 @@ set noparent -include /packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
\ No newline at end of file +include /packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS +include /packages/SystemUI/TEST_OWNERS diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt index cea8857c01bf..cea8857c01bf 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractorTest.kt diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt index 1f4e80e48bb7..740abf359e92 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt @@ -21,7 +21,6 @@ import android.platform.test.annotations.DisableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR -import com.android.systemui.Flags.FLAG_NEW_AOD_TRANSITION import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.Flags @@ -85,7 +84,6 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() { lastWakeReason = WakeSleepReason.OTHER, lastSleepReason = WakeSleepReason.OTHER, ) - mSetFlagsRule.enableFlags(FLAG_NEW_AOD_TRANSITION) } @Test @@ -97,14 +95,10 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() { lastSleepReason = WakeSleepReason.OTHER, ) keyguardTransitionRepository.sendTransitionStep( - TransitionStep( - transitionState = TransitionState.STARTED, - ) + TransitionStep(transitionState = TransitionState.STARTED) ) keyguardRepository.setDozeTransitionModel( - DozeTransitionModel( - to = DozeStateModel.DOZE_AOD, - ) + DozeTransitionModel(to = DozeStateModel.DOZE_AOD) ) val animationsEnabled by collectLastValue(underTest.areContainerChangesAnimated) runCurrent() @@ -120,14 +114,10 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() { lastSleepReason = WakeSleepReason.OTHER, ) keyguardTransitionRepository.sendTransitionStep( - TransitionStep( - transitionState = TransitionState.STARTED, - ) + TransitionStep(transitionState = TransitionState.STARTED) ) keyguardRepository.setDozeTransitionModel( - DozeTransitionModel( - to = DozeStateModel.DOZE_PULSING, - ) + DozeTransitionModel(to = DozeStateModel.DOZE_PULSING) ) val animationsEnabled by collectLastValue(underTest.areContainerChangesAnimated) runCurrent() @@ -186,9 +176,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() { lastSleepReason = WakeSleepReason.OTHER, ) keyguardTransitionRepository.sendTransitionStep( - TransitionStep( - transitionState = TransitionState.STARTED, - ) + TransitionStep(transitionState = TransitionState.STARTED) ) val animationsEnabled by collectLastValue(underTest.areContainerChangesAnimated) runCurrent() @@ -200,9 +188,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() { fun animationsEnabled_isTrue_whenKeyguardIsShowing() = testScope.runTest { keyguardTransitionRepository.sendTransitionStep( - TransitionStep( - transitionState = TransitionState.STARTED, - ) + TransitionStep(transitionState = TransitionState.STARTED) ) val animationsEnabled by collectLastValue(underTest.areContainerChangesAnimated) runCurrent() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index a06f4d2d2d80..bb9f12b4de31 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.stack; import static android.view.View.GONE; import static android.view.WindowInsets.Type.ime; -import static com.android.systemui.Flags.FLAG_NEW_AOD_TRANSITION; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.RUBBER_BAND_FACTOR_NORMAL; @@ -83,13 +82,13 @@ import com.android.systemui.res.R; import com.android.systemui.shade.QSHeaderBoundsProvider; import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.transition.LargeScreenShadeInterpolator; -import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; +import com.android.systemui.statusbar.notification.emptyshade.ui.view.EmptyShadeView; import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor; import com.android.systemui.statusbar.notification.footer.ui.view.FooterView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -174,12 +173,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mFeatureFlags.set(Flags.NSSL_DEBUG_REMOVE_ANIMATION, false); mFeatureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false); - // Register the feature flags we use - // TODO: Ideally we wouldn't need to set these unless a test actually reads them, - // and then we would test both configurations, but currently they are all read - // in the constructor. - mSetFlagsRule.enableFlags(FLAG_NEW_AOD_TRANSITION); - // Inject dependencies before initializing the layout mDependency.injectTestDependency(FeatureFlags.class, mFeatureFlags); mDependency.injectTestDependency(SysuiStatusBarStateController.class, mBarState); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt index 3e8bf4792f02..1ef400710102 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt @@ -18,11 +18,11 @@ import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.res.R import com.android.systemui.shade.transition.LargeScreenShadeInterpolator -import com.android.systemui.statusbar.EmptyShadeView import com.android.systemui.statusbar.NotificationShelf import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.notification.RoundableState import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.emptyshade.ui.view.EmptyShadeView import com.android.systemui.statusbar.notification.footer.ui.view.FooterView import com.android.systemui.statusbar.notification.footer.ui.view.FooterView.FooterViewState import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow @@ -79,7 +79,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* bypassController */ { false }, mStatusBarKeyguardViewManager, largeScreenShadeInterpolator, - avalancheController + avalancheController, ) private val testableResources = mContext.getOrCreateTestableResources() @@ -240,7 +240,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { headsUpTop = headsUpTop, stackTop = stackTop, collapsedHeight = collapsedHeight, - intrinsicHeight = intrinsicHeight + intrinsicHeight = intrinsicHeight, ) // When @@ -269,7 +269,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { headsUpTop = headsUpTop, stackTop = stackTop, collapsedHeight = collapsedHeight, - intrinsicHeight = intrinsicHeight + intrinsicHeight = intrinsicHeight, ) // When @@ -548,7 +548,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { whenever(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit).thenReturn(false) resetViewStates_expansionChanging_notificationAlphaUpdated( expansionFraction = 0.25f, - expectedAlpha = 0.0f + expectedAlpha = 0.0f, ) } @@ -558,7 +558,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { whenever(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit).thenReturn(true) resetViewStates_expansionChanging_notificationAlphaUpdated( expansionFraction = 0.85f, - expectedAlpha = 0.0f + expectedAlpha = 0.0f, ) } @@ -568,7 +568,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { whenever(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit).thenReturn(false) resetViewStates_expansionChanging_notificationAlphaUpdated( expansionFraction = 0.6f, - expectedAlpha = getContentAlpha(0.6f) + expectedAlpha = getContentAlpha(0.6f), ) } @@ -785,7 +785,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { val gap = stackScrollAlgorithm.getGapForLocation( /* fractionToShade= */ 0f, - /* onKeyguard= */ true + /* onKeyguard= */ true, ) assertThat(gap).isEqualTo(smallGap) } @@ -795,7 +795,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { val gap = stackScrollAlgorithm.getGapForLocation( /* fractionToShade= */ 0.5f, - /* onKeyguard= */ true + /* onKeyguard= */ true, ) assertThat(gap).isEqualTo(smallGap * 0.5f + bigGap * 0.5f) } @@ -805,7 +805,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { val gap = stackScrollAlgorithm.getGapForLocation( /* fractionToShade= */ 0f, - /* onKeyguard= */ false + /* onKeyguard= */ false, ) assertThat(gap).isEqualTo(bigGap) } @@ -869,7 +869,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* mustStayOnScreen= */ true, /* isViewEndVisible= */ true, /* viewEnd= */ 0f, - /* maxHunY= */ 10f + /* maxHunY= */ 10f, ) assertTrue(expandableViewState.headsUpIsVisible) @@ -886,7 +886,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* mustStayOnScreen= */ true, /* isViewEndVisible= */ true, /* viewEnd= */ 10f, - /* maxHunY= */ 0f + /* maxHunY= */ 0f, ) assertFalse(expandableViewState.headsUpIsVisible) @@ -903,7 +903,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* mustStayOnScreen= */ true, /* isViewEndVisible= */ true, /* viewEnd= */ 10f, - /* maxHunY= */ 1f + /* maxHunY= */ 1f, ) assertTrue(expandableViewState.headsUpIsVisible) @@ -920,7 +920,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* mustStayOnScreen= */ false, /* isViewEndVisible= */ true, /* viewEnd= */ 10f, - /* maxHunY= */ 1f + /* maxHunY= */ 1f, ) assertTrue(expandableViewState.headsUpIsVisible) @@ -937,7 +937,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* mustStayOnScreen= */ true, /* isViewEndVisible= */ false, /* viewEnd= */ 10f, - /* maxHunY= */ 1f + /* maxHunY= */ 1f, ) assertTrue(expandableViewState.headsUpIsVisible) @@ -951,7 +951,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { stackScrollAlgorithm.clampHunToTop( /* headsUpTop= */ 10f, /* collapsedHeight= */ 1f, - expandableViewState + expandableViewState, ) // qqs (10 + 0) < viewY (50) @@ -966,7 +966,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { stackScrollAlgorithm.clampHunToTop( /* headsUpTop= */ 10f, /* collapsedHeight= */ 1f, - expandableViewState + expandableViewState, ) // qqs (10 + 0) > viewY (-10) @@ -982,7 +982,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { stackScrollAlgorithm.clampHunToTop( /* headsUpTop= */ 10f, /* collapsedHeight= */ 10f, - expandableViewState + expandableViewState, ) // newTranslation = max(10, -100) = 10 @@ -1000,7 +1000,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { stackScrollAlgorithm.clampHunToTop( /* headsUpTop= */ 10f, /* collapsedHeight= */ 10f, - expandableViewState + expandableViewState, ) // newTranslation = max(10, 5) = 10 @@ -1016,7 +1016,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* hostViewHeight= */ 100f, /* stackY= */ 110f, /* viewMaxHeight= */ 20f, - /* originalCornerRoundness= */ 0f + /* originalCornerRoundness= */ 0f, ) assertEquals(1f, currentRoundness) } @@ -1028,7 +1028,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* hostViewHeight= */ 100f, /* stackY= */ 90f, /* viewMaxHeight= */ 20f, - /* originalCornerRoundness= */ 0f + /* originalCornerRoundness= */ 0f, ) assertEquals(0.5f, currentRoundness) } @@ -1040,7 +1040,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* hostViewHeight= */ 100f, /* stackY= */ 0f, /* viewMaxHeight= */ 20f, - /* originalCornerRoundness= */ 0f + /* originalCornerRoundness= */ 0f, ) assertEquals(0f, currentRoundness) } @@ -1052,7 +1052,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* hostViewHeight= */ 100f, /* stackY= */ 0f, /* viewMaxHeight= */ 20f, - /* originalCornerRoundness= */ 1f + /* originalCornerRoundness= */ 1f, ) assertEquals(1f, currentRoundness) } @@ -1076,7 +1076,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* childrenOnTop= */ 0.0f, /* StackScrollAlgorithmState= */ algorithmState, /* ambientState= */ ambientState, - /* shouldElevateHun= */ true + /* shouldElevateHun= */ true, ) // Then: full shadow would be applied @@ -1104,7 +1104,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* childrenOnTop= */ 0.0f, /* StackScrollAlgorithmState= */ algorithmState, /* ambientState= */ ambientState, - /* shouldElevateHun= */ true + /* shouldElevateHun= */ true, ) // Then: HUN should have shadow, but not as full size @@ -1137,7 +1137,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* childrenOnTop= */ 0.0f, /* StackScrollAlgorithmState= */ algorithmState, /* ambientState= */ ambientState, - /* shouldElevateHun= */ true + /* shouldElevateHun= */ true, ) // Then: HUN should not have shadow @@ -1166,7 +1166,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* childrenOnTop= */ 0.0f, /* StackScrollAlgorithmState= */ algorithmState, /* ambientState= */ ambientState, - /* shouldElevateHun= */ true + /* shouldElevateHun= */ true, ) // Then: HUN should have full shadow @@ -1196,7 +1196,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* childrenOnTop= */ 0.0f, /* StackScrollAlgorithmState= */ algorithmState, /* ambientState= */ ambientState, - /* shouldElevateHun= */ true + /* shouldElevateHun= */ true, ) // Then: HUN should have shadow, but not as full size @@ -1274,14 +1274,14 @@ class StackScrollAlgorithmTest : SysuiTestCase() { setExpansionFractionWithoutShelfDuringAodToLockScreen( ambientState, algorithmState, - fraction = 0.5f + fraction = 0.5f, ) stackScrollAlgorithm.resetViewStates(ambientState, 0) // Then: pulsingNotificationView should show at full height assertEquals( stackScrollAlgorithm.getMaxAllowedChildHeight(pulsingNotificationView), - pulsingNotificationView.viewState.height + pulsingNotificationView.viewState.height, ) // After: reset dozeAmount and expansionFraction @@ -1289,7 +1289,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { setExpansionFractionWithoutShelfDuringAodToLockScreen( ambientState, algorithmState, - fraction = 1f + fraction = 1f, ) } @@ -1302,7 +1302,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* headsUpIsVisible= */ false, /* showingPulsing= */ false, /* isOnKeyguard=*/ false, - /*headsUpOnKeyguard=*/ false + /*headsUpOnKeyguard=*/ false, ) ) .isFalse() @@ -1316,7 +1316,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* headsUpIsVisible= */ true, /* showingPulsing= */ false, /* isOnKeyguard=*/ false, - /*headsUpOnKeyguard=*/ false + /*headsUpOnKeyguard=*/ false, ) ) .isFalse() @@ -1330,7 +1330,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* headsUpIsVisible= */ false, /* showingPulsing= */ true, /* isOnKeyguard=*/ false, - /* headsUpOnKeyguard= */ false + /* headsUpOnKeyguard= */ false, ) ) .isFalse() @@ -1344,7 +1344,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* headsUpIsVisible= */ false, /* showingPulsing= */ false, /* isOnKeyguard=*/ true, - /* headsUpOnKeyguard= */ false + /* headsUpOnKeyguard= */ false, ) ) .isFalse() @@ -1358,7 +1358,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* headsUpIsVisible= */ false, /* showingPulsing= */ false, /* isOnKeyguard=*/ false, - /* headsUpOnKeyguard= */ false + /* headsUpOnKeyguard= */ false, ) ) .isTrue() @@ -1372,7 +1372,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { /* headsUpIsVisible= */ false, /* showingPulsing= */ false, /* isOnKeyguard=*/ true, - /* headsUpOnKeyguard= */ true + /* headsUpOnKeyguard= */ true, ) ) .isTrue() @@ -1408,7 +1408,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { private fun createHunViewMock( isShadeOpen: Boolean, fullyVisible: Boolean, - headerVisibleAmount: Float + headerVisibleAmount: Float, ) = mock<ExpandableNotificationRow>().apply { val childViewStateMock = createHunChildViewState(isShadeOpen, fullyVisible) @@ -1440,7 +1440,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { private fun setExpansionFractionWithoutShelfDuringAodToLockScreen( ambientState: AmbientState, algorithmState: StackScrollAlgorithm.StackScrollAlgorithmState, - fraction: Float + fraction: Float, ) { // showingShelf: false algorithmState.firstViewInShelf = null @@ -1476,7 +1476,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { private fun resetViewStates_hunsOverlapping_bottomHunClipped( topHun: ExpandableNotificationRow, - bottomHun: ExpandableNotificationRow + bottomHun: ExpandableNotificationRow, ) { val topHunHeight = mContext.resources.getDimensionPixelSize(R.dimen.notification_content_min_height) @@ -1524,7 +1524,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { headsUpBottom: Float = headsUpTop + intrinsicHeight, // assume all the space available stackTop: Float, stackCutoff: Float = 2000f, - fullStackHeight: Float = 3000f + fullStackHeight: Float = 3000f, ) { ambientState.headsUpTop = headsUpTop ambientState.headsUpBottom = headsUpBottom 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 135fab877d57..63a560ffd2c1 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 android.view.Display.DEFAULT_DISPLAY; 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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @Test + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void testDisableNone() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); @@ -167,6 +169,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @Test + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void testDisableSystemInfo_systemAnimationIdle_doesHide() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); @@ -184,6 +187,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { 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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @Test + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void testDisableNotifications() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); @@ -285,6 +292,25 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @Test @DisableSceneContainer + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void disable_shadeOpenButNotShouldHide_everythingShown() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); @@ -338,6 +384,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { /** 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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @Test + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void disable_notTransitioningToOccluded_everythingShown() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); @@ -380,6 +428,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @Test @DisableSceneContainer + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void disable_isTransitioningToOccluded_everythingHidden() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); @@ -395,6 +444,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @Test @DisableSceneContainer + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void disable_wasTransitioningToOccluded_transitionFinished_everythingShown() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); @@ -425,7 +475,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @Test @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS) + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void noOngoingActivity_chipHidden() { resumeAndGetFragment(); @@ -568,6 +619,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @Test @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS) + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void hasPrimaryOngoingActivity_primaryChipDisplayedAndNotificationIconsHidden() { resumeAndGetFragment(); @@ -581,8 +633,36 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @Test @EnableSceneContainer + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void isHomeStatusBarAllowedByScene_false_everythingHidden() { resumeAndGetFragment(); @@ -861,6 +949,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @Test @EnableSceneContainer + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void isHomeStatusBarAllowedByScene_true_everythingShown() { resumeAndGetFragment(); @@ -874,6 +963,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @Test @EnableSceneContainer + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void disable_isHomeStatusBarAllowedBySceneFalse_disableValuesIgnored() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); @@ -891,6 +981,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @Test @EnableSceneContainer + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void disable_isHomeStatusBarAllowedBySceneTrue_disableValuesUsed() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); @@ -908,6 +999,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @Test @DisableSceneContainer + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void isHomeStatusBarAllowedByScene_sceneContainerDisabled_valueNotUsed() { resumeAndGetFragment(); @@ -921,6 +1013,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @Test + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void disable_isDozing_clockAndSystemInfoVisible() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); when(mStatusBarStateController.isDozing()).thenReturn(true); @@ -932,6 +1025,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @Test + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void disable_NotDozing_clockAndSystemInfoVisible() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); when(mStatusBarStateController.isDozing()).thenReturn(false); @@ -943,6 +1037,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @Test + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void disable_headsUpShouldBeVisibleTrue_clockDisabled() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(true); @@ -953,6 +1048,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @Test + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void disable_headsUpShouldBeVisibleFalse_clockNotDisabled() { CollapsedStatusBarFragment fragment = resumeAndGetFragment(); when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(false); @@ -1006,6 +1102,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @Test @DisableSceneContainer + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void testStatusBarIcons_hiddenThroughoutCameraLaunch() { final CollapsedStatusBarFragment fragment = resumeAndGetFragment(); @@ -1028,6 +1125,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @Test @DisableSceneContainer + @DisableFlags(FLAG_STATUS_BAR_SIMPLE_FRAGMENT) public void testStatusBarIcons_hiddenThroughoutLockscreenToDreamTransition() { final CollapsedStatusBarFragment fragment = resumeAndGetFragment(); @@ -1063,6 +1161,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { } @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 997c00cf49a4..c435d3d99680 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 @@ private const val INITIAL_ALPHA = 1f @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 @@ class MultiSourceMinAlphaControllerTest : SysuiTestCase() { 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 @@ class MultiSourceMinAlphaControllerTest : SysuiTestCase() { 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 @@ class MultiSourceMinAlphaControllerTest : SysuiTestCase() { 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/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt index 4fd830d0891e..a8bcfbcfc539 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt @@ -756,6 +756,27 @@ class MobileIconInteractorTest : SysuiTestCase() { assertThat(latest!!.level).isEqualTo(4) } + @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) + @Test + fun satBasedIcon_reportsLevelZeroWhenOutOfService() = + testScope.runTest { + val latest by collectLastValue(underTest.signalLevelIcon) + + // GIVEN a satellite connection + connectionRepository.isNonTerrestrial.value = true + // GIVEN this carrier has set INFLATE_SIGNAL_STRENGTH + connectionRepository.inflateSignalStrength.value = true + + connectionRepository.primaryLevel.value = 4 + assertThat(latest!!.level).isEqualTo(4) + + connectionRepository.isInService.value = false + connectionRepository.primaryLevel.value = 4 + + // THEN level reports 0, by policy + assertThat(latest!!.level).isEqualTo(0) + } + private fun createInteractor( overrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl() ) = 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 000000000000..5036e775211e --- /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 7ae6ea51b912..bd857807851c 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.log.assertLogsWtf 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 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() { 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 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() { 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 4834d367d4be..cc90c1167ef1 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 @@ class FakeCollapsedStatusBarViewModel : CollapsedStatusBarViewModel { override val isHomeStatusBarAllowedByScene = MutableStateFlow(false) - override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> = areNotificationLightsOut + override val isClockVisible = + MutableStateFlow( + CollapsedStatusBarViewModel.VisibilityModel( + visibility = View.GONE, + shouldAnimateChange = false, + ) + ) + + override val isNotificationIconContainerVisible = + MutableStateFlow( + CollapsedStatusBarViewModel.VisibilityModel( + visibility = View.GONE, + shouldAnimateChange = false, + ) + ) - fun setNotificationLightsOut(lightsOut: Boolean) { - areNotificationLightsOut.value = lightsOut - } + 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/StatusBarWindowStatePerDisplayRepositoryTest.kt index 38e04bb1d00f..0c27e58fd369 100644 --- 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/StatusBarWindowStatePerDisplayRepositoryTest.kt @@ -39,12 +39,16 @@ import org.mockito.kotlin.argumentCaptor @SmallTest @OptIn(ExperimentalCoroutinesApi::class) -class StatusBarWindowStateRepositoryTest : SysuiTestCase() { +class StatusBarWindowStatePerDisplayRepositoryTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val commandQueue = kosmos.commandQueue private val underTest = - StatusBarWindowStateRepository(commandQueue, DISPLAY_ID, testScope.backgroundScope) + StatusBarWindowStatePerDisplayRepositoryImpl( + DISPLAY_ID, + commandQueue, + testScope.backgroundScope, + ) private val callback: CommandQueue.Callbacks get() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreTest.kt new file mode 100644 index 000000000000..b6a3f367fe33 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreTest.kt @@ -0,0 +1,123 @@ +/* + * 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.WINDOW_STATE_HIDDEN +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.settings.displayTracker +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 kotlin.test.Test +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.mockito.Mockito.verify +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.reset + +@SmallTest +@OptIn(ExperimentalCoroutinesApi::class) +class StatusBarWindowStateRepositoryStoreTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val commandQueue = kosmos.commandQueue + private val defaultDisplayId = kosmos.displayTracker.defaultDisplayId + + private val underTest = kosmos.statusBarWindowStateRepositoryStore + + @Test + fun defaultDisplay_repoIsForDefaultDisplay() = + testScope.runTest { + val repo = underTest.defaultDisplay + val latest by collectLastValue(repo.windowState) + + testScope.runCurrent() + val callbackCaptor = argumentCaptor<CommandQueue.Callbacks>() + verify(commandQueue).addCallback(callbackCaptor.capture()) + val callback = callbackCaptor.firstValue + + // WHEN a default display callback is sent + callback.setWindowState(defaultDisplayId, WINDOW_STATUS_BAR, WINDOW_STATE_SHOWING) + + // THEN its value is used + assertThat(latest).isEqualTo(StatusBarWindowState.Showing) + + // WHEN a non-default display callback is sent + callback.setWindowState(defaultDisplayId + 1, WINDOW_STATUS_BAR, WINDOW_STATE_HIDDEN) + + // THEN its value is NOT used + assertThat(latest).isEqualTo(StatusBarWindowState.Showing) + } + + @Test + fun forDisplay_repoIsForSpecifiedDisplay() = + testScope.runTest { + // The repository store will always create a repository for the default display, which + // will always add a callback to commandQueue. Ignore that callback here. + testScope.runCurrent() + reset(commandQueue) + + val displayId = defaultDisplayId + 15 + val repo = underTest.forDisplay(displayId) + val latest by collectLastValue(repo.windowState) + + testScope.runCurrent() + val callbackCaptor = argumentCaptor<CommandQueue.Callbacks>() + verify(commandQueue).addCallback(callbackCaptor.capture()) + val callback = callbackCaptor.firstValue + + // WHEN a default display callback is sent + callback.setWindowState(defaultDisplayId, WINDOW_STATUS_BAR, WINDOW_STATE_SHOWING) + + // THEN its value is NOT used + assertThat(latest).isEqualTo(StatusBarWindowState.Hidden) + + // WHEN a callback for this display is sent + callback.setWindowState(displayId, WINDOW_STATUS_BAR, WINDOW_STATE_SHOWING) + + // THEN its value is used + assertThat(latest).isEqualTo(StatusBarWindowState.Showing) + } + + @Test + fun forDisplay_reusesRepoForSameDisplayId() = + testScope.runTest { + // The repository store will always create a repository for the default display, which + // will always add a callback to commandQueue. Ignore that callback here. + testScope.runCurrent() + reset(commandQueue) + + val displayId = defaultDisplayId + 15 + val firstRepo = underTest.forDisplay(displayId) + testScope.runCurrent() + val secondRepo = underTest.forDisplay(displayId) + testScope.runCurrent() + + assertThat(firstRepo).isEqualTo(secondRepo) + // Verify that we only added 1 CommandQueue.Callback because we only created 1 repo. + val callbackCaptor = argumentCaptor<CommandQueue.Callbacks>() + verify(commandQueue).addCallback(callbackCaptor.capture()) + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt index 59809e3d253f..79d58a1d4e40 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt @@ -19,19 +19,27 @@ package com.android.systemui.biometrics.ui.binder import android.content.applicationContext import android.view.layoutInflater import android.view.windowManager -import com.android.systemui.biometrics.domain.interactor.sideFpsOverlayInteractor -import com.android.systemui.biometrics.ui.viewmodel.sideFpsOverlayViewModel +import com.android.systemui.biometrics.domain.interactor.biometricStatusInteractor +import com.android.systemui.biometrics.domain.interactor.displayStateInteractor +import com.android.systemui.biometrics.domain.interactor.sideFpsSensorInteractor +import com.android.systemui.keyguard.domain.interactor.deviceEntrySideFpsOverlayInteractor +import com.android.systemui.keyguard.ui.viewmodel.sideFpsProgressBarViewModel import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.applicationCoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.sideFpsOverlayViewBinder by Fixture { SideFpsOverlayViewBinder( - applicationCoroutineScope, - applicationContext, + applicationScope = applicationCoroutineScope, + applicationContext = applicationContext, + { biometricStatusInteractor }, + { displayStateInteractor }, + { deviceEntrySideFpsOverlayInteractor }, { layoutInflater }, - { sideFpsOverlayInteractor }, - { sideFpsOverlayViewModel }, + { sideFpsProgressBarViewModel }, + { sideFpsSensorInteractor }, { windowManager } ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt index e10b2dd6497d..de038559fc38 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt @@ -27,9 +27,9 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi @OptIn(ExperimentalCoroutinesApi::class) val Kosmos.sideFpsOverlayViewModel by Fixture { SideFpsOverlayViewModel( - applicationContext, - deviceEntrySideFpsOverlayInteractor, - displayStateInteractor, - sideFpsSensorInteractor, + applicationContext = applicationContext, + deviceEntrySideFpsOverlayInteractor = deviceEntrySideFpsOverlayInteractor, + displayStateInteractor = displayStateInteractor, + sfpsSensorInteractor = sideFpsSensorInteractor, ) } 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 81242244b7a6..3d4136252ca4 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 @@ val Kosmos.widgetTrampolineInteractor: WidgetTrampolineInteractor by 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/data/repository/KeyguardBlueprintRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt index fb12897ead19..12d7c49194ff 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt @@ -24,6 +24,7 @@ import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBl import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection +import com.android.systemui.keyguard.ui.viewmodel.aodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardSmartspaceViewModel @@ -41,6 +42,7 @@ val Kosmos.keyguardClockSection: ClockSection by smartspaceViewModel = keyguardSmartspaceViewModel, blueprintInteractor = { keyguardBlueprintInteractor }, rootViewModel = keyguardRootViewModel, + aodBurnInViewModel = aodBurnInViewModel, ) } @@ -95,11 +97,7 @@ val Kosmos.keyguardBlueprintRepository by Kosmos.Fixture { spy( KeyguardBlueprintRepository( - blueprints = - setOf( - defaultKeyguardBlueprint, - splitShadeBlueprint, - ), + blueprints = setOf(defaultKeyguardBlueprint, splitShadeBlueprint), handler = fakeExecutorHandler, assert = mock(), ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorKosmos.kt index 64ae05131b5a..e6c98cd83b5e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorKosmos.kt @@ -16,6 +16,8 @@ package com.android.systemui.keyguard.domain.interactor +import android.service.dream.dreamManager +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.deviceentry.domain.interactor.deviceEntryInteractor @@ -39,10 +41,12 @@ var Kosmos.fromDreamingTransitionInteractor by mainDispatcher = testDispatcher, keyguardInteractor = keyguardInteractor, glanceableHubTransitions = glanceableHubTransitions, + communalInteractor = communalInteractor, communalSceneInteractor = communalSceneInteractor, communalSettingsInteractor = communalSettingsInteractor, powerInteractor = powerInteractor, keyguardOcclusionInteractor = keyguardOcclusionInteractor, + dreamManager = dreamManager, deviceEntryInteractor = deviceEntryInteractor, ) } 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 574bbcd6106c..e2b283b06562 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 @@ val Kosmos.keyguardDismissActionInteractor by powerInteractor = powerInteractor, alternateBouncerInteractor = alternateBouncerInteractor, shadeInteractor = { shadeInteractor }, + keyguardInteractor = { keyguardInteractor }, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt index 52416bae0d9d..ace11573c7c6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt @@ -41,6 +41,5 @@ val Kosmos.keyguardDismissInteractor by trustRepository = trustRepository, alternateBouncerInteractor = alternateBouncerInteractor, powerInteractor = powerInteractor, - keyguardTransitionInteractor = keyguardTransitionInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt index 6cf668c50fa4..c3c2c8c95aad 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt @@ -24,10 +24,12 @@ import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.kosmos.applicationCoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.aodBurnInViewModel by Fixture { AodBurnInViewModel( + applicationScope = applicationCoroutineScope, burnInInteractor = burnInInteractor, configurationInteractor = configurationInteractor, keyguardInteractor = keyguardInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelKosmos.kt index 15c7e25f8a5c..ef10459b45cb 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelKosmos.kt @@ -14,19 +14,14 @@ * limitations under the License. */ -package com.android.systemui.biometrics.domain.interactor +package com.android.systemui.keyguard.ui.viewmodel -import com.android.systemui.keyguard.domain.interactor.deviceEntrySideFpsOverlayInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) -val Kosmos.sideFpsOverlayInteractor by Fixture { - SideFpsOverlayInteractorImpl( - biometricStatusInteractor, - displayStateInteractor, - deviceEntrySideFpsOverlayInteractor, - sideFpsSensorInteractor, - ) +@ExperimentalCoroutinesApi +val Kosmos.dozingToGlanceableHubTransitionViewModel by Fixture { + DozingToGlanceableHubTransitionViewModel(animationFlow = keyguardTransitionAnimationFlow) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt index 7cf4083e8407..38626a5dbac3 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt @@ -26,6 +26,7 @@ import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.ui.viewmodel.notificationShadeWindowModel +import com.android.systemui.statusbar.notification.icon.ui.viewmodel.notificationIconContainerAlwaysOnDisplayViewModel import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor import com.android.systemui.statusbar.phone.dozeParameters import com.android.systemui.statusbar.phone.screenOffAnimationController @@ -40,6 +41,7 @@ val Kosmos.keyguardRootViewModel by Fixture { communalInteractor = communalInteractor, keyguardTransitionInteractor = keyguardTransitionInteractor, notificationsKeyguardInteractor = notificationsKeyguardInteractor, + aodNotificationIconViewModel = notificationIconContainerAlwaysOnDisplayViewModel, notificationShadeWindowModel = notificationShadeWindowModel, alternateBouncerToAodTransitionViewModel = alternateBouncerToAodTransitionViewModel, alternateBouncerToGoneTransitionViewModel = alternateBouncerToGoneTransitionViewModel, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt index 2deeb253e925..cfc31c7f301c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt @@ -20,6 +20,7 @@ import com.android.internal.logging.uiEventLogger import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor import com.android.systemui.jank.interactionJankMonitor import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.scene.domain.interactor.sceneBackInteractor @@ -36,6 +37,7 @@ var Kosmos.statusBarStateController: SysuiStatusBarStateController by uiEventLogger, { interactionJankMonitor }, mock(), + { keyguardInteractor }, { keyguardTransitionInteractor }, { shadeInteractor }, { deviceUnlockedInteractor }, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/domain/interactor/KeyguardStateCallbackInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/domain/interactor/KeyguardStateCallbackInteractorKosmos.kt new file mode 100644 index 000000000000..58dd522d40ec --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/domain/interactor/KeyguardStateCallbackInteractorKosmos.kt @@ -0,0 +1,44 @@ +/* + * 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.domain.interactor + +import com.android.keyguard.trustManager +import com.android.systemui.bouncer.domain.interactor.simBouncerInteractor +import com.android.systemui.keyguard.dismissCallbackRegistry +import com.android.systemui.keyguard.domain.interactor.KeyguardStateCallbackInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.domain.interactor.trustInteractor +import com.android.systemui.keyguard.domain.interactor.windowManagerLockscreenVisibilityInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.kosmos.testScope +import com.android.systemui.user.domain.interactor.selectedUserInteractor + +val Kosmos.keyguardStateCallbackInteractor by + Kosmos.Fixture { + KeyguardStateCallbackInteractor( + applicationScope = testScope.backgroundScope, + backgroundDispatcher = testDispatcher, + selectedUserInteractor = selectedUserInteractor, + keyguardTransitionInteractor = keyguardTransitionInteractor, + trustInteractor = trustInteractor, + simBouncerInteractor = simBouncerInteractor, + dismissCallbackRegistry = dismissCallbackRegistry, + wmLockscreenVisibilityInteractor = windowManagerLockscreenVisibilityInteractor, + trustManager = trustManager, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt index ffd8aabdd964..a9e117affefb 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt @@ -25,6 +25,7 @@ import com.android.systemui.keyguard.ui.viewmodel.aodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.aodToGoneTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.aodToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.aodToOccludedTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.dozingToGlanceableHubTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.dozingToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.dozingToOccludedTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.dreamingToLockscreenTransitionViewModel @@ -66,6 +67,7 @@ val Kosmos.sharedNotificationContainerViewModel by Fixture { aodToGoneTransitionViewModel = aodToGoneTransitionViewModel, aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel, aodToOccludedTransitionViewModel = aodToOccludedTransitionViewModel, + dozingToGlanceableHubTransitionViewModel = dozingToGlanceableHubTransitionViewModel, dozingToLockscreenTransitionViewModel = dozingToLockscreenTransitionViewModel, dozingToOccludedTransitionViewModel = dozingToOccludedTransitionViewModel, dreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt new file mode 100644 index 000000000000..385a813996ff --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt @@ -0,0 +1,23 @@ +/* + * 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.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 000000000000..1c7fd4817498 --- /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/tests/utils/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreKosmos.kt new file mode 100644 index 000000000000..e2b7f5fa0717 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreKosmos.kt @@ -0,0 +1,41 @@ +/* + * 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 com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.settings.displayTracker +import com.android.systemui.statusbar.commandQueue + +class KosmosStatusBarWindowStatePerDisplayRepositoryFactory(private val kosmos: Kosmos) : + StatusBarWindowStatePerDisplayRepositoryFactory { + override fun create(displayId: Int): StatusBarWindowStatePerDisplayRepositoryImpl { + return StatusBarWindowStatePerDisplayRepositoryImpl( + displayId, + kosmos.commandQueue, + kosmos.applicationCoroutineScope, + ) + } +} + +val Kosmos.statusBarWindowStateRepositoryStore by + Kosmos.Fixture { + StatusBarWindowStateRepositoryStoreImpl( + displayId = displayTracker.defaultDisplayId, + factory = KosmosStatusBarWindowStatePerDisplayRepositoryFactory(this), + ) + } diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java index 93cdde0d9a20..75d07bb80c05 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 @@ public class CameraExtensionsProxyService extends Service { @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/TEST_MAPPING b/ravenwood/TEST_MAPPING index d4d188ddf692..86246e2dcc2a 100644 --- a/ravenwood/TEST_MAPPING +++ b/ravenwood/TEST_MAPPING @@ -34,15 +34,18 @@ }, { "name": "CarLibHostUnitTest", - "host": true + "host": true, + "keywords": ["automotive_code_coverage"] }, { "name": "CarServiceHostUnitTest", - "host": true + "host": true, + "keywords": ["automotive_code_coverage"] }, { "name": "CarSystemUIRavenTests", - "host": true + "host": true, + "keywords": ["automotive_code_coverage"] }, { "name": "CtsAccountManagerTestCasesRavenwood", diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java index 5d251bdafd44..5ba972df1193 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 @@ public final class RavenwoodAwareTestRunner extends Runner implements Filterable return runner; } + private final Class<?> mTestJavaClass; private TestClass mTestClass = null; private Runner mRealRunner = null; private Description mDescription = null; @@ -192,6 +193,7 @@ public final class RavenwoodAwareTestRunner extends Runner implements Filterable * Constructor. */ public RavenwoodAwareTestRunner(Class<?> testClass) { + mTestJavaClass = testClass; try { performGlobalInitialization(); @@ -320,7 +322,7 @@ public final class RavenwoodAwareTestRunner extends Runner implements Filterable return; } - Log.v(TAG, "Starting " + mTestClass.getJavaClass().getCanonicalName()); + Log.v(TAG, "Starting " + mTestJavaClass.getCanonicalName()); if (RAVENWOOD_VERBOSE_LOGGING) { dumpDescription(getDescription()); } 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 09ed12d49cea..bd013133d3a4 100644 --- a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerCallbackTest.java +++ b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerCallbackTest.java @@ -33,6 +33,7 @@ import org.junit.rules.TestRule; 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; @@ -365,14 +366,14 @@ public class RavenwoodRunnerCallbackTest extends RavenwoodRunnerTestBase { @Expected(""" testRunStarted: classes testSuiteStarted: classes - testSuiteStarted: ClassUnloadbleTest(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$ClassUnloadbleTest) - testIgnored: ClassUnloadbleTest(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$ClassUnloadbleTest) - testSuiteFinished: ClassUnloadbleTest(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$ClassUnloadbleTest) + 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 ClassUnloadbleTest { + public static class ClassUnloadbleAndDisabledTest { static { Assert.fail("Class unloadable!"); } @@ -385,4 +386,73 @@ public class RavenwoodRunnerCallbackTest extends RavenwoodRunnerTestBase { 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/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java b/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java index 54368ca9c03e..4b97745b3b25 100644 --- a/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java +++ b/services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java @@ -73,12 +73,16 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation private static final int MESSAGE_MOVE_MOUSE_POINTER = 1; private static final int MESSAGE_SCROLL_MOUSE_POINTER = 2; - private static final float MOUSE_POINTER_MOVEMENT_STEP = 1.8f; private static final int KEY_NOT_SET = -1; /** Time interval after which mouse action will be repeated */ private static final int INTERVAL_MILLIS = 10; + @VisibleForTesting + public static final float MOUSE_POINTER_MOVEMENT_STEP = 1.8f; + @VisibleForTesting + public static final float MOUSE_SCROLL_STEP = 0.2f; + private final AccessibilityManagerService mAms; private final Handler mHandler; private final InputManager mInputManager; @@ -281,8 +285,8 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation MouseKeyEvent mouseKeyEvent = MouseKeyEvent.from( keyCode, mActiveInputDeviceId, mDeviceKeyCodeMap); float y = switch (mouseKeyEvent) { - case UP_MOVE_OR_SCROLL -> 1.0f; - case DOWN_MOVE_OR_SCROLL -> -1.0f; + case UP_MOVE_OR_SCROLL -> MOUSE_SCROLL_STEP; + case DOWN_MOVE_OR_SCROLL -> -MOUSE_SCROLL_STEP; default -> 0.0f; }; waitForVirtualMouseCreation(); diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java index aa57e0b84a63..a19fdddea49c 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java @@ -68,11 +68,15 @@ import android.view.ViewConfiguration; import com.android.internal.R; import com.android.internal.accessibility.util.AccessibilityStatsLogUtils; import com.android.internal.annotations.VisibleForTesting; +import com.android.modules.expresslog.Histogram; import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.accessibility.AccessibilityTraceManager; import com.android.server.accessibility.Flags; import com.android.server.accessibility.gestures.GestureUtils; +import java.util.ArrayList; +import java.util.List; + /** * This class handles full screen magnification in response to touch events. * @@ -871,6 +875,15 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH */ class DetectingState implements State, Handler.Callback { + private static final Histogram HISTOGRAM_FIRST_INTERVAL = + new Histogram( + "accessibility.value_full_triple_tap_first_interval", + new Histogram.UniformOptions(25, 0, 250)); + private static final Histogram HISTOGRAM_SECOND_INTERVAL = + new Histogram( + "accessibility.value_full_triple_tap_second_interval", + new Histogram.UniformOptions(25, 0, 250)); + private static final int MESSAGE_ON_TRIPLE_TAP_AND_HOLD = 1; private static final int MESSAGE_TRANSITION_TO_DELEGATING_STATE = 2; private static final int MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE = 3; @@ -1115,6 +1128,12 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH if (multitapTriggered && numTaps > 2) { final boolean enabled = !isActivated(); mMagnificationLogger.logMagnificationTripleTap(enabled); + + List<Long> intervals = intervalsOf(mDelayedEventQueue, ACTION_UP); + if (intervals.size() >= 2) { + HISTOGRAM_FIRST_INTERVAL.logSample(intervals.get(0)); + HISTOGRAM_SECOND_INTERVAL.logSample(intervals.get(1)); + } } return multitapTriggered; } @@ -1144,6 +1163,10 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH return event != null ? event.getEventTime() : Long.MIN_VALUE; } + public List<Long> intervalsOf(MotionEventInfo info, int eventType) { + return MotionEventInfo.intervalsOf(info, eventType); + } + public int tapCount() { return MotionEventInfo.countOf(mDelayedEventQueue, ACTION_UP); } @@ -1649,7 +1672,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH return !(Float.isNaN(pointerDownLocation.x) && Float.isNaN(pointerDownLocation.y)); } - private static final class MotionEventInfo { + public static final class MotionEventInfo { private static final int MAX_POOL_SIZE = 10; private static final Object sLock = new Object(); @@ -1709,6 +1732,14 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH } } + public MotionEventInfo getNext() { + return mNext; + } + + public void setNext(MotionEventInfo info) { + mNext = info; + } + private void clear() { event = recycleAndNullify(event); rawEvent = recycleAndNullify(rawEvent); @@ -1721,6 +1752,23 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH + countOf(info.mNext, eventType); } + static List<Long> intervalsOf(MotionEventInfo info, int eventType) { + List<Long> intervals = new ArrayList<>(); + MotionEventInfo current = info; + MotionEventInfo previous = null; + + while (current != null) { + if (current.event.getAction() == eventType) { + if (previous != null) { + intervals.add(current.event.getDownTime() - previous.event.getDownTime()); + } + previous = current; + } + current = current.mNext; + } + return intervals; + } + public static String toString(MotionEventInfo info) { return info == null ? "" diff --git a/services/appfunctions/Android.bp b/services/appfunctions/Android.bp index f8ee823ef0c9..eb6e46861898 100644 --- a/services/appfunctions/Android.bp +++ b/services/appfunctions/Android.bp @@ -22,4 +22,7 @@ java_library_static { "java/**/*.logtags", ], libs: ["services.core"], + lint: { + baseline_filename: "lint-baseline.xml", + }, } diff --git a/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java b/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java index 759f02eb138a..d84b20556053 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java +++ b/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java @@ -53,12 +53,10 @@ import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Set; -import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; /** * This class implements helper methods for synchronously interacting with AppSearch while @@ -74,8 +72,9 @@ public class MetadataSyncAdapter { private final AppSearchManager mAppSearchManager; private final PackageManager mPackageManager; private final Object mLock = new Object(); + @GuardedBy("mLock") - private Future<AndroidFuture<Boolean>> mCurrentSyncTask; + private Future<?> mCurrentSyncTask; // Hidden constants in {@link SetSchemaRequest} that restricts runtime metadata visibility // by permissions. @@ -105,7 +104,7 @@ public class MetadataSyncAdapter { AppFunctionRuntimeMetadata.APP_FUNCTION_RUNTIME_METADATA_DB) .build(); AndroidFuture<Boolean> settableSyncStatus = new AndroidFuture<>(); - Callable<AndroidFuture<Boolean>> callableTask = + Runnable runnable = () -> { try (FutureAppSearchSession staticMetadataSearchSession = new FutureAppSearchSessionImpl( @@ -125,14 +124,13 @@ public class MetadataSyncAdapter { } catch (Exception ex) { settableSyncStatus.completeExceptionally(ex); } - return settableSyncStatus; }; synchronized (mLock) { if (mCurrentSyncTask != null && !mCurrentSyncTask.isDone()) { - boolean cancel = mCurrentSyncTask.cancel(false); + var unused = mCurrentSyncTask.cancel(false); } - mCurrentSyncTask = mExecutor.submit(callableTask); + mCurrentSyncTask = mExecutor.submit(runnable); } return settableSyncStatus; @@ -140,11 +138,7 @@ public class MetadataSyncAdapter { /** This method shuts down the {@link MetadataSyncAdapter} scheduler. */ public void shutDown() { - try { - var unused = mExecutor.awaitTermination(30, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Slog.e(TAG, "Error shutting down MetadataSyncAdapter scheduler", e); - } + mExecutor.shutdown(); } @WorkerThread diff --git a/services/appfunctions/lint-baseline.xml b/services/appfunctions/lint-baseline.xml new file mode 100644 index 000000000000..fbcb9f3e6ec6 --- /dev/null +++ b/services/appfunctions/lint-baseline.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<issues format="6" by="lint 8.4.0-alpha08" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha08"> + + <issue + id="MissingPermissionAnnotation" + message="executeAppFunction should be annotated with either @EnforcePermission, @RequiresNoPermission or @PermissionManuallyEnforced." + errorLine1=" @Override" + errorLine2=" ^"> + <location + file="frameworks/base/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java" + line="101" + column="5"/> + </issue> + + <issue + id="MissingPermissionAnnotation" + message="onResult should be annotated with either @EnforcePermission, @RequiresNoPermission or @PermissionManuallyEnforced." + errorLine1=" @Override" + errorLine2=" ^"> + <location + file="frameworks/base/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java" + line="243" + column="49"/> + </issue> + +</issues> 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 46d60f9c8504..0c54720c53e4 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 @@ public final class AssociationDiskStore { @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/core/Android.bp b/services/core/Android.bp index 4e36e3ff9188..c6e599e8edee 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -225,6 +225,7 @@ java_library_static { "updates_flags_lib", "com_android_server_accessibility_flags_lib", "//frameworks/libs/systemui:com_android_systemui_shared_flags_lib", + "com_android_launcher3_flags_lib", "com_android_wm_shell_flags_lib", "com.android.server.utils_aconfig-java", "service-jobscheduler-deviceidle.flags-aconfig-java", diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags index fd512a64b32c..5b271a3730fc 100644 --- a/services/core/java/com/android/server/EventLogTags.logtags +++ b/services/core/java/com/android/server/EventLogTags.logtags @@ -96,6 +96,8 @@ option java_package com.android.server 27535 notification_adjusted (key|3),(adjustment_type|3),(new_value|3) # when a notification cancellation is prevented by the system 27536 notification_cancel_prevented (key|3) +# when a summary notification is converted to a regular notification because of force autogrouping +27537 notification_summary_converted (key|3) # --------------------------- # Watchdog.java diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 871c32086a7f..a85e2a23e4c8 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -262,6 +262,7 @@ import android.appwidget.AppWidgetManagerInternal; import android.content.AttributionSource; import android.content.AutofillOptions; import android.content.BroadcastReceiver; +import android.content.ClipData; import android.content.ComponentCallbacks2; import android.content.ComponentName; import android.content.ContentCaptureOptions; @@ -418,7 +419,6 @@ import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.MemInfoReader; import com.android.internal.util.Preconditions; -import com.android.server.crashrecovery.CrashRecoveryHelper; import com.android.server.AlarmManagerInternal; import com.android.server.BootReceiver; import com.android.server.DeviceIdleInternal; @@ -438,6 +438,7 @@ import com.android.server.am.LowMemDetector.MemFactor; import com.android.server.appop.AppOpsService; import com.android.server.compat.PlatformCompat; import com.android.server.contentcapture.ContentCaptureManagerInternal; +import com.android.server.crashrecovery.CrashRecoveryHelper; import com.android.server.criticalevents.CriticalEventLog; import com.android.server.firewall.IntentFirewall; import com.android.server.graphics.fonts.FontManagerInternal; @@ -482,6 +483,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; +import java.lang.ref.WeakReference; import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; @@ -499,6 +501,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; @@ -1038,13 +1041,14 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void onIntentStarted(@NonNull Intent intent, long timestampNanos) { synchronized (this) { - mProcessList.getAppStartInfoTracker().onIntentStarted(intent, timestampNanos); + mProcessList.getAppStartInfoTracker() + .onActivityIntentStarted(intent, timestampNanos); } } @Override public void onIntentFailed(long id) { - mProcessList.getAppStartInfoTracker().onIntentFailed(id); + mProcessList.getAppStartInfoTracker().onActivityIntentFailed(id); } @Override @@ -1078,7 +1082,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void onReportFullyDrawn(long id, long timestampNanos) { - mProcessList.getAppStartInfoTracker().onReportFullyDrawn(id, timestampNanos); + mProcessList.getAppStartInfoTracker().onActivityReportFullyDrawn(id, timestampNanos); } }; @@ -15304,10 +15308,8 @@ public class ActivityManagerService extends IActivityManager.Stub } 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); @@ -19086,4 +19088,87 @@ public class ActivityManagerService extends IActivityManager.Stub Freezer getFreezer() { return mFreezer; } + + // Set of IntentCreatorToken objects that are currently active. + private static final Map<IntentCreatorToken.Key, WeakReference<IntentCreatorToken>> + sIntentCreatorTokenCache = new ConcurrentHashMap<>(); + + /** + * A binder token used to keep track of which app created the intent. This token can be used to + * defend against intent redirect attacks. It stores uid of the intent creator and key fields of + * the intent to make it impossible for attacker to fake uid with a malicious intent. + * + * @hide + */ + public static final class IntentCreatorToken extends Binder { + @NonNull + private final Key mKeyFields; + + public IntentCreatorToken(int creatorUid, Intent intent) { + super(); + this.mKeyFields = new Key(creatorUid, intent); + } + + public int getCreatorUid() { + return mKeyFields.mCreatorUid; + } + + /** {@hide} */ + public static boolean isValid(@NonNull Intent intent) { + IBinder binder = intent.getCreatorToken(); + IntentCreatorToken token = null; + if (binder instanceof IntentCreatorToken) { + token = (IntentCreatorToken) binder; + } + return token != null && token.mKeyFields.equals( + new Key(token.mKeyFields.mCreatorUid, intent)); + } + + private static class Key { + private Key(int creatorUid, Intent intent) { + this.mCreatorUid = creatorUid; + this.mAction = intent.getAction(); + this.mData = intent.getData(); + this.mType = intent.getType(); + this.mPackage = intent.getPackage(); + this.mComponent = intent.getComponent(); + this.mFlags = intent.getFlags() & Intent.IMMUTABLE_FLAGS; + ClipData clipData = intent.getClipData(); + if (clipData != null) { + this.mClipDataUris = new ArrayList<>(clipData.getItemCount()); + for (int i = 0; i < clipData.getItemCount(); i++) { + this.mClipDataUris.add(clipData.getItemAt(i).getUri()); + } + } + } + + private final int mCreatorUid; + private final String mAction; + private final Uri mData; + private final String mType; + private final String mPackage; + private final ComponentName mComponent; + private final int mFlags; + private List<Uri> mClipDataUris; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Key key = (Key) o; + return mCreatorUid == key.mCreatorUid && mFlags == key.mFlags && Objects.equals( + mAction, key.mAction) && Objects.equals(mData, key.mData) + && Objects.equals(mType, key.mType) && Objects.equals(mPackage, + key.mPackage) && Objects.equals(mComponent, key.mComponent) + && Objects.equals(mClipDataUris, key.mClipDataUris); + } + + @Override + public int hashCode() { + return Objects.hash(mCreatorUid, mAction, mData, mType, mPackage, mComponent, + mFlags, + mClipDataUris); + } + } + } } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 0e19347163f1..210301ec4c5e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -133,6 +133,7 @@ import com.android.server.am.nano.VMCapability; import com.android.server.am.nano.VMInfo; import com.android.server.compat.PlatformCompat; import com.android.server.pm.UserManagerInternal; +import com.android.server.utils.AnrTimer; import com.android.server.utils.Slogf; import dalvik.annotation.optimization.NeverCompile; @@ -285,6 +286,8 @@ final class ActivityManagerShellCommand extends ShellCommand { return -1; case "trace-ipc": return runTraceIpc(pw); + case "trace-timer": + return runTraceTimer(pw); case "profile": return runProfile(pw); case "dumpheap": @@ -1062,6 +1065,23 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } + // Update AnrTimer tracing. + private int runTraceTimer(PrintWriter pw) throws RemoteException { + if (!AnrTimer.traceFeatureEnabled()) return -1; + + // Delegate all argument parsing to the AnrTimer method. + try { + final String result = AnrTimer.traceTimers(peekRemainingArgs()); + if (result != null) { + pw.println(result); + } + return 0; + } catch (IllegalArgumentException e) { + getErrPrintWriter().println("Error: bad trace-timer command: " + e); + return -1; + } + } + // NOTE: current profiles can only be started on default display (even on automotive builds with // passenger displays), so there's no need to pass a display-id private int runProfile(PrintWriter pw) throws RemoteException { @@ -4352,6 +4372,7 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" start: start tracing IPC transactions."); pw.println(" stop: stop tracing IPC transactions and dump the results to file."); pw.println(" --dump-file <FILE>: Specify the file the trace should be dumped to."); + anrTimerHelp(pw); pw.println(" profile start [--user <USER_ID> current]"); pw.println(" [--clock-type <TYPE>]"); pw.println(" [" + PROFILER_OUTPUT_VERSION_FLAG + " VERSION]"); @@ -4605,4 +4626,19 @@ final class ActivityManagerShellCommand extends ShellCommand { Intent.printIntentArgsHelp(pw, ""); } } + + static void anrTimerHelp(PrintWriter pw) { + // Return silently if tracing is not feature-enabled. + if (!AnrTimer.traceFeatureEnabled()) return; + + String h = AnrTimer.traceTimers(new String[]{"help"}); + if (h == null) { + return; + } + + pw.println(" trace-timer <cmd>"); + for (String s : h.split("\n")) { + pw.println(" " + s); + } + } } diff --git a/services/core/java/com/android/server/am/AppStartInfoTracker.java b/services/core/java/com/android/server/am/AppStartInfoTracker.java index 6aadcdc74870..71b64567d062 100644 --- a/services/core/java/com/android/server/am/AppStartInfoTracker.java +++ b/services/core/java/com/android/server/am/AppStartInfoTracker.java @@ -280,7 +280,11 @@ public final class AppStartInfoTracker { mTemporaryInProgressIndexes.clear(); } - void onIntentStarted(@NonNull Intent intent, long timestampNanos) { + /** + * Should only be called for Activity launch sequences from an instance of + * {@link ActivityMetricsLaunchObserver}. + */ + void onActivityIntentStarted(@NonNull Intent intent, long timestampNanos) { synchronized (mLock) { if (!mEnabled) { return; @@ -291,6 +295,10 @@ public final class AppStartInfoTracker { start.setStartType(ApplicationStartInfo.START_TYPE_UNSET); start.addStartupTimestamp(ApplicationStartInfo.START_TIMESTAMP_LAUNCH, timestampNanos); + if (android.app.Flags.appStartInfoComponent()) { + start.setStartComponent(ApplicationStartInfo.START_COMPONENT_ACTIVITY); + } + // TODO: handle possible alarm activity start. if (intent != null && intent.getCategories() != null && intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) { @@ -303,7 +311,11 @@ public final class AppStartInfoTracker { } } - void onIntentFailed(long id) { + /** + * Should only be called for Activity launch sequences from an instance of + * {@link ActivityMetricsLaunchObserver}. + */ + void onActivityIntentFailed(long id) { synchronized (mLock) { if (!mEnabled) { return; @@ -322,6 +334,10 @@ public final class AppStartInfoTracker { } } + /** + * Should only be called for Activity launch sequences from an instance of + * {@link ActivityMetricsLaunchObserver}. + */ void onActivityLaunched(long id, ComponentName name, long temperature, ProcessRecord app) { synchronized (mLock) { if (!mEnabled) { @@ -349,6 +365,10 @@ public final class AppStartInfoTracker { } } + /** + * Should only be called for Activity launch sequences from an instance of + * {@link ActivityMetricsLaunchObserver}. + */ void onActivityLaunchCancelled(long id) { synchronized (mLock) { if (!mEnabled) { @@ -368,6 +388,10 @@ public final class AppStartInfoTracker { } } + /** + * Should only be called for Activity launch sequences from an instance of + * {@link ActivityMetricsLaunchObserver}. + */ void onActivityLaunchFinished(long id, ComponentName name, long timestampNanos, int launchMode) { synchronized (mLock) { @@ -391,7 +415,11 @@ public final class AppStartInfoTracker { } } - void onReportFullyDrawn(long id, long timestampNanos) { + /** + * Should only be called for Activity launch sequences from an instance of + * {@link ActivityMetricsLaunchObserver}. + */ + void onActivityReportFullyDrawn(long id, long timestampNanos) { synchronized (mLock) { if (!mEnabled) { return; @@ -424,6 +452,10 @@ public final class AppStartInfoTracker { ApplicationStartInfo.START_TIMESTAMP_LAUNCH, startTimeNs); start.setStartType(ApplicationStartInfo.START_TYPE_COLD); + if (android.app.Flags.appStartInfoComponent()) { + start.setStartComponent(ApplicationStartInfo.START_COMPONENT_SERVICE); + } + // TODO: handle possible alarm service start. start.setReason(serviceRecord.permission != null && serviceRecord.permission.contains("android.permission.BIND_JOB_SERVICE") @@ -455,6 +487,11 @@ public final class AppStartInfoTracker { start.setReason(ApplicationStartInfo.START_REASON_BROADCAST); } start.setIntent(intent); + + if (android.app.Flags.appStartInfoComponent()) { + start.setStartComponent(ApplicationStartInfo.START_COMPONENT_BROADCAST); + } + addStartInfoLocked(start); } } @@ -472,6 +509,11 @@ public final class AppStartInfoTracker { ApplicationStartInfo.START_TIMESTAMP_LAUNCH, startTimeNs); start.setStartType(ApplicationStartInfo.START_TYPE_COLD); start.setReason(ApplicationStartInfo.START_REASON_CONTENT_PROVIDER); + + if (android.app.Flags.appStartInfoComponent()) { + start.setStartComponent(ApplicationStartInfo.START_COMPONENT_CONTENT_PROVIDER); + } + addStartInfoLocked(start); } } @@ -490,6 +532,11 @@ public final class AppStartInfoTracker { start.setStartType(cold ? ApplicationStartInfo.START_TYPE_COLD : ApplicationStartInfo.START_TYPE_WARM); start.setReason(ApplicationStartInfo.START_REASON_BACKUP); + + if (android.app.Flags.appStartInfoComponent()) { + start.setStartComponent(ApplicationStartInfo.START_COMPONENT_OTHER); + } + addStartInfoLocked(start); } } diff --git a/services/core/java/com/android/server/am/BroadcastController.java b/services/core/java/com/android/server/am/BroadcastController.java index f7085b4b26b4..15f1085b7125 100644 --- a/services/core/java/com/android/server/am/BroadcastController.java +++ b/services/core/java/com/android/server/am/BroadcastController.java @@ -57,6 +57,7 @@ import android.app.ApplicationExitInfo; import android.app.ApplicationThreadConstants; import android.app.BackgroundStartPrivileges; import android.app.BroadcastOptions; +import android.app.BroadcastStickyCache; import android.app.IApplicationThread; import android.app.compat.CompatChanges; import android.appwidget.AppWidgetManager; @@ -685,6 +686,7 @@ class BroadcastController { boolean serialized, boolean sticky, int userId) { mService.enforceNotIsolatedCaller("broadcastIntent"); + int result; synchronized (mService) { intent = verifyBroadcastLocked(intent); @@ -706,7 +708,7 @@ class BroadcastController { final long origId = Binder.clearCallingIdentity(); try { - return broadcastIntentLocked(callerApp, + result = broadcastIntentLocked(callerApp, callerApp != null ? callerApp.info.packageName : null, callingFeatureId, intent, resolvedType, resultToApp, resultTo, resultCode, resultData, resultExtras, requiredPermissions, excludedPermissions, excludedPackages, @@ -717,6 +719,10 @@ class BroadcastController { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } } + if (sticky && result == ActivityManager.BROADCAST_SUCCESS) { + BroadcastStickyCache.incrementVersion(intent.getAction()); + } + return result; } // Not the binder call surface @@ -727,6 +733,7 @@ class BroadcastController { boolean serialized, boolean sticky, int userId, BackgroundStartPrivileges backgroundStartPrivileges, @Nullable int[] broadcastAllowList) { + int result; synchronized (mService) { intent = verifyBroadcastLocked(intent); @@ -734,7 +741,7 @@ class BroadcastController { String[] requiredPermissions = requiredPermission == null ? null : new String[] {requiredPermission}; try { - return broadcastIntentLocked(null, packageName, featureId, intent, resolvedType, + result = broadcastIntentLocked(null, packageName, featureId, intent, resolvedType, resultToApp, resultTo, resultCode, resultData, resultExtras, requiredPermissions, null, null, OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid, realCallingPid, userId, @@ -744,6 +751,10 @@ class BroadcastController { Binder.restoreCallingIdentity(origId); } } + if (sticky && result == ActivityManager.BROADCAST_SUCCESS) { + BroadcastStickyCache.incrementVersion(intent.getAction()); + } + return result; } @GuardedBy("mService") @@ -1442,6 +1453,7 @@ class BroadcastController { list.add(StickyBroadcast.create(new Intent(intent), deferUntilActive, callingUid, callerAppProcessState, resolvedType)); } + BroadcastStickyCache.incrementVersion(intent.getAction()); } } @@ -1708,6 +1720,7 @@ class BroadcastController { Slog.w(TAG, msg); throw new SecurityException(msg); } + final ArrayList<String> changedStickyBroadcasts = new ArrayList<>(); synchronized (mStickyBroadcasts) { ArrayMap<String, ArrayList<StickyBroadcast>> stickies = mStickyBroadcasts.get(userId); if (stickies != null) { @@ -1724,12 +1737,16 @@ class BroadcastController { if (list.size() <= 0) { stickies.remove(intent.getAction()); } + changedStickyBroadcasts.add(intent.getAction()); } if (stickies.size() <= 0) { mStickyBroadcasts.remove(userId); } } } + for (int i = changedStickyBroadcasts.size() - 1; i >= 0; --i) { + BroadcastStickyCache.incrementVersionIfExists(changedStickyBroadcasts.get(i)); + } } void finishReceiver(IBinder caller, int resultCode, String resultData, @@ -1892,7 +1909,9 @@ class BroadcastController { private void sendPackageBroadcastLocked(int cmd, String[] packages, int userId) { mService.mProcessList.sendPackageBroadcastLocked(cmd, packages, userId); - }private List<ResolveInfo> collectReceiverComponents( + } + + private List<ResolveInfo> collectReceiverComponents( Intent intent, String resolvedType, int callingUid, int callingPid, int[] users, int[] broadcastAllowList) { // TODO: come back and remove this assumption to triage all broadcasts @@ -2108,9 +2127,18 @@ class BroadcastController { } void removeStickyBroadcasts(int userId) { + final ArrayList<String> changedStickyBroadcasts = new ArrayList<>(); synchronized (mStickyBroadcasts) { + final ArrayMap<String, ArrayList<StickyBroadcast>> stickies = + mStickyBroadcasts.get(userId); + if (stickies != null) { + changedStickyBroadcasts.addAll(stickies.keySet()); + } mStickyBroadcasts.remove(userId); } + for (int i = changedStickyBroadcasts.size() - 1; i >= 0; --i) { + BroadcastStickyCache.incrementVersionIfExists(changedStickyBroadcasts.get(i)); + } } @NeverCompile diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS index d6f04db5af55..2a30ad0e0f3f 100644 --- a/services/core/java/com/android/server/am/OWNERS +++ b/services/core/java/com/android/server/am/OWNERS @@ -1,43 +1,46 @@ # Applications & Processes -yamasani@google.com -jsharkey@google.com -hackbod@google.com -omakoto@google.com -ctate@google.com -huiyu@google.com -mwachens@google.com -sudheersai@google.com -suprabh@google.com -varunshah@google.com -bookatz@google.com -jji@google.com - -# Windows & Activities -ogunwale@google.com +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 +per-file App*ExitInfo* = file:/ACTIVITY_MANAGER_OWNERS +per-file appexitinfo.proto = file:/ACTIVITY_MANAGER_OWNERS +per-file App*StartInfo* = file:/PERFORMANCE_OWNERS +per-file appstartinfo.proto = file:/PERFORMANCE_OWNERS # Permissions & Packages -patb@google.com per-file AccessCheckDelegateHelper.java = file:/core/java/android/permission/OWNERS # Battery Stats -joeo@google.com +per-file AppBatteryTracker.java = file:/BATTERY_STATS_OWNERS per-file BatteryStats* = file:/BATTERY_STATS_OWNERS per-file BatteryExternalStats* = file:/BATTERY_STATS_OWNERS -# Londoners -michaelwr@google.com -narayan@google.com - # 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 = omakoto@google.com, yamasani@google.com, dzshen@google.com, zhidou@google.com, tedbauer@google.com - -per-file CarUserSwitchingDialog.java = file:platform/packages/services/Car:/OWNERS - -per-file ContentProviderHelper.java = varunshah@google.com, omakoto@google.com, jsharkey@google.com, yamasani@google.com +# Content Provider +per-file ContentProvider* = varunshah@google.com, yamasani@google.com +# 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 @@ per-file User* = file:/MULTIUSER_OWNERS # Broadcasts per-file Broadcast* = file:/BROADCASTS_OWNERS + +# Permissions & Packages +per-file *Permission* = patb@google.com +per-file *Package* = patb@google.com + +# OOM Adjuster +per-file *Oom* = file:/OOM_ADJUSTER_OWNERS + +# Miscellaneous +per-file SettingsToPropertiesMapper.java = omakoto@google.com, yamasani@google.com, dzshen@google.com, zhidou@google.com, tedbauer@google.com +per-file CarUserSwitchingDialog.java = file:platform/packages/services/Car:/OWNERS + +# Londoners +michaelwr@google.com #{LAST_RESORT_SUGGESTION} +narayan@google.com #{LAST_RESORT_SUGGESTION} + +# Default +yamasani@google.com +hackbod@google.com #{LAST_RESORT_SUGGESTION} +omakoto@google.com #{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 22ec7904f972..78a0a117fe6f 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 @@ public class OomAdjuster { 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 00250b4ef463..a93ae72fcfea 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -4998,50 +4998,67 @@ public final class ProcessList { } @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; + 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); } - i--; + 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); - } + 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); } - 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(); + } else { + item = new ActivityManagerService.ProcessChangeItem(); + if (DEBUG_PROCESS_OBSERVERS) { + Slog.i(TAG_PROCESS_OBSERVERS, "Allocating new item: " + item); } - mPendingProcessChanges.add(item); } - - return 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") diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 6ae6f3d4713a..a6389f7f5311 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -423,7 +423,7 @@ public class AppOpsService extends IAppOpsService.Stub { /** Hands the definition of foreground and uid states */ @GuardedBy("this") - public AppOpsUidStateTracker getUidStateTracker() { + private AppOpsUidStateTracker getUidStateTracker() { if (mUidStateTracker == null) { mUidStateTracker = new AppOpsUidStateTrackerImpl( LocalServices.getService(ActivityManagerInternal.class), @@ -619,7 +619,7 @@ public class AppOpsService extends IAppOpsService.Stub { 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 @@ public class AppOpsService extends IAppOpsService.Stub { @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 @@ public class AppOpsService extends IAppOpsService.Stub { 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 = @@ -2895,21 +2895,28 @@ public class AppOpsService extends IAppOpsService.Stub { uidState.uid, getPersistentId(virtualDeviceId), code); if (rawUidMode != AppOpsManager.opToDefaultMode(code)) { - return raw ? rawUidMode : uidState.evalMode(code, rawUidMode); + return raw ? rawUidMode : + evaluateForegroundMode(/* uid= */ uid, /* op= */ code, + /* rawUidMode= */ rawUidMode); } } Op op = getOpLocked(code, uid, packageName, null, false, pvr.bypass, /* edit */ false); if (op == null) { - return AppOpsManager.opToDefaultMode(code); + return evaluateForegroundMode( + /* uid= */ uid, + /* op= */ code, + /* rawUidMode= */ AppOpsManager.opToDefaultMode(code)); } - return raw - ? mAppOpsCheckingService.getPackageMode( - op.packageName, op.op, UserHandle.getUserId(op.uid)) - : op.uidState.evalMode( - op.op, - mAppOpsCheckingService.getPackageMode( - op.packageName, op.op, UserHandle.getUserId(op.uid))); + var packageMode = mAppOpsCheckingService.getPackageMode( + op.packageName, + op.op, + UserHandle.getUserId(op.uid)); + return raw ? packageMode : + evaluateForegroundMode( + /* uid= */ uid, + /* op= */op.op, + /* rawUidMode= */ packageMode); } } @@ -4739,7 +4746,7 @@ public class AppOpsService extends IAppOpsService.Stub { return null; } ops = new Ops(packageName, uidState); - uidState.pkgOps.put(packageName, ops); + uidState.pkgOps.put(packageName.intern(), ops); } if (edit) { @@ -5076,7 +5083,7 @@ public class AppOpsService extends IAppOpsService.Stub { 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); } @@ -7003,6 +7010,11 @@ public class AppOpsService extends IAppOpsService.Stub { "Requested persistentId for invalid virtualDeviceId: " + virtualDeviceId); } + @GuardedBy("this") + private int evaluateForegroundMode(int uid, int op, int rawUidMode) { + return getUidStateTracker().evalMode(uid, op, rawUidMode); + } + private final class ClientUserRestrictionState implements DeathRecipient { private final IBinder token; diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 55d9c6eac87a..0fd22c583192 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -17,6 +17,11 @@ package com.android.server.audio; import static android.media.audio.Flags.scoManagedByAudio; +import static com.android.media.audio.Flags.equalScoLeaVcIndexRange; +import static com.android.server.audio.AudioService.BT_COMM_DEVICE_ACTIVE_BLE_HEADSET; +import static com.android.server.audio.AudioService.BT_COMM_DEVICE_ACTIVE_BLE_SPEAKER; +import static com.android.server.audio.AudioService.BT_COMM_DEVICE_ACTIVE_SCO; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.compat.CompatChanges; @@ -64,6 +69,7 @@ import android.util.Pair; import android.util.PrintWriterPrinter; import com.android.internal.annotations.GuardedBy; +import com.android.server.audio.AudioService.BtCommDeviceActiveType; import com.android.server.utils.EventLogger; import java.io.PrintWriter; @@ -333,8 +339,8 @@ public class AudioDeviceBroker { Log.v(TAG, "setCommunicationDevice, device: " + device + ", uid: " + uid); } - synchronized (mDeviceStateLock) { - if (device == null) { + if (device == null) { + synchronized (mDeviceStateLock) { CommunicationRouteClient client = getCommunicationRouteClientForUid(uid); if (client == null) { return false; @@ -835,15 +841,15 @@ public class AudioDeviceBroker { return isDeviceOnForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO); } - /*package*/ boolean isBluetoothScoActive() { + private boolean isBluetoothScoActive() { return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO); } - /*package*/ boolean isBluetoothBleHeadsetActive() { + private boolean isBluetoothBleHeadsetActive() { return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLE_HEADSET); } - /*package*/ boolean isBluetoothBleSpeakerActive() { + private boolean isBluetoothBleSpeakerActive() { return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLE_SPEAKER); } @@ -1437,7 +1443,20 @@ public class AudioDeviceBroker { } mCurCommunicationPortId = portId; - mAudioService.postScoDeviceActive(isBluetoothScoActive()); + @BtCommDeviceActiveType int btCommDeviceActiveType = 0; + if (equalScoLeaVcIndexRange()) { + if (isBluetoothScoActive()) { + btCommDeviceActiveType = BT_COMM_DEVICE_ACTIVE_SCO; + } else if (isBluetoothBleHeadsetActive()) { + btCommDeviceActiveType = BT_COMM_DEVICE_ACTIVE_BLE_HEADSET; + } else if (isBluetoothBleSpeakerActive()) { + btCommDeviceActiveType = BT_COMM_DEVICE_ACTIVE_BLE_SPEAKER; + } + mAudioService.postBtCommDeviceActive(btCommDeviceActiveType); + } else { + mAudioService.postBtCommDeviceActive( + isBluetoothScoActive() ? BT_COMM_DEVICE_ACTIVE_SCO : btCommDeviceActiveType); + } final int nbDispatchers = mCommDevDispatchers.beginBroadcast(); for (int i = 0; i < nbDispatchers; i++) { diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 9e110819cb85..e83b03690a24 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -66,6 +66,7 @@ import static com.android.media.audio.Flags.alarmMinVolumeZero; import static com.android.media.audio.Flags.asDeviceConnectionFailure; import static com.android.media.audio.Flags.audioserverPermissions; import static com.android.media.audio.Flags.disablePrescaleAbsoluteVolume; +import static com.android.media.audio.Flags.equalScoLeaVcIndexRange; import static com.android.media.audio.Flags.replaceStreamBtSco; import static com.android.media.audio.Flags.ringerModeAffectsAlarm; import static com.android.media.audio.Flags.setStreamVolumeOrder; @@ -470,7 +471,7 @@ public class AudioService extends IAudioService.Stub private static final int MSG_CONFIGURATION_CHANGED = 54; private static final int MSG_BROADCAST_MASTER_MUTE = 55; private static final int MSG_UPDATE_CONTEXTUAL_VOLUMES = 56; - private static final int MSG_SCO_DEVICE_ACTIVE_UPDATE = 57; + private static final int MSG_BT_COMM_DEVICE_ACTIVE_UPDATE = 57; /** * Messages handled by the {@link SoundDoseHelper}, do not exceed @@ -766,7 +767,21 @@ public class AudioService extends IAudioService.Stub * @see System#MUTE_STREAMS_AFFECTED */ private int mUserMutableStreams; - private final AtomicBoolean mScoDeviceActive = new AtomicBoolean(false); + /** The active bluetooth device type used for communication is sco. */ + /*package*/ static final int BT_COMM_DEVICE_ACTIVE_SCO = 1; + /** The active bluetooth device type used for communication is ble headset. */ + /*package*/ static final int BT_COMM_DEVICE_ACTIVE_BLE_HEADSET = 1 << 1; + /** The active bluetooth device type used for communication is ble speaker. */ + /*package*/ static final int BT_COMM_DEVICE_ACTIVE_BLE_SPEAKER = 1 << 2; + @IntDef({ + BT_COMM_DEVICE_ACTIVE_SCO, BT_COMM_DEVICE_ACTIVE_BLE_HEADSET, + BT_COMM_DEVICE_ACTIVE_BLE_SPEAKER + }) + @Retention(RetentionPolicy.SOURCE) + public @interface BtCommDeviceActiveType { + } + + private final AtomicInteger mBtCommDeviceActive = new AtomicInteger(0); @NonNull private SoundEffectsHelper mSfxHelper; @@ -2522,12 +2537,18 @@ public class AudioService extends IAudioService.Stub // this should not happen, throwing exception throw new IllegalArgumentException("STREAM_BLUETOOTH_SCO is deprecated"); } - return streamType == AudioSystem.STREAM_VOICE_CALL && mScoDeviceActive.get(); + return streamType == AudioSystem.STREAM_VOICE_CALL + && mBtCommDeviceActive.get() == BT_COMM_DEVICE_ACTIVE_SCO; } else { return streamType == AudioSystem.STREAM_BLUETOOTH_SCO; } } + private boolean isStreamBluetoothComm(int streamType) { + return (streamType == AudioSystem.STREAM_VOICE_CALL && mBtCommDeviceActive.get() != 0) + || streamType == AudioSystem.STREAM_BLUETOOTH_SCO; + } + private void dumpStreamStates(PrintWriter pw) { pw.println("\nStream volumes (device: index)"); int numStreamTypes = AudioSystem.getNumStreamTypes(); @@ -4761,7 +4782,7 @@ public class AudioService extends IAudioService.Stub + asDeviceConnectionFailure()); pw.println("\tandroid.media.audio.autoPublicVolumeApiHardening:" + autoPublicVolumeApiHardening()); - pw.println("\tandroid.media.audio.Flags.automaticBtDeviceType:" + pw.println("\tandroid.media.audio.automaticBtDeviceType:" + automaticBtDeviceType()); pw.println("\tandroid.media.audio.featureSpatialAudioHeadtrackingLowLatency:" + featureSpatialAudioHeadtrackingLowLatency()); @@ -4783,6 +4804,8 @@ public class AudioService extends IAudioService.Stub + absVolumeIndexFix()); pw.println("\tcom.android.media.audio.replaceStreamBtSco:" + replaceStreamBtSco()); + pw.println("\tcom.android.media.audio.equalScoLeaVcIndexRange:" + + equalScoLeaVcIndexRange()); } private void dumpAudioMode(PrintWriter pw) { @@ -4896,7 +4919,7 @@ public class AudioService extends IAudioService.Stub final VolumeStreamState streamState = getVssForStreamOrDefault(streamTypeAlias); if (!replaceStreamBtSco() && (streamType == AudioManager.STREAM_VOICE_CALL) - && isInCommunication() && mDeviceBroker.isBluetoothScoActive()) { + && isInCommunication() && mBtCommDeviceActive.get() == BT_COMM_DEVICE_ACTIVE_SCO) { Log.i(TAG, "setStreamVolume for STREAM_VOICE_CALL, switching to STREAM_BLUETOOTH_SCO"); streamType = AudioManager.STREAM_BLUETOOTH_SCO; } @@ -5947,10 +5970,10 @@ public class AudioService extends IAudioService.Stub final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE || ringerMode == AudioManager.RINGER_MODE_SILENT; final boolean shouldRingSco = ringerMode == AudioManager.RINGER_MODE_VIBRATE - && mDeviceBroker.isBluetoothScoActive(); + && mBtCommDeviceActive.get() == BT_COMM_DEVICE_ACTIVE_SCO; final boolean shouldRingBle = ringerMode == AudioManager.RINGER_MODE_VIBRATE - && (mDeviceBroker.isBluetoothBleHeadsetActive() - || mDeviceBroker.isBluetoothBleSpeakerActive()); + && (mBtCommDeviceActive.get() == BT_COMM_DEVICE_ACTIVE_BLE_HEADSET + || mBtCommDeviceActive.get() == BT_COMM_DEVICE_ACTIVE_BLE_SPEAKER); // Ask audio policy engine to force use Bluetooth SCO/BLE channel if needed final String eventSource = "muteRingerModeStreams() from u/pid:" + Binder.getCallingUid() + "/" + Binder.getCallingPid(); @@ -7419,7 +7442,8 @@ public class AudioService extends IAudioService.Stub case AudioSystem.PLATFORM_VOICE: if (isInCommunication() || mAudioSystem.isStreamActive(AudioManager.STREAM_VOICE_CALL, 0)) { - if (!replaceStreamBtSco() && mDeviceBroker.isBluetoothScoActive()) { + if (!replaceStreamBtSco() + && mBtCommDeviceActive.get() == BT_COMM_DEVICE_ACTIVE_SCO) { if (DEBUG_VOL) { Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); } @@ -7463,7 +7487,8 @@ public class AudioService extends IAudioService.Stub } default: if (isInCommunication()) { - if (!replaceStreamBtSco() && mDeviceBroker.isBluetoothScoActive()) { + if (!replaceStreamBtSco() + && mBtCommDeviceActive.get() == BT_COMM_DEVICE_ACTIVE_SCO) { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO"); return AudioSystem.STREAM_BLUETOOTH_SCO; } else { @@ -7788,15 +7813,15 @@ public class AudioService extends IAudioService.Stub 0 /*delay*/); } - /*package*/ void postScoDeviceActive(boolean scoDeviceActive) { + /*package*/ void postBtCommDeviceActive(@BtCommDeviceActiveType int btCommDeviceActive) { sendMsg(mAudioHandler, - MSG_SCO_DEVICE_ACTIVE_UPDATE, - SENDMSG_QUEUE, scoDeviceActive ? 1 : 0 /*arg1*/, 0 /*arg2*/, null /*obj*/, + MSG_BT_COMM_DEVICE_ACTIVE_UPDATE, + SENDMSG_QUEUE, btCommDeviceActive /*arg1*/, 0 /*arg2*/, null /*obj*/, 0 /*delay*/); } - private void onUpdateScoDeviceActive(boolean scoDeviceActive) { - if (mScoDeviceActive.compareAndSet(!scoDeviceActive, scoDeviceActive)) { + private void onUpdateBtCommDeviceActive(@BtCommDeviceActiveType int btCommDeviceActive) { + if (mBtCommDeviceActive.getAndSet(btCommDeviceActive) != btCommDeviceActive) { getVssForStreamOrDefault(AudioSystem.STREAM_VOICE_CALL).updateIndexFactors(); } } @@ -8997,7 +9022,7 @@ public class AudioService extends IAudioService.Stub } public void updateIndexFactors() { - if (!replaceStreamBtSco()) { + if (!replaceStreamBtSco() && !equalScoLeaVcIndexRange()) { return; } @@ -9008,10 +9033,18 @@ public class AudioService extends IAudioService.Stub mIndexMax = MAX_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO] * 10; } - // SCO devices have a different min index - if (isStreamBluetoothSco(mStreamType)) { + if (!equalScoLeaVcIndexRange() && isStreamBluetoothSco(mStreamType)) { + // SCO devices have a different min index mIndexMin = MIN_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO] * 10; mIndexStepFactor = 1.f; + } else if (equalScoLeaVcIndexRange() && isStreamBluetoothComm(mStreamType)) { + // For non SCO devices the stream state does not change the min index + if (mBtCommDeviceActive.get() == BT_COMM_DEVICE_ACTIVE_SCO) { + mIndexMin = MIN_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO] * 10; + } else { + mIndexMin = MIN_STREAM_VOLUME[mStreamType] * 10; + } + mIndexStepFactor = 1.f; } else { mIndexMin = MIN_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] * 10; mIndexStepFactor = (float) (mIndexMax - mIndexMin) / (float) ( @@ -9207,7 +9240,7 @@ public class AudioService extends IAudioService.Stub private void setStreamVolumeIndex(int index, int device) { // Only set audio policy BT SCO stream volume to 0 when the stream is actually muted. // This allows RX path muting by the audio HAL only when explicitly muted but not when - // index is just set to 0 to repect BT requirements + // index is just set to 0 to respect BT requirements if (isStreamBluetoothSco(mStreamType) && index == 0 && !isFullyMuted()) { index = 1; } @@ -10217,8 +10250,8 @@ public class AudioService extends IAudioService.Stub onUpdateContextualVolumes(); break; - case MSG_SCO_DEVICE_ACTIVE_UPDATE: - onUpdateScoDeviceActive(msg.arg1 != 0); + case MSG_BT_COMM_DEVICE_ACTIVE_UPDATE: + onUpdateBtCommDeviceActive(msg.arg1); break; case MusicFxHelper.MSG_EFFECT_CLIENT_GONE: @@ -10809,7 +10842,8 @@ public class AudioService extends IAudioService.Stub //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, diff --git a/services/core/java/com/android/server/audio/HardeningEnforcer.java b/services/core/java/com/android/server/audio/HardeningEnforcer.java index faeba5d068fc..661111070aae 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 @@ public class HardeningEnforcer { } 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 @@ public class HardeningEnforcer { + targetSdk); } blocked = false; + unblockedBySdk = true; } - metricsLogFocusReq(blocked, focusReqType, callingUid); + metricsLogFocusReq(blocked, focusReqType, callingUid, unblockedBySdk); if (!blocked) { return false; @@ -195,7 +198,16 @@ public class HardeningEnforcer { 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 @@ public class HardeningEnforcer { } 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/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java index 5d850896d5de..2d802b21cf03 100644 --- a/services/core/java/com/android/server/biometrics/AuthService.java +++ b/services/core/java/com/android/server/biometrics/AuthService.java @@ -49,7 +49,6 @@ import android.hardware.biometrics.ITestSessionCallback; import android.hardware.biometrics.PromptInfo; import android.hardware.biometrics.SensorLocationInternal; import android.hardware.biometrics.SensorPropertiesInternal; -import android.hardware.biometrics.face.IFace; import android.hardware.face.FaceSensorConfigurations; import android.hardware.face.FaceSensorProperties; import android.hardware.face.FaceSensorPropertiesInternal; @@ -73,6 +72,7 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.server.SystemService; +import com.android.server.biometrics.sensors.face.FaceService; import com.android.server.biometrics.sensors.fingerprint.FingerprintService; import com.android.server.companion.virtual.VirtualDeviceManagerInternal; @@ -211,7 +211,7 @@ public class AuthService extends SystemService { */ @VisibleForTesting public String[] getFaceAidlInstances() { - return ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR); + return FaceService.getDeclaredInstances(); } /** diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java index bd6d59391e4a..8c988729a1ae 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java @@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.face; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.MANAGE_FACE; import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; +import static android.hardware.face.FaceSensorConfigurations.getIFace; import android.annotation.NonNull; import android.annotation.Nullable; @@ -60,6 +61,7 @@ import android.util.proto.ProtoOutputStream; import android.view.Surface; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.widget.LockPatternUtils; import com.android.server.SystemService; @@ -753,7 +755,7 @@ public class FaceService extends SystemService { public FaceService(Context context) { this(context, null /* faceProviderFunction */, () -> IBiometricService.Stub.asInterface( ServiceManager.getService(Context.BIOMETRIC_SERVICE)), null /* faceProvider */, - () -> ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR)); + () -> getDeclaredInstances()); } @VisibleForTesting FaceService(Context context, @@ -778,8 +780,7 @@ public class FaceService extends SystemService { mFaceProvider = faceProvider != null ? faceProvider : (name) -> { final String fqName = IFace.DESCRIPTOR + "/" + name; - final IFace face = IFace.Stub.asInterface( - Binder.allowBlocking(ServiceManager.waitForDeclaredService(fqName))); + final IFace face = getIFace(fqName); if (face == null) { Slog.e(TAG, "Unable to get declared service: " + fqName); return null; @@ -835,6 +836,23 @@ public class FaceService extends SystemService { */ public static native void releaseSurfaceHandle(@NonNull NativeHandle handle); + /** + * Get all face hal instances declared in manifest + * @return instance names + */ + public static String[] getDeclaredInstances() { + String[] a = ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR); + Slog.i(TAG, "Before:getDeclaredInstances: IFace instance found, a.length=" + + a.length); + if (!ArrayUtils.contains(a, "virtual")) { + // Now, the virtual hal is registered with IVirtualHal interface and it is also + // moved from vendor to system_ext partition without a device manifest. So + // if the old vhal is not declared, add here. + a = ArrayUtils.appendElement(String.class, a, "virtual"); + } + Slog.i(TAG, "After:getDeclaredInstances: a.length=" + a.length); + return a; + } void syncEnrollmentsNow() { Utils.checkPermissionOrShell(getContext(), MANAGE_FACE); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java index dca14914a572..3ed01d5a2cc9 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java @@ -23,6 +23,9 @@ import android.hardware.biometrics.ITestSessionCallback; import android.hardware.biometrics.face.AuthenticationFrame; import android.hardware.biometrics.face.BaseFrame; import android.hardware.biometrics.face.EnrollmentFrame; +import android.hardware.biometrics.face.virtualhal.AcquiredInfoAndVendorCode; +import android.hardware.biometrics.face.virtualhal.EnrollmentProgressStep; +import android.hardware.biometrics.face.virtualhal.NextEnrollment; import android.hardware.face.Face; import android.hardware.face.FaceAuthenticationFrame; import android.hardware.face.FaceEnrollFrame; @@ -50,6 +53,7 @@ import java.util.Set; public class BiometricTestSessionImpl extends ITestSession.Stub { private static final String TAG = "face/aidl/BiometricTestSessionImpl"; + private static final int VHAL_ENROLLMENT_ID = 9999; @NonNull private final Context mContext; private final int mSensorId; @@ -144,16 +148,35 @@ public class BiometricTestSessionImpl extends ITestSession.Stub { super.setTestHalEnabled_enforcePermission(); - mProvider.setTestHalEnabled(enabled); mSensor.setTestHalEnabled(enabled); + mProvider.setTestHalEnabled(enabled); } @android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC) @Override - public void startEnroll(int userId) { + public void startEnroll(int userId) throws RemoteException { super.startEnroll_enforcePermission(); + Slog.i(TAG, "startEnroll(): isVhalForTesting=" + mProvider.isVhalForTesting()); + if (mProvider.isVhalForTesting()) { + final AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes = + {new AcquiredInfoAndVendorCode()}; + final EnrollmentProgressStep[] enrollmentProgressSteps = + {new EnrollmentProgressStep(), new EnrollmentProgressStep()}; + enrollmentProgressSteps[0].durationMs = 100; + enrollmentProgressSteps[0].acquiredInfoAndVendorCodes = acquiredInfoAndVendorCodes; + enrollmentProgressSteps[1].durationMs = 200; + enrollmentProgressSteps[1].acquiredInfoAndVendorCodes = acquiredInfoAndVendorCodes; + + final NextEnrollment nextEnrollment = new NextEnrollment(); + nextEnrollment.id = VHAL_ENROLLMENT_ID; + nextEnrollment.progressSteps = enrollmentProgressSteps; + nextEnrollment.result = true; + mProvider.getVhal().setNextEnrollment(nextEnrollment); + mProvider.getVhal().setOperationAuthenticateDuration(6000); + } + mProvider.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver, mContext.getOpPackageName(), new int[0] /* disabledFeatures */, null /* previewSurface */, false /* debugConsent */, @@ -166,6 +189,10 @@ public class BiometricTestSessionImpl extends ITestSession.Stub { super.finishEnroll_enforcePermission(); + if (mProvider.isVhalForTesting()) { + return; + } + int nextRandomId = mRandom.nextInt(); while (mEnrollmentIds.contains(nextRandomId)) { nextRandomId = mRandom.nextInt(); @@ -178,11 +205,16 @@ public class BiometricTestSessionImpl extends ITestSession.Stub { @android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC) @Override - public void acceptAuthentication(int userId) { + public void acceptAuthentication(int userId) throws RemoteException { // Fake authentication with any of the existing faces super.acceptAuthentication_enforcePermission(); + if (mProvider.isVhalForTesting()) { + mProvider.getVhal().setEnrollmentHit(VHAL_ENROLLMENT_ID); + return; + } + List<Face> faces = FaceUtils.getInstance(mSensorId) .getBiometricsForUser(mContext, userId); if (faces.isEmpty()) { @@ -196,10 +228,15 @@ public class BiometricTestSessionImpl extends ITestSession.Stub { @android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC) @Override - public void rejectAuthentication(int userId) { + public void rejectAuthentication(int userId) throws RemoteException { super.rejectAuthentication_enforcePermission(); + if (mProvider.isVhalForTesting()) { + mProvider.getVhal().setEnrollmentHit(VHAL_ENROLLMENT_ID + 1); + return; + } + mSensor.getSessionForUser(userId).getHalSessionCallback().onAuthenticationFailed(); } @@ -236,11 +273,17 @@ public class BiometricTestSessionImpl extends ITestSession.Stub { @android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC) @Override - public void cleanupInternalState(int userId) { + public void cleanupInternalState(int userId) throws RemoteException { super.cleanupInternalState_enforcePermission(); Slog.d(TAG, "cleanupInternalState: " + userId); + + if (mProvider.isVhalForTesting()) { + Slog.i(TAG, "cleanup virtualhal configurations"); + mProvider.getVhal().resetConfigurations(); //setEnrollments(new int[]{}); + } + mProvider.scheduleInternalCleanup(mSensorId, userId, new ClientMonitorCallback() { @Override public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java index bb213bfa79e6..5127e68a9df3 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java @@ -16,6 +16,9 @@ package com.android.server.biometrics.sensors.face.aidl; +import static android.hardware.face.FaceSensorConfigurations.getIFace; +import static android.hardware.face.FaceSensorConfigurations.remapFqName; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -32,6 +35,7 @@ import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; import android.hardware.biometrics.face.IFace; import android.hardware.biometrics.face.SensorProps; +import android.hardware.biometrics.face.virtualhal.IVirtualHal; import android.hardware.face.Face; import android.hardware.face.FaceAuthenticateOptions; import android.hardware.face.FaceEnrollOptions; @@ -54,6 +58,7 @@ import com.android.server.biometrics.AuthenticationStatsBroadcastReceiver; import com.android.server.biometrics.AuthenticationStatsCollector; import com.android.server.biometrics.BiometricDanglingReceiver; import com.android.server.biometrics.BiometricHandlerProvider; +import com.android.server.biometrics.Flags; import com.android.server.biometrics.Utils; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.log.BiometricLogger; @@ -130,6 +135,11 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { private AuthenticationStatsCollector mAuthenticationStatsCollector; @Nullable private IFace mDaemon; + @Nullable + private IVirtualHal mVhal; + @Nullable + private String mHalInstanceNameCurrent; + private final class BiometricTaskStackListener extends TaskStackListener { @Override @@ -286,14 +296,37 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { if (mTestHalEnabled) { return true; } - return ServiceManager.checkService(IFace.DESCRIPTOR + "/" + mHalInstanceName) != null; + return ServiceManager.checkService( + remapFqName(IFace.DESCRIPTOR + "/" + mHalInstanceName)) != null; } @Nullable @VisibleForTesting synchronized IFace getHalInstance() { if (mTestHalEnabled) { - return new TestHal(); + if (Flags.useVhalForTesting()) { + if (!mHalInstanceNameCurrent.contains("virtual")) { + Slog.i(getTag(), "Switching face hal from " + mHalInstanceName + + " to virtual hal"); + mHalInstanceNameCurrent = "virtual"; + mDaemon = null; + } + } else { + // Enabling the test HAL for a single sensor in a multi-sensor HAL currently enables + // the test HAL for all sensors under that HAL. This can be updated in the future if + // necessary. + return new TestHal(); + } + } else { + if (mHalInstanceNameCurrent == null) { + mHalInstanceNameCurrent = mHalInstanceName; + } else if (mHalInstanceNameCurrent.contains("virtual") + && mHalInstanceNameCurrent != mHalInstanceName) { + Slog.i(getTag(), "Switching face from virtual hal " + "to " + + mHalInstanceName); + mHalInstanceNameCurrent = mHalInstanceName; + mDaemon = null; + } } if (mDaemon != null) { @@ -302,10 +335,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { Slog.d(getTag(), "Daemon was null, reconnecting"); - mDaemon = IFace.Stub.asInterface( - Binder.allowBlocking( - ServiceManager.waitForDeclaredService( - IFace.DESCRIPTOR + "/" + mHalInstanceName))); + mDaemon = getIFace(IFace.DESCRIPTOR + "/" + mHalInstanceNameCurrent); if (mDaemon == null) { Slog.e(getTag(), "Unable to get daemon"); return null; @@ -833,7 +863,13 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { } void setTestHalEnabled(boolean enabled) { + final boolean changed = enabled != mTestHalEnabled; mTestHalEnabled = enabled; + Slog.i(getTag(), "setTestHalEnabled(): isVhalForTestingFlags=" + Flags.useVhalForTesting() + + " mTestHalEnabled=" + mTestHalEnabled + " changed=" + changed); + if (changed && isVhalForTesting()) { + getHalInstance(); + } } @Override @@ -851,9 +887,40 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { } /** + * Return true if vhal_for_testing feature is enabled and test is active + */ + public boolean isVhalForTesting() { + return (Flags.useVhalForTesting() && mTestHalEnabled); + } + + + /** * Sends a face re enroll notification. */ public void sendFaceReEnrollNotification() { mAuthenticationStatsCollector.sendFaceReEnrollNotification(); } + + /** + * Sends a fingerprint enroll notification. + */ + public void sendFingerprintReEnrollNotification() { + mAuthenticationStatsCollector.sendFingerprintReEnrollNotification(); + } + + /** + * Return virtual hal AIDL interface if it is used for testing + * + */ + public IVirtualHal getVhal() throws RemoteException { + if (mVhal == null && isVhalForTesting()) { + mVhal = IVirtualHal.Stub.asInterface( + Binder.allowBlocking( + ServiceManager.waitForService( + IVirtualHal.DESCRIPTOR + "/" + + mHalInstanceNameCurrent))); + Slog.d(getTag(), "getVhal " + mHalInstanceNameCurrent); + } + return mVhal; + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java index 6f9534993a3f..9fddcfc199b9 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java @@ -17,6 +17,7 @@ package com.android.server.biometrics.sensors.face.aidl; import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE; +import static android.hardware.face.FaceSensorConfigurations.remapFqName; import android.annotation.NonNull; import android.annotation.Nullable; @@ -337,7 +338,8 @@ public class Sensor { if (mTestHalEnabled) { return true; } - return ServiceManager.checkService(IFace.DESCRIPTOR + "/" + halInstanceName) != null; + return ServiceManager.checkService( + remapFqName(IFace.DESCRIPTOR + "/" + halInstanceName)) != null; } /** diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java index 86015acc232f..774041152d3e 100644 --- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java +++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java @@ -1279,8 +1279,9 @@ public class AutomaticBrightnessController { private boolean shouldApplyDozeScaleFactor() { // We don't apply the doze scale factor if we have a designated brightness curve for doze. return (mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled() - ? !mUseNormalBrightnessForDoze && mDisplayPolicy == POLICY_DOZE - : Display.isDozeState(mDisplayState)) && getMode() != AUTO_BRIGHTNESS_MODE_DOZE; + ? (!mUseNormalBrightnessForDoze && mDisplayPolicy == POLICY_DOZE) + || Display.isDozeState(mDisplayState) : Display.isDozeState(mDisplayState)) + && getMode() != AUTO_BRIGHTNESS_MODE_DOZE; } private class ShortTermModel { diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index e7fd8f7db182..ae33b83b49dc 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -571,6 +571,10 @@ public final class DisplayManagerService extends SystemService { private final DisplayNotificationManager mDisplayNotificationManager; private final ExternalDisplayStatsService mExternalDisplayStatsService; + // Manages the relative placement of extended displays + @Nullable + private final DisplayTopologyCoordinator mDisplayTopologyCoordinator; + /** * Applications use {@link android.view.Display#getRefreshRate} and * {@link android.view.Display.Mode#getRefreshRate} to know what is the display refresh rate. @@ -644,6 +648,11 @@ public final class DisplayManagerService extends SystemService { mDisplayNotificationManager = new DisplayNotificationManager(mFlags, mContext, mExternalDisplayStatsService); mExternalDisplayPolicy = new ExternalDisplayPolicy(new ExternalDisplayPolicyInjector()); + if (mFlags.isDisplayTopologyEnabled()) { + mDisplayTopologyCoordinator = new DisplayTopologyCoordinator(); + } else { + mDisplayTopologyCoordinator = null; + } } public void setupSchedulerPolicies() { @@ -3474,9 +3483,13 @@ public final class DisplayManagerService extends SystemService { mSmallAreaDetectionController.dump(pw); } + if (mDisplayTopologyCoordinator != null) { + pw.println(); + mDisplayTopologyCoordinator.dump(pw); + } + pw.println(); mFlags.dump(pw); - } private static float[] getFloatArray(TypedArray array) { diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 04573f4b7514..711bc7972091 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -1357,6 +1357,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mDisplayStateController.shouldPerformScreenOffTransition()); state = mPowerState.getScreenState(); + // Use doze brightness if one of following is true: + // 1. The target `state` isDozeState. + // 2. Doze power request(POLICY_DOZE) if there's no exception(useNormalBrightnessForDoze). + final boolean useDozeBrightness = mFlags.isNormalBrightnessForDozeParameterEnabled() + ? (!mPowerRequest.useNormalBrightnessForDoze && mPowerRequest.policy == POLICY_DOZE) + || Display.isDozeState(state) : Display.isDozeState(state); + DisplayBrightnessState displayBrightnessState = mDisplayBrightnessController .updateBrightness(mPowerRequest, state, mDisplayOffloadSession); float brightnessState = displayBrightnessState.getBrightness(); @@ -1399,7 +1406,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call && !mAutomaticBrightnessController.isInIdleMode()) { // Set sendUpdate to false, we're already in updatePowerState() so there's no need // to trigger it again - mAutomaticBrightnessController.switchMode(Display.isDozeState(state) + mAutomaticBrightnessController.switchMode(useDozeBrightness ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT, /* sendUpdate= */ false); } @@ -1472,9 +1479,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call brightnessState = clampScreenBrightness(brightnessState); } - if (mFlags.isNormalBrightnessForDozeParameterEnabled() - ? !mPowerRequest.useNormalBrightnessForDoze && mPowerRequest.policy == POLICY_DOZE - : Display.isDozeState(state)) { + if (useDozeBrightness) { // TODO(b/329676661): Introduce a config property to choose between this brightness // strategy and DOZE_DEFAULT // On some devices, when auto-brightness is disabled and the device is dozing, we use diff --git a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java new file mode 100644 index 000000000000..631f14755b12 --- /dev/null +++ b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.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.android.server.display; + +import android.annotation.Nullable; +import android.util.IndentingPrintWriter; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +/** + * This class manages the relative placement (topology) of extended displays. It is responsible for + * updating and persisting the topology. + */ +class DisplayTopologyCoordinator { + + /** + * The topology tree + */ + @Nullable + private TopologyTreeNode mRoot; + + /** + * The logical display ID of the primary display that will show certain UI elements. + * This is not necessarily the same as the default display. + */ + private int mPrimaryDisplayId; + + /** + * Print the object's state and debug information into the given stream. + * @param pw The stream to dump information to. + */ + public void dump(PrintWriter pw) { + pw.println("DisplayTopologyCoordinator:"); + pw.println("--------------------"); + IndentingPrintWriter ipw = new IndentingPrintWriter(pw); + ipw.increaseIndent(); + + ipw.println("mPrimaryDisplayId: " + mPrimaryDisplayId); + + ipw.println("Topology tree:"); + if (mRoot != null) { + ipw.increaseIndent(); + mRoot.dump(ipw); + ipw.decreaseIndent(); + } + } + + private static class TopologyTreeNode { + + /** + * The logical display ID + */ + private int mDisplayId; + + private final List<TopologyTreeNode> mChildren = new ArrayList<>(); + + /** + * The position of this display relative to its parent. + */ + private Position mPosition; + + /** + * The distance from the top edge of the parent display to the top edge of this display (in + * case of POSITION_LEFT or POSITION_RIGHT) or from the left edge of the parent display + * to the left edge of this display (in case of POSITION_TOP or POSITION_BOTTOM). The unit + * used is density-independent pixels (dp). + */ + private double mOffset; + + /** + * Print the object's state and debug information into the given stream. + * @param ipw The stream to dump information to. + */ + void dump(IndentingPrintWriter ipw) { + ipw.println("Display {id=" + mDisplayId + ", position=" + mPosition + + ", offset=" + mOffset + "}"); + ipw.increaseIndent(); + for (TopologyTreeNode child : mChildren) { + child.dump(ipw); + } + ipw.decreaseIndent(); + } + + private enum Position { + POSITION_LEFT, POSITION_TOP, POSITION_RIGHT, POSITION_BOTTOM + } + } +} diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java index bf01f2d9c749..2fdec78bbbda 100644 --- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java +++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java @@ -510,10 +510,10 @@ public class AutomaticBrightnessStrategy extends AutomaticBrightnessStrategy2 && mAutomaticBrightnessController != null && !mAutomaticBrightnessController.isInIdleMode()) { - boolean shouldUseDozeMode = + final boolean shouldUseDozeMode = mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled() - ? !useNormalBrightnessForDoze && policy == POLICY_DOZE - : Display.isDozeState(state); + ? (!useNormalBrightnessForDoze && policy == POLICY_DOZE) + || Display.isDozeState(state) : Display.isDozeState(state); mAutomaticBrightnessController.switchMode(shouldUseDozeMode ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT, sendUpdate); } diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java index f600e7fc2946..df66893a2f35 100644 --- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java @@ -69,6 +69,10 @@ public class DisplayManagerFlags { Flags.FLAG_ENABLE_MODE_LIMIT_FOR_EXTERNAL_DISPLAY, Flags::enableModeLimitForExternalDisplay); + private final FlagState mDisplayTopology = new FlagState( + Flags.FLAG_DISPLAY_TOPOLOGY, + Flags::displayTopology); + private final FlagState mConnectedDisplayErrorHandlingFlagState = new FlagState( Flags.FLAG_ENABLE_CONNECTED_DISPLAY_ERROR_HANDLING, Flags::enableConnectedDisplayErrorHandling); @@ -266,6 +270,10 @@ public class DisplayManagerFlags { return mExternalDisplayLimitModeState.isEnabled(); } + public boolean isDisplayTopologyEnabled() { + return mDisplayTopology.isEnabled(); + } + /** * @return Whether displays refresh rate synchronization is enabled. */ @@ -441,6 +449,7 @@ public class DisplayManagerFlags { pw.println(" " + mConnectedDisplayManagementFlagState); pw.println(" " + mDisplayOffloadFlagState); pw.println(" " + mExternalDisplayLimitModeState); + pw.println(" " + mDisplayTopology); pw.println(" " + mHdrClamperFlagState); pw.println(" " + mNbmControllerFlagState); pw.println(" " + mPowerThrottlingClamperFlagState); diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig index 9968ba57bba4..e3ebe5bcd9ed 100644 --- a/services/core/java/com/android/server/display/feature/display_flags.aconfig +++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig @@ -92,6 +92,14 @@ flag { } flag { + name: "display_topology" + namespace: "display_manager" + description: "Display topology for moving cursors and windows between extended displays" + bug: "278199220" + is_fixed_read_only: true +} + +flag { name: "enable_displays_refresh_rates_synchronization" namespace: "display_manager" description: "Enables synchronization of refresh rates across displays" diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 101596d9d7c1..aae7b59b1a1a 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -261,6 +261,7 @@ public class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { .setDisplayName(HdmiUtils.getDefaultDeviceName(source)) .setDeviceType(deviceTypes.get(0)) .setVendorId(Constants.VENDOR_ID_UNKNOWN) + .setPortId(mService.getHdmiCecNetwork().physicalAddressToPortId(physicalAddress)) .build(); mService.getHdmiCecNetwork().addCecDevice(newDevice); } @@ -1433,6 +1434,7 @@ public class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) { assertRunOnServiceThread(); mService.unregisterTvInputCallback(mTvInputCallback); + mTvInputs.clear(); // Remove any repeated working actions. // HotplugDetectionAction will be reinstated during the wake up process. // HdmiControlService.onWakeUp() -> initializeLocalDevices() -> diff --git a/services/core/java/com/android/server/input/KeyRemapper.java b/services/core/java/com/android/server/input/KeyRemapper.java index 7ba77698cb5d..82b36aff5273 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 @@ final class KeyRemapper implements InputManager.InputDeviceListener { 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 @@ final class KeyRemapper implements InputManager.InputDeviceListener { } 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 @@ final class KeyRemapper implements InputManager.InputDeviceListener { } } - 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 @@ final class KeyRemapper implements InputManager.InputDeviceListener { } finally { mDataStore.saveIfNeeded(); } + setKeyRemapping(mDataStore.getKeyRemapping()); } } @@ -123,45 +115,25 @@ final class KeyRemapper implements InputManager.InputDeviceListener { 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 5dd461dda061..d17e256e34fc 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 @@ interface NativeInputManagerService { 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); @@ -311,7 +311,7 @@ interface NativeInputManagerService { 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, 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 0e940d281b09..a1e5ebc002a5 100644 --- a/services/core/java/com/android/server/input/debug/TouchpadDebugView.java +++ b/services/core/java/com/android/server/input/debug/TouchpadDebugView.java @@ -24,7 +24,6 @@ import android.content.res.Configuration; import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Rect; -import android.hardware.input.InputManager; import android.util.Slog; import android.util.TypedValue; import android.view.Gravity; @@ -42,6 +41,7 @@ import com.android.server.input.TouchpadHardwareProperties; import com.android.server.input.TouchpadHardwareState; import java.util.Objects; +import java.util.function.Consumer; public class TouchpadDebugView extends LinearLayout { private static final float MAX_SCREEN_WIDTH_PROPORTION = 0.4f; @@ -52,7 +52,8 @@ public class TouchpadDebugView extends LinearLayout { 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. */ @@ -74,22 +75,24 @@ public class TouchpadDebugView extends LinearLayout { private int mWindowLocationBeforeDragX; private int mWindowLocationBeforeDragY; private int mLatestGestureType = 0; + private TouchpadSelectionView mTouchpadSelectionView; + private TouchpadVisualizationView mTouchpadVisualizationView; private TextView mGestureInfoView; @NonNull private TouchpadHardwareState mLastTouchpadState = new TouchpadHardwareState(0, 0 /* buttonsDown */, 0, 0, new TouchpadFingerState[0]); - private TouchpadVisualizationView mTouchpadVisualizationView; private final TouchpadHardwareProperties mTouchpadHardwareProperties; public TouchpadDebugView(Context context, int touchpadId, - TouchpadHardwareProperties touchpadHardwareProperties) { + TouchpadHardwareProperties touchpadHardwareProperties, + Consumer<Integer> touchpadSwitchHandler) { super(context); mTouchpadId = touchpadId; mWindowManager = Objects.requireNonNull(getContext().getSystemService(WindowManager.class)); mTouchpadHardwareProperties = touchpadHardwareProperties; - init(context, touchpadId); + init(context, touchpadId, touchpadSwitchHandler); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mWindowLayoutParams = new WindowManager.LayoutParams(); @@ -111,7 +114,8 @@ public class TouchpadDebugView extends LinearLayout { mWindowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT; } - private void init(Context context, int touchpadId) { + private void init(Context context, int touchpadId, + Consumer<Integer> touchpadSwitchHandler) { updateScreenDimensions(); setOrientation(VERTICAL); setLayoutParams(new LayoutParams( @@ -119,35 +123,31 @@ public class TouchpadDebugView extends LinearLayout { 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( - mContext.getSystemService(InputManager.class)) - .getInputDevice(touchpadId)).getName()); - nameView.setGravity(Gravity.CENTER); - nameView.setTextColor(Color.WHITE); + mTouchpadSelectionView = new TouchpadSelectionView(context, + touchpadId, touchpadSwitchHandler); + mTouchpadSelectionView.setBackgroundColor(BUTTON_RELEASED_BACKGROUND_COLOR); + mTouchpadSelectionView.setGravity(Gravity.CENTER); int paddingInDP = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, TEXT_PADDING_DP, getResources().getDisplayMetrics()); - nameView.setPadding(paddingInDP, paddingInDP, paddingInDP, paddingInDP); - nameView.setLayoutParams( + mTouchpadSelectionView.setPadding(paddingInDP, paddingInDP, paddingInDP, paddingInDP); + mTouchpadSelectionView.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)); + //TODO(b/369061237): Handle longer text - addView(nameView); + updateTheme(getResources().getConfiguration().uiMode); + + addView(mTouchpadSelectionView); addView(mTouchpadVisualizationView); addView(mGestureInfoView); @@ -239,6 +239,8 @@ public class TouchpadDebugView extends LinearLayout { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); + + updateTheme(newConfig.uiMode); updateScreenDimensions(); updateViewsDimensions(); @@ -250,6 +252,27 @@ public class TouchpadDebugView extends LinearLayout { 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; } @@ -333,12 +356,12 @@ public class TouchpadDebugView extends LinearLayout { private void onTouchpadButtonPress() { Slog.d(TAG, "You clicked me!"); - getChildAt(0).setBackgroundColor(Color.BLUE); + mTouchpadSelectionView.setBackgroundColor(BUTTON_PRESSED_BACKGROUND_COLOR); } private void onTouchpadButtonRelease() { Slog.d(TAG, "You released the click"); - getChildAt(0).setBackgroundColor(Color.RED); + mTouchpadSelectionView.setBackgroundColor(BUTTON_RELEASED_BACKGROUND_COLOR); } /** diff --git a/services/core/java/com/android/server/input/debug/TouchpadDebugViewController.java b/services/core/java/com/android/server/input/debug/TouchpadDebugViewController.java index cb43977d9911..9cfbfa649e1c 100644 --- a/services/core/java/com/android/server/input/debug/TouchpadDebugViewController.java +++ b/services/core/java/com/android/server/input/debug/TouchpadDebugViewController.java @@ -16,6 +16,7 @@ package com.android.server.input.debug; +import android.annotation.AnyThread; import android.annotation.Nullable; import android.content.Context; import android.hardware.input.InputManager; @@ -45,8 +46,8 @@ public class TouchpadDebugViewController implements InputManager.InputDeviceList private boolean mTouchpadVisualizerEnabled = false; public TouchpadDebugViewController(Context context, Looper looper, - InputManagerService inputManagerService) { - //TODO(b/363979581): Handle multi-display scenarios + InputManagerService inputManagerService) { + //TODO(b/369059937): Handle multi-display scenarios mContext = context; mHandler = new Handler(looper); mInputManagerService = inputManagerService; @@ -77,6 +78,14 @@ public class TouchpadDebugViewController implements InputManager.InputDeviceList } } + /** + * Switch to showing the touchpad with the given device ID + */ + public void switchVisualisationToTouchpadId(int newDeviceId) { + if (mTouchpadDebugView != null) hideDebugView(mTouchpadDebugView.getTouchpadId()); + showDebugView(newDeviceId); + } + @Override public void onInputDeviceChanged(int deviceId) { } @@ -117,7 +126,7 @@ public class TouchpadDebugViewController implements InputManager.InputDeviceList touchpadId); mTouchpadDebugView = new TouchpadDebugView(mContext, touchpadId, - touchpadHardwareProperties); + touchpadHardwareProperties, this::switchVisualisationToTouchpadId); final WindowManager.LayoutParams mWindowLayoutParams = mTouchpadDebugView.getWindowLayoutParams(); @@ -149,19 +158,28 @@ public class TouchpadDebugViewController implements InputManager.InputDeviceList * @param touchpadHardwareState the hardware state of a touchpad * @param deviceId the deviceId of the touchpad that is sending the hardware state */ + @AnyThread public void updateTouchpadHardwareState(TouchpadHardwareState touchpadHardwareState, - int deviceId) { - if (mTouchpadDebugView != null) { - mTouchpadDebugView.updateHardwareState(touchpadHardwareState, deviceId); - } + int deviceId) { + mHandler.post(() -> { + if (mTouchpadDebugView != null) { + mTouchpadDebugView.post( + () -> mTouchpadDebugView.updateHardwareState(touchpadHardwareState, + deviceId)); + } + }); } /** * Notify the TouchpadDebugView of a new touchpad gesture. */ + @AnyThread public void updateTouchpadGestureInfo(int gestureType, int deviceId) { - if (mTouchpadDebugView != null) { - mTouchpadDebugView.updateGestureInfo(gestureType, deviceId); - } + mHandler.post(() -> { + if (mTouchpadDebugView != null) { + mTouchpadDebugView.post( + () -> mTouchpadDebugView.updateGestureInfo(gestureType, deviceId)); + } + }); } } diff --git a/services/core/java/com/android/server/input/debug/TouchpadSelectionView.java b/services/core/java/com/android/server/input/debug/TouchpadSelectionView.java new file mode 100644 index 000000000000..05217b6ab1e0 --- /dev/null +++ b/services/core/java/com/android/server/input/debug/TouchpadSelectionView.java @@ -0,0 +1,111 @@ +/* + * 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.input.debug; + +import android.content.Context; +import android.graphics.Color; +import android.hardware.input.InputManager; +import android.view.Gravity; +import android.view.InputDevice; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.PopupMenu; +import android.widget.TextView; + +import java.util.Objects; +import java.util.function.Consumer; + +public class TouchpadSelectionView extends LinearLayout { + private static final float TEXT_SIZE_SP = 16.0f; + + int mCurrentTouchpadId; + + public TouchpadSelectionView(Context context, int touchpadId, + Consumer<Integer> touchpadSwitchHandler) { + super(context); + mCurrentTouchpadId = touchpadId; + init(context, touchpadSwitchHandler); + } + + private void init(Context context, Consumer<Integer> touchpadSwitchHandler) { + setOrientation(HORIZONTAL); + setLayoutParams(new LayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT)); + setBackgroundColor(Color.TRANSPARENT); + + TextView nameView = new TextView(context); + nameView.setTextSize(TEXT_SIZE_SP); + nameView.setText(getTouchpadName(mCurrentTouchpadId)); + nameView.setGravity(Gravity.LEFT); + nameView.setTextColor(Color.WHITE); + + LayoutParams textParams = new LayoutParams( + LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + textParams.rightMargin = 16; + nameView.setLayoutParams(textParams); + + ImageButton arrowButton = new ImageButton(context); + arrowButton.setImageDrawable(context.getDrawable(android.R.drawable.arrow_down_float)); + arrowButton.setForegroundGravity(Gravity.RIGHT); + arrowButton.setBackgroundColor(Color.TRANSPARENT); + arrowButton.setLayoutParams(new LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + + arrowButton.setOnClickListener(v -> showPopupMenu(v, context, touchpadSwitchHandler)); + + addView(nameView); + addView(arrowButton); + } + + private void showPopupMenu(View anchorView, Context context, + Consumer<Integer> touchpadSwitchHandler) { + int i = 0; + PopupMenu popupMenu = new PopupMenu(context, anchorView); + + final InputManager inputManager = Objects.requireNonNull( + mContext.getSystemService(InputManager.class)); + for (int deviceId : inputManager.getInputDeviceIds()) { + InputDevice inputDevice = inputManager.getInputDevice(deviceId); + if (Objects.requireNonNull(inputDevice).supportsSource( + InputDevice.SOURCE_TOUCHPAD | InputDevice.SOURCE_MOUSE)) { + popupMenu.getMenu().add(0, deviceId, i, getTouchpadName(deviceId)); + i++; + } + } + + popupMenu.setOnMenuItemClickListener(item -> { + if (item.getItemId() == mCurrentTouchpadId) { + return false; + } + + touchpadSwitchHandler.accept(item.getItemId()); + return true; + }); + + popupMenu.show(); + } + + private String getTouchpadName(int touchpadId) { + return Objects.requireNonNull(Objects.requireNonNull( + mContext.getSystemService(InputManager.class)) + .getInputDevice(touchpadId)).getName(); + } +} 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 2eed9ba95413..eeec5ccdecf6 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 @@ package com.android.server.input.debug; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.Slog; @@ -29,6 +30,7 @@ import com.android.server.input.TouchpadHardwareState; import java.util.ArrayDeque; import java.util.HashMap; +import java.util.Locale; import java.util.Map; public class TouchpadVisualizationView extends View { @@ -49,6 +51,7 @@ public class TouchpadVisualizationView extends View { private final Paint mOvalFillPaint; private final Paint mTracePaint; private final Paint mCenterPointPaint; + private final Paint mPressureTextPaint; private final RectF mTempOvalRect = new RectF(); public TouchpadVisualizationView(Context context, @@ -58,11 +61,9 @@ public class TouchpadVisualizationView extends View { 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); @@ -72,6 +73,8 @@ public class TouchpadVisualizationView extends View { mCenterPointPaint.setAntiAlias(true); mCenterPointPaint.setARGB(255, 255, 0, 0); mCenterPointPaint.setStrokeWidth(2); + mPressureTextPaint = new Paint(); + mPressureTextPaint.setAntiAlias(true); } private void removeOldPoints() { @@ -135,6 +138,13 @@ public class TouchpadVisualizationView extends View { mOvalFillPaint.setAlpha((int) pressureToOpacity); drawOval(canvas, newX, newY, newTouchMajor, newTouchMinor, newAngle); + + String formattedPressure = String.format(Locale.getDefault(), "Ps: %.2f", + touchpadFingerState.getPressure()); + float textWidth = mPressureTextPaint.measureText(formattedPressure); + + canvas.drawText(formattedPressure, newX - textWidth / 2, + newY - newTouchMajor / 2, mPressureTextPaint); } mTempFingerStatesByTrackingId.clear(); @@ -195,6 +205,26 @@ public class TouchpadVisualizationView extends View { 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)); + mPressureTextPaint.setARGB(255, 255, 255, 255); + 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)); + mPressureTextPaint.setARGB(255, 0, 0, 0); + 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/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index ba7d4d218ca5..dc62b27dec05 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -33,6 +33,7 @@ import static android.app.Notification.EXTRA_LARGE_ICON_BIG; import static android.app.Notification.EXTRA_SUB_TEXT; import static android.app.Notification.EXTRA_TEXT; import static android.app.Notification.EXTRA_TEXT_LINES; +import static android.app.Notification.EXTRA_TITLE; import static android.app.Notification.EXTRA_TITLE_BIG; import static android.app.Notification.FLAG_AUTOGROUP_SUMMARY; import static android.app.Notification.FLAG_AUTO_CANCEL; @@ -45,6 +46,7 @@ import static android.app.Notification.FLAG_NO_CLEAR; import static android.app.Notification.FLAG_NO_DISMISS; import static android.app.Notification.FLAG_ONGOING_EVENT; import static android.app.Notification.FLAG_ONLY_ALERT_ONCE; +import static android.app.Notification.FLAG_PROMOTED_ONGOING; import static android.app.Notification.FLAG_USER_INITIATED_JOB; import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT; import static android.app.NotificationChannel.NEWS_ID; @@ -3516,7 +3518,7 @@ public class NotificationManagerService extends SystemService { private String getHistoryTitle(Notification n) { CharSequence title = null; if (n.extras != null) { - title = n.extras.getCharSequence(Notification.EXTRA_TITLE); + title = n.extras.getCharSequence(EXTRA_TITLE); if (title == null) { title = n.extras.getCharSequence(EXTRA_TITLE_BIG); } @@ -4114,6 +4116,75 @@ public class NotificationManagerService extends SystemService { } @Override + @FlaggedApi(android.app.Flags.FLAG_UI_RICH_ONGOING) + public boolean canBePromoted(String pkg, int uid) { + checkCallerIsSystemOrSystemUiOrShell(); + if (!android.app.Flags.uiRichOngoing()) { + return false; + } + return mPreferencesHelper.canBePromoted(pkg, uid); + } + + @Override + @FlaggedApi(android.app.Flags.FLAG_UI_RICH_ONGOING) + public void setCanBePromoted(String pkg, int uid, boolean promote) { + checkCallerIsSystemOrSystemUiOrShell(); + if (!android.app.Flags.uiRichOngoing()) { + return; + } + boolean changed = mPreferencesHelper.setCanBePromoted(pkg, uid, promote); + if (changed) { + // check for pending/posted notifs from this app and update the flag + synchronized (mNotificationLock) { + // for enqueued we just need to update the flag + List<NotificationRecord> enqueued = findAppNotificationByListLocked( + mEnqueuedNotifications, pkg, UserHandle.getUserId(uid)); + for (NotificationRecord r : enqueued) { + if (promote + && r.getNotification().hasPromotableCharacteristics() + && r.getImportance() > IMPORTANCE_MIN) { + r.getNotification().flags |= FLAG_PROMOTED_ONGOING; + } else if (!promote) { + r.getNotification().flags &= ~FLAG_PROMOTED_ONGOING; + } + } + // if the notification is posted we need to update the flag and tell listeners + List<NotificationRecord> posted = findAppNotificationByListLocked( + mNotificationList, pkg, UserHandle.getUserId(uid)); + for (NotificationRecord r : posted) { + if (promote + && !hasFlag(r.getNotification().flags, FLAG_PROMOTED_ONGOING) + && r.getNotification().hasPromotableCharacteristics() + && r.getImportance() > IMPORTANCE_MIN) { + r.getNotification().flags |= FLAG_PROMOTED_ONGOING; + // we could set a wake lock here but this value should only change + // in response to user action, so the device should be awake long enough + // to post + PostNotificationTracker tracker = + mPostNotificationTrackerFactory.newTracker(null); + // Set false for isAppForeground because that field is only used + // for bubbles and messagingstyle can not be promoted + mHandler.post(new EnqueueNotificationRunnable( + r.getUser().getIdentifier(), + r, /* isAppForeground */ false, /* isAppProvided= */ false, + tracker)); + } else if (!promote + && hasFlag(r.getNotification().flags, FLAG_PROMOTED_ONGOING)){ + r.getNotification().flags &= ~FLAG_PROMOTED_ONGOING; + PostNotificationTracker tracker = + mPostNotificationTrackerFactory.newTracker(null); + mHandler.post(new EnqueueNotificationRunnable( + r.getUser().getIdentifier(), + r, /* isAppForeground */ false, /* isAppProvided= */ false, + tracker)); + } + } + } + handleSavePolicyFile(); + } + } + + @Override public boolean hasSentValidMsg(String pkg, int uid) { checkCallerIsSystem(); return mPreferencesHelper.hasSentValidMsg(pkg, uid); @@ -6795,6 +6866,9 @@ public class NotificationManagerService extends SystemService { if (notificationForceGrouping()) { if (r.getSbn().isAppGroup()) { mListeners.notifyPostedLocked(r, r); + + mNotificationRecordLogger.log( + NotificationRecordLogger.NotificationEvent.NOTIFICATION_FORCE_GROUP, r); } } } @@ -6975,6 +7049,10 @@ public class NotificationManagerService extends SystemService { // Clear summary flag StatusBarNotification sbn = r.getSbn(); sbn.getNotification().flags = (r.mOriginalFlags & ~FLAG_GROUP_SUMMARY); + + EventLogTags.writeNotificationSummaryConverted(key); + mNotificationRecordLogger.log( + NotificationRecordLogger.NotificationEvent.NOTIFICATION_FORCE_GROUP_SUMMARY, r); return true; } return false; @@ -7698,6 +7776,16 @@ public class NotificationManagerService extends SystemService { return false; } + if (android.app.Flags.uiRichOngoing()) { + // This would normally be done in fixNotification(), but we need the channel info so + // it's done a little late + if (mPreferencesHelper.canBePromoted(pkg, notificationUid) + && notification.hasPromotableCharacteristics() + && channel.getImportance() > IMPORTANCE_MIN) { + notification.flags |= FLAG_PROMOTED_ONGOING; + } + } + final NotificationRecord r = new NotificationRecord(getContext(), n, channel); r.setIsAppImportanceLocked(mPermissionHelper.isPermissionUserSet(pkg, userId)); r.setPostSilently(postSilently); @@ -7938,6 +8026,9 @@ public class NotificationManagerService extends SystemService { } } + // Apps cannot set this flag + notification.flags &= ~FLAG_PROMOTED_ONGOING; + // Ensure CallStyle has all the correct actions if (notification.isStyle(Notification.CallStyle.class)) { Notification.Builder builder = @@ -8061,12 +8152,7 @@ public class NotificationManagerService extends SystemService { private void checkRemoteViews(String pkg, String tag, int id, Notification notification) { if (android.app.Flags.removeRemoteViews()) { - if (notification.contentView != null || notification.bigContentView != null - || notification.headsUpContentView != null - || (notification.publicVersion != null - && (notification.publicVersion.contentView != null - || notification.publicVersion.bigContentView != null - || notification.publicVersion.headsUpContentView != null))) { + if (notification.containsCustomViews()) { Slog.i(TAG, "Removed customViews for " + pkg); mUsageStats.registerImageRemoved(pkg); } @@ -9236,8 +9322,8 @@ public class NotificationManagerService extends SystemService { } } - final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE)); - final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE)); + final String oldTitle = String.valueOf(oldN.extras.get(EXTRA_TITLE)); + final String newTitle = String.valueOf(newN.extras.get(EXTRA_TITLE)); if (!Objects.equals(oldTitle, newTitle)) { if (DEBUG_INTERRUPTIVENESS) { Slog.v(TAG, "INTERRUPTIVENESS: " @@ -10654,6 +10740,22 @@ public class NotificationManagerService extends SystemService { } @GuardedBy("mNotificationLock") + @FlaggedApi(android.app.Flags.FLAG_UI_RICH_ONGOING) + private @NonNull List<NotificationRecord> findAppNotificationByListLocked( + ArrayList<NotificationRecord> list, String pkg, int userId) { + List<NotificationRecord> records = new ArrayList<>(); + final int len = list.size(); + for (int i = 0; i < len; i++) { + NotificationRecord r = list.get(i); + if (notificationMatchesUserId(r, userId, false) + && r.getSbn().getPackageName().equals(pkg)) { + records.add(r); + } + } + return records; + } + + @GuardedBy("mNotificationLock") private @NonNull List<NotificationRecord> findGroupNotificationByListLocked( ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) { List<NotificationRecord> records = new ArrayList<>(); diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java index 65ef53f1df14..3943aa583fee 100644 --- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java +++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java @@ -313,7 +313,11 @@ interface NotificationRecordLogger { @UiEvent(doc = "Notification assistant generated notification action at 1 was clicked.") NOTIFICATION_ASSIST_ACTION_CLICKED_1(457), @UiEvent(doc = "Notification assistant generated notification action at 2 was clicked.") - NOTIFICATION_ASSIST_ACTION_CLICKED_2(458); + NOTIFICATION_ASSIST_ACTION_CLICKED_2(458), + @UiEvent(doc = "Notification was force autogrouped.") + NOTIFICATION_FORCE_GROUP(1843), + @UiEvent(doc = "Notification summary was force autogrouped.") + NOTIFICATION_FORCE_GROUP_SUMMARY(1844); private final int mId; NotificationEvent(int id) { diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index a4fdb758a740..fcc8d2f74ce9 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -41,6 +41,7 @@ import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_P import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED; import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -162,6 +163,7 @@ public class PreferencesHelper implements RankingConfig { private static final String ATT_SENT_VALID_MESSAGE = "sent_valid_msg"; private static final String ATT_USER_DEMOTED_INVALID_MSG_APP = "user_demote_msg_app"; private static final String ATT_SENT_VALID_BUBBLE = "sent_valid_bubble"; + private static final String ATT_PROMOTE_NOTIFS = "promote"; private static final String ATT_CREATION_TIME = "creation_time"; @@ -351,6 +353,10 @@ public class PreferencesHelper implements RankingConfig { r.userDemotedMsgApp = parser.getAttributeBoolean( null, ATT_USER_DEMOTED_INVALID_MSG_APP, false); r.hasSentValidBubble = parser.getAttributeBoolean(null, ATT_SENT_VALID_BUBBLE, false); + if (android.app.Flags.uiRichOngoing()) { + r.canHavePromotedNotifs = + parser.getAttributeBoolean(null, ATT_PROMOTE_NOTIFS, false); + } final int innerDepth = parser.getDepth(); int type; @@ -739,6 +745,11 @@ public class PreferencesHelper implements RankingConfig { out.attributeBoolean(null, ATT_USER_DEMOTED_INVALID_MSG_APP, r.userDemotedMsgApp); out.attributeBoolean(null, ATT_SENT_VALID_BUBBLE, r.hasSentValidBubble); + if (android.app.Flags.uiRichOngoing()) { + if (r.canHavePromotedNotifs) { + out.attributeBoolean(null, ATT_PROMOTE_NOTIFS, r.canHavePromotedNotifs); + } + } if (Flags.persistIncompleteRestoreData() && r.uid == UNKNOWN_UID) { out.attributeLong(null, ATT_CREATION_TIME, r.creationTime); @@ -839,6 +850,28 @@ public class PreferencesHelper implements RankingConfig { } } + @FlaggedApi(android.app.Flags.FLAG_UI_RICH_ONGOING) + public boolean canBePromoted(String packageName, int uid) { + synchronized (mLock) { + return getOrCreatePackagePreferencesLocked(packageName, uid).canHavePromotedNotifs; + } + } + + @FlaggedApi(android.app.Flags.FLAG_UI_RICH_ONGOING) + public boolean setCanBePromoted(String packageName, int uid, boolean promote) { + boolean changed = false; + synchronized (mLock) { + PackagePreferences pkgPrefs = getOrCreatePackagePreferencesLocked(packageName, uid); + if (pkgPrefs.canHavePromotedNotifs != promote) { + pkgPrefs.canHavePromotedNotifs = promote; + changed = true; + } + } + // no need to send a ranking update because we need to update the flag value on all pending + // and posted notifs and NMS will take care of that + return changed; + } + public boolean isInInvalidMsgState(String packageName, int uid) { synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid); @@ -2180,6 +2213,10 @@ public class PreferencesHelper implements RankingConfig { pw.print(" fixedImportance="); pw.print(r.fixedImportance); } + if (android.app.Flags.uiRichOngoing() && r.canHavePromotedNotifs) { + pw.print(" promoted="); + pw.print(r.canHavePromotedNotifs); + } pw.println(); for (NotificationChannel channel : r.channels.values()) { pw.print(prefix); @@ -3028,6 +3065,9 @@ public class PreferencesHelper implements RankingConfig { boolean migrateToPm = false; long creationTime; + @FlaggedApi(android.app.Flags.FLAG_UI_RICH_ONGOING) + boolean canHavePromotedNotifs = false; + @UserIdInt int userId; Delegate delegate = null; diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index e9db1b529a63..626c3ddd49d9 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 @@ public class ZenModeHelper { 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. @@ -1721,7 +1722,7 @@ public class ZenModeHelper { // booleans to determine whether to reset the rules to the default rules boolean allRulesDisabled = true; boolean hasDefaultRules = config.automaticRules.containsAll( - ZenModeConfig.DEFAULT_RULE_IDS); + ZenModeConfig.getDefaultRuleIds()); long time = Flags.modesApi() ? mClock.millis() : System.currentTimeMillis(); if (config.automaticRules != null && config.automaticRules.size() > 0) { @@ -1773,7 +1774,7 @@ public class ZenModeHelper { // 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"; } @@ -1798,6 +1799,14 @@ public class ZenModeHelper { config.deletedRules.clear(); } + if (Flags.modesUi() && config.automaticRules != null) { + ZenRule obsoleteEventsRule = config.automaticRules.get( + ZenModeConfig.EVENTS_OBSOLETE_RULE_ID); + if (obsoleteEventsRule != null && !obsoleteEventsRule.enabled) { + config.automaticRules.remove(ZenModeConfig.EVENTS_OBSOLETE_RULE_ID); + } + } + if (DEBUG) Log.d(TAG, reason); synchronized (mConfigLock) { setConfigLocked(config, null, @@ -2256,7 +2265,7 @@ public class ZenModeHelper { private static void updateRuleStringsForCurrentLocale(Context context, ZenModeConfig defaultConfig) { for (ZenRule rule : defaultConfig.automaticRules.values()) { - if (ZenModeConfig.EVENTS_DEFAULT_RULE_ID.equals(rule.id)) { + if (ZenModeConfig.EVENTS_OBSOLETE_RULE_ID.equals(rule.id)) { rule.name = context.getResources() .getString(R.string.zen_mode_default_events_name); } else if (ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID.equals(rule.id)) { @@ -2278,7 +2287,7 @@ public class ZenModeHelper { } ZenPolicy defaultPolicy = defaultConfig.getZenPolicy(); for (ZenRule rule : defaultConfig.automaticRules.values()) { - if (ZenModeConfig.DEFAULT_RULE_IDS.contains(rule.id) && rule.zenPolicy == null) { + if (ZenModeConfig.getDefaultRuleIds().contains(rule.id) && rule.zenPolicy == null) { rule.zenPolicy = defaultPolicy.copy(); } } @@ -2482,7 +2491,7 @@ public class ZenModeHelper { List<StatsEvent> events) { // Make the ID safe. String id = rule.id == null ? "" : rule.id; - if (!ZenModeConfig.DEFAULT_RULE_IDS.contains(id)) { + if (!ZenModeConfig.getDefaultRuleIds().contains(id)) { id = ""; } diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index efd58ed6edcc..5653da07779b 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -1674,18 +1674,32 @@ public class LauncherAppsService extends SystemService { @Override public PendingIntent getActivityLaunchIntent(String callingPackage, ComponentName component, UserHandle user) { + try { + Log.d(TAG, + "getActivityLaunchIntent callingPackage=" + callingPackage + " component=" + + component + " user=" + user); + } catch (Exception e) { + Log.e(TAG, "getActivityLaunchIntent is called and error occurred when" + + " printing the logs", e); + } if (mContext.checkPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS, injectBinderCallingPid(), injectBinderCallingUid()) != PackageManager.PERMISSION_GRANTED) { + Log.d(TAG, "getActivityLaunchIntent no permission callingPid=" + + injectBinderCallingPid() + " callingUid=" + injectBinderCallingUid()); throw new SecurityException("Permission START_TASKS_FROM_RECENTS required"); } if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) { + Log.d(TAG, "getActivityLaunchIntent cannot access profile user=" + + user.getIdentifier()); throw new ActivityNotFoundException("Activity could not be found"); } final Intent launchIntent = getMainActivityLaunchIntent(component, user, false /* includeArchivedApps */); if (launchIntent == null) { + Log.d(TAG, "getActivityLaunchIntent cannot access profile user=" + + user.getIdentifier() + " component=" + component); throw new SecurityException("Attempt to launch activity without " + " category Intent.CATEGORY_LAUNCHER " + component); } @@ -1965,6 +1979,17 @@ public class LauncherAppsService extends SystemService { canLaunch = true; } if (!canLaunch) { + try { + Log.w(TAG, "getMainActivityLaunchIntent return null because it can't launch" + + " component=" + component + " user=" + user + " appsSize=" + size + + " includeArchivedApps=" + includeArchivedApps + + " isArchivingEnabled=" + isArchivingEnabled() + + " matchingArchivedAppActivityInfo=" + + getMatchingArchivedAppActivityInfo(component, user)); + } catch (Exception e) { + Log.e(TAG, "getMainActivityLaunchIntent return null and error occurred when" + + " printing the logs", e); + } return null; } } finally { diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 60056eb471d1..6f50295cc8d5 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -912,12 +912,13 @@ class ShortcutPackage extends ShortcutPackageItem { * available ShareTarget definitions in this package. */ public List<ShortcutManager.ShareShortcutInfo> getMatchingShareTargets( - @NonNull final IntentFilter filter) { - return getMatchingShareTargets(filter, null); + @NonNull final IntentFilter filter, final int callingUserId) { + return getMatchingShareTargets(filter, null, callingUserId); } List<ShortcutManager.ShareShortcutInfo> getMatchingShareTargets( - @NonNull final IntentFilter filter, @Nullable final String pkgName) { + @NonNull final IntentFilter filter, @Nullable final String pkgName, + final int callingUserId) { synchronized (mPackageItemLock) { final List<ShareTargetInfo> matchedTargets = new ArrayList<>(); for (int i = 0; i < mShareTargets.size(); i++) { @@ -941,7 +942,7 @@ class ShortcutPackage extends ShortcutPackageItem { // included in the result findAll(shortcuts, ShortcutInfo::isNonManifestVisible, ShortcutInfo.CLONE_REMOVE_FOR_APP_PREDICTION, - pkgName, 0, /*getPinnedByAnyLauncher=*/ false); + pkgName, callingUserId, /*getPinnedByAnyLauncher=*/ false); final List<ShortcutManager.ShareShortcutInfo> result = new ArrayList<>(); for (int i = 0; i < shortcuts.size(); i++) { diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index a3ff1952205f..5518bfae8277 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -2591,7 +2591,8 @@ public class ShortcutService extends IShortcutService.Stub { final List<ShortcutManager.ShareShortcutInfo> shortcutInfoList = new ArrayList<>(); final ShortcutUser user = getUserShortcutsLocked(userId); user.forAllPackages(p -> shortcutInfoList.addAll( - p.getMatchingShareTargets(filter, pkg))); + p.getMatchingShareTargets(filter, pkg, + mUserManagerInternal.getProfileParentId(userId)))); return new ParceledListSlice<>(shortcutInfoList); } } @@ -2623,7 +2624,8 @@ public class ShortcutService extends IShortcutService.Stub { final List<ShortcutManager.ShareShortcutInfo> matchedTargets = getPackageShortcutsLocked(packageName, userId) - .getMatchingShareTargets(filter); + .getMatchingShareTargets(filter, + mUserManagerInternal.getProfileParentId(callingUserId)); final int matchedSize = matchedTargets.size(); for (int i = 0; i < matchedSize; i++) { if (matchedTargets.get(i).getShortcutInfo().getId().equals(shortcutId)) { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 89417f3765ff..8bab9de903ba 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 @@ public class UserManagerService extends IUserManager.Stub { if (android.multiuser.Flags.cachesNotInvalidatedAtStartReadOnly()) { UserManager.invalidateIsUserUnlockedCache(); UserManager.invalidateQuietModeEnabledCache(); - UserManager.invalidateStaticUserProperties(); - UserManager.invalidateUserPropertiesCache(); UserManager.invalidateUserSerialNumberCache(); } } @@ -2647,11 +2645,15 @@ public class UserManagerService extends IUserManager.Stub { } @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 46207c1860c0..b43ddaa92562 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 @@ public final class UserVisibilityMediator implements Dumpable { 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 @@ public final class UserVisibilityMediator implements Dumpable { 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 63491e8434bf..ca6051874d78 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -37,6 +37,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.O; import static android.os.IInputConstants.INVALID_INPUT_DEVICE_ID; +import static android.os.UserManager.isVisibleBackgroundUsersEnabled; import static android.provider.Settings.Secure.VOLUME_HUSH_OFF; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; @@ -184,6 +185,7 @@ import android.service.dreams.IDreamManager; import android.service.vr.IPersistentVrStateCallbacks; import android.speech.RecognizerIntent; import android.telecom.TelecomManager; +import android.util.ArraySet; import android.util.Log; import android.util.MathUtils; import android.util.MutableBoolean; @@ -256,6 +258,7 @@ import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -718,6 +721,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Timeout for showing the keyguard after the screen is on, in case no "ready" is received. private int mKeyguardDrawnTimeout = 1000; + private final boolean mVisibleBackgroundUsersEnabled = isVisibleBackgroundUsersEnabled(); + + // Key codes that should be ignored for visible background users in MUMD environment. + private static final Set<Integer> KEY_CODES_IGNORED_FOR_VISIBLE_BACKGROUND_USERS = + new ArraySet<>(Arrays.asList( + KeyEvent.KEYCODE_POWER, + KeyEvent.KEYCODE_SLEEP, + KeyEvent.KEYCODE_WAKEUP, + KeyEvent.KEYCODE_CALL, + KeyEvent.KEYCODE_ENDCALL, + KeyEvent.KEYCODE_ASSIST, + KeyEvent.KEYCODE_VOICE_ASSIST, + KeyEvent.KEYCODE_MUTE, + KeyEvent.KEYCODE_VOLUME_MUTE + )); + private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3; private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4; private static final int MSG_KEYGUARD_DRAWN_COMPLETE = 5; @@ -811,7 +830,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { event.recycle(); break; case MSG_HANDLE_ALL_APPS: - launchAllAppsAction(); + KeyEvent keyEvent = (KeyEvent) msg.obj; + if (isKeyEventForCurrentUser(keyEvent.getDisplayId(), keyEvent.getKeyCode(), + "launchAllAppsViaA11y")) { + launchAllAppsAction(); + } break; case MSG_RINGER_TOGGLE_CHORD: handleRingerChordGesture(); @@ -2082,7 +2105,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { switch (mLongPressOnHomeBehavior) { case LONG_PRESS_HOME_ALL_APPS: notifyKeyGestureCompleted(event, KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS); - launchAllAppsAction(); + if (isKeyEventForCurrentUser(event.getDisplayId(), event.getKeyCode(), + "launchAllAppsViaA11y")) { + launchAllAppsAction(); + } break; case LONG_PRESS_HOME_ASSIST: notifyKeyGestureCompleted(event, @@ -3763,7 +3789,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK); } else if (mPendingMetaAction) { if (!canceled) { - launchAllAppsAction(); + if (isKeyEventForCurrentUser(event.getDisplayId(), event.getKeyCode(), + "launchAllAppsViaA11y")) { + launchAllAppsAction(); + } notifyKeyGestureCompleted(event, KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS); } @@ -4030,7 +4059,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return true; case KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS: case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS: - if (complete) { + if (complete && isKeyEventForCurrentUser(event.getDisplayId(), + event.getKeycodes()[0], "launchAllAppsViaA11y")) { launchAllAppsAction(); } return true; @@ -4859,6 +4889,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0 || event.isWakeKey(); + // There are key events that perform the operation as the current user, + // and these should be ignored for visible background users. + if (mVisibleBackgroundUsersEnabled + && KEY_CODES_IGNORED_FOR_VISIBLE_BACKGROUND_USERS.contains(keyCode) + && !isKeyEventForCurrentUser(event.getDisplayId(), keyCode, null)) { + return 0; + } + if (!mSystemBooted) { // If we have not yet booted, don't let key events do anything. // Exception: Wake and power key events are forwarded to PowerManager to allow it to @@ -5866,6 +5904,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private void wakeUpFromWakeKey(KeyEvent event) { + if (!isKeyEventForCurrentUser( + event.getDisplayId(), event.getKeyCode(), "wakeUpFromWakeKey")) { + return; + } wakeUpFromWakeKey( event.getEventTime(), event.getKeyCode(), @@ -6445,6 +6487,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { // TODO (b/113840485): Move this logic to DisplayPolicy when lockscreen supports multi-display. @Override public void setAllowLockscreenWhenOn(int displayId, boolean allow) { + // We should ignore this operation for visible background users + // until lockscreen supports multi-display. + if (mVisibleBackgroundUsersEnabled + && mUserManagerInternal.getUserAssignedToDisplay(displayId) != mCurrentUserId) { + return; + } if (allow) { mAllowLockscreenWhenOnDisplays.add(displayId); } else { @@ -7253,4 +7301,29 @@ public class PhoneWindowManager implements WindowManagerPolicy { } return DEFAULT_DISPLAY; } + + /** + * This method is intended to prevent key events for visible background users + * from interfering with the current user's experience in MUMD environment. + * + * @param displayId the displayId of the key event. + * @param keyCode the key code of the event. + * + * @return false if the key event is for a visible background user. + */ + private boolean isKeyEventForCurrentUser(int displayId, int keyCode, @Nullable String purpose) { + if (!mVisibleBackgroundUsersEnabled) { + return true; + } + int assignedUser = mUserManagerInternal.getUserAssignedToDisplay(displayId); + if (assignedUser == mCurrentUserId) { + return true; + } + if (DEBUG_INPUT) { + Slog.w(TAG, "Cannot handle " + KeyEvent.keyCodeToString(keyCode) + + (purpose != null ? " to " + purpose : "") + + " for visible background user(u" + assignedUser + ")"); + } + return false; + } } diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 71cb8820761f..e0539647d061 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -2207,7 +2207,7 @@ public final class PowerManagerService extends SystemService + ", groupId=" + powerGroup.getGroupId() + ", reason=" + PowerManager.wakeReasonToString(reason) + ", uid=" + uid); } - if (mForceSuspendActive || !mSystemReady) { + if (mForceSuspendActive || !mSystemReady || (powerGroup == null)) { return; } powerGroup.wakeUpLocked(eventTime, reason, details, uid, opPackageName, opUid, @@ -6027,6 +6027,12 @@ public final class PowerManagerService extends SystemService @Override // Binder call public void wakeUp(long eventTime, @WakeReason int reason, String details, String opPackageName) { + wakeUpWithDisplayId(eventTime, reason, details, opPackageName, Display.DEFAULT_DISPLAY); + } + + @Override // Binder call + public void wakeUpWithDisplayId(long eventTime, @WakeReason int reason, String details, + String opPackageName, int displayId) { final long now = mClock.uptimeMillis(); if (eventTime > now) { Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now); @@ -6039,13 +6045,14 @@ public final class PowerManagerService extends SystemService final int uid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); try { + int displayGroupId = getDisplayGroupId(displayId); synchronized (mLock) { if (!mBootCompleted && sQuiescent) { mDirty |= DIRTY_QUIESCENT; updatePowerStateLocked(); return; } - wakePowerGroupLocked(mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP), eventTime, + wakePowerGroupLocked(mPowerGroups.get(displayGroupId), eventTime, reason, details, uid, opPackageName, uid); } } finally { @@ -7335,4 +7342,12 @@ public final class PowerManagerService extends SystemService } } } + + private int getDisplayGroupId(int displayId) { + DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(displayId); + if (displayInfo == null) { + return Display.INVALID_DISPLAY_GROUP; + } + return displayInfo.displayGroupId; + } } diff --git a/services/core/java/com/android/server/power/PowerManagerShellCommand.java b/services/core/java/com/android/server/power/PowerManagerShellCommand.java index 20184e9fd1a7..f69a017fc45a 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 @@ class PowerManagerShellCommand extends ShellCommand { 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 @@ class PowerManagerShellCommand extends ShellCommand { 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 @@ class PowerManagerShellCommand extends ShellCommand { 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 @@ class PowerManagerShellCommand extends ShellCommand { 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 e3d71e4998be..f78c4488cbfb 100644 --- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -81,7 +81,7 @@ import java.util.function.Consumer; 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 String CLASS_NAME = RollbackPackageHealthObserver.class.getName(); private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT | ApplicationInfo.FLAG_SYSTEM; @@ -610,14 +610,16 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } }; + String intentActionName = CLASS_NAME + rollback.getRollbackId(); // Register the BroadcastReceiver mContext.registerReceiver(rollbackReceiver, - new IntentFilter(ACTION_NAME), + new IntentFilter(intentActionName), Context.RECEIVER_NOT_EXPORTED); - Intent intentReceiver = new Intent(ACTION_NAME); + Intent intentReceiver = new Intent(intentActionName); intentReceiver.putExtra("rollbackId", rollback.getRollbackId()); intentReceiver.setPackage(mContext.getPackageName()); + intentReceiver.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); PendingIntent rollbackPendingIntent = PendingIntent.getBroadcast(mContext, rollback.getRollbackId(), diff --git a/services/core/java/com/android/server/security/forensic/OWNERS b/services/core/java/com/android/server/security/forensic/OWNERS new file mode 100644 index 000000000000..3bc3eb5d1412 --- /dev/null +++ b/services/core/java/com/android/server/security/forensic/OWNERS @@ -0,0 +1 @@ +file:platform/frameworks/base:main:/core/java/android/security/forensic/OWNERS diff --git a/services/core/java/com/android/server/utils/AnrTimer.java b/services/core/java/com/android/server/utils/AnrTimer.java index 153bb917d188..1ba2487566ba 100644 --- a/services/core/java/com/android/server/utils/AnrTimer.java +++ b/services/core/java/com/android/server/utils/AnrTimer.java @@ -130,22 +130,35 @@ public abstract class AnrTimer<V> implements AutoCloseable { } /** - * Return true if freezing is enabled. This has no effect if the service is not enabled. + * Return true if freezing is feature-enabled. Freezing must still be enabled on a + * per-service basis. */ - private static boolean anrTimerFreezerEnabled() { + private static boolean freezerFeatureEnabled() { return Flags.anrTimerFreezer(); } /** + * Return true if tracing is feature-enabled. This has no effect unless tracing is configured. + * Note that this does not represent any per-process overrides via an Injector. + */ + public static boolean traceFeatureEnabled() { + return anrTimerServiceEnabled() && Flags.anrTimerTrace(); + } + + /** * This class allows test code to provide instance-specific overrides. */ static class Injector { - boolean anrTimerServiceEnabled() { + boolean serviceEnabled() { return AnrTimer.anrTimerServiceEnabled(); } - boolean anrTimerFreezerEnabled() { - return AnrTimer.anrTimerFreezerEnabled(); + boolean freezerEnabled() { + return AnrTimer.freezerFeatureEnabled(); + } + + boolean traceEnabled() { + return AnrTimer.traceFeatureEnabled(); } } @@ -349,7 +362,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { mWhat = what; mLabel = label; mArgs = args; - boolean enabled = args.mInjector.anrTimerServiceEnabled() && nativeTimersSupported(); + boolean enabled = args.mInjector.serviceEnabled() && nativeTimersSupported(); mFeature = createFeatureSwitch(enabled); } @@ -448,7 +461,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** * The FeatureDisabled class bypasses almost all AnrTimer logic. It is used when the AnrTimer - * service is disabled via Flags.anrTimerServiceEnabled. + * service is disabled via Flags.anrTimerService(). */ private class FeatureDisabled extends FeatureSwitch { /** Start a timer by sending a message to the client's handler. */ @@ -515,7 +528,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** * The FeatureEnabled class enables the AnrTimer logic. It is used when the AnrTimer service - * is enabled via Flags.anrTimerServiceEnabled. + * is enabled via Flags.anrTimerService(). */ private class FeatureEnabled extends FeatureSwitch { @@ -533,7 +546,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { FeatureEnabled() { mNative = nativeAnrTimerCreate(mLabel, mArgs.mExtend, - mArgs.mFreeze && mArgs.mInjector.anrTimerFreezerEnabled()); + mArgs.mFreeze && mArgs.mInjector.freezerEnabled()); if (mNative == 0) throw new IllegalArgumentException("unable to create native timer"); synchronized (sAnrTimerList) { sAnrTimerList.put(mNative, new WeakReference(AnrTimer.this)); @@ -550,7 +563,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { // exist. if (cancel(arg)) mTotalRestarted++; - int timerId = nativeAnrTimerStart(mNative, pid, uid, timeoutMs); + final int timerId = nativeAnrTimerStart(mNative, pid, uid, timeoutMs); if (timerId > 0) { mTimerIdMap.put(arg, timerId); mTimerArgMap.put(timerId, arg); @@ -895,7 +908,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** Dumpsys output, allowing for overrides. */ @VisibleForTesting static void dump(@NonNull PrintWriter pw, boolean verbose, @NonNull Injector injector) { - if (!injector.anrTimerServiceEnabled()) return; + if (!injector.serviceEnabled()) return; final IndentingPrintWriter ipw = new IndentingPrintWriter(pw); ipw.println("AnrTimer statistics"); @@ -926,6 +939,18 @@ public abstract class AnrTimer<V> implements AutoCloseable { } /** + * Set a trace specification. The input is a set of strings. On success, the function pushes + * the trace specification to all timers, and then returns a response message. On failure, + * the function throws IllegalArgumentException and tracing is disabled. + * + * An empty specification has no effect other than returning the current trace specification. + */ + @Nullable + public static String traceTimers(@Nullable String[] spec) { + return nativeAnrTimerTrace(spec); + } + + /** * Return true if the native timers are supported. Native timers are supported if the method * nativeAnrTimerSupported() can be executed and it returns true. */ @@ -981,6 +1006,15 @@ public abstract class AnrTimer<V> implements AutoCloseable { */ private static native boolean nativeAnrTimerRelease(long service, int timerId); + /** + * Configure tracing. The input array is a set of words pulled from the command line. All + * parsing happens inside the native layer. The function returns a string which is either an + * error message (so nothing happened) or the current configuration after applying the config. + * Passing an null array or an empty array simply returns the current configuration. + * The function returns null if the native layer is not implemented. + */ + private static native @Nullable String nativeAnrTimerTrace(@Nullable String[] config); + /** Retrieve runtime dump information from the native layer. */ private static native String[] nativeAnrTimerDump(long service); } diff --git a/services/core/java/com/android/server/utils/flags.aconfig b/services/core/java/com/android/server/utils/flags.aconfig index 00ebb6691c4a..333287fd4069 100644 --- a/services/core/java/com/android/server/utils/flags.aconfig +++ b/services/core/java/com/android/server/utils/flags.aconfig @@ -17,3 +17,10 @@ flag { bug: "325594551" } +flag { + name: "anr_timer_trace" + namespace: "system_performance" + is_fixed_read_only: true + description: "When true, start a trace if an ANR timer reaches 50%" + bug: "352085328" +} diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index ccc9b17ff840..12d733fc8c1a 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2641,9 +2641,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return true; } // Only do transfer after transaction has done when starting window exist. - if (mStartingData != null && mStartingData.mWaitForSyncTransactionCommit) { - mStartingData.mRemoveAfterTransaction = AFTER_TRANSACTION_COPY_TO_CLIENT; - return true; + if (mStartingData != null) { + final boolean isWaitingForSyncTransactionCommit = + Flags.removeStartingWindowWaitForMultiTransitions() + ? getSyncTransactionCommitCallbackDepth() > 0 + : mStartingData.mWaitForSyncTransactionCommit; + if (isWaitingForSyncTransactionCommit) { + mStartingData.mRemoveAfterTransaction = AFTER_TRANSACTION_COPY_TO_CLIENT; + return true; + } } requestCopySplashScreen(); return isTransferringSplashScreen(); @@ -2847,7 +2853,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final boolean animate; final boolean hasImeSurface; if (mStartingData != null) { - if (mStartingData.mWaitForSyncTransactionCommit + final boolean isWaitingForSyncTransactionCommit = + Flags.removeStartingWindowWaitForMultiTransitions() + ? getSyncTransactionCommitCallbackDepth() > 0 + : mStartingData.mWaitForSyncTransactionCommit; + if (isWaitingForSyncTransactionCommit || mSyncState != SYNC_STATE_NONE) { mStartingData.mRemoveAfterTransaction = AFTER_TRANSACTION_REMOVE_DIRECTLY; mStartingData.mPrepareRemoveAnimation = prepareAnimation; diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index bc11bacf8200..d29ff540e391 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1749,12 +1749,13 @@ class ActivityStarter { mIntent.setFlags(mLaunchFlags); boolean dreamStopping = false; - - for (ActivityRecord stoppingActivity : mSupervisor.mStoppingActivities) { - if (stoppingActivity.getActivityType() - == WindowConfiguration.ACTIVITY_TYPE_DREAM) { - dreamStopping = true; - break; + if (!com.android.window.flags.Flags.removeActivityStarterDreamCallback()) { + for (ActivityRecord stoppingActivity : mSupervisor.mStoppingActivities) { + if (stoppingActivity.getActivityType() + == WindowConfiguration.ACTIVITY_TYPE_DREAM) { + dreamStopping = true; + break; + } } } @@ -1878,8 +1879,21 @@ class ActivityStarter { if (mDoResume) { if (!avoidMoveToFront()) { mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask); - if (!mTargetRootTask.isTopRootTaskInDisplayArea() && mService.isDreaming() - && !dreamStopping) { + + final boolean launchBehindDream; + if (com.android.window.flags.Flags.removeActivityStarterDreamCallback()) { + final TaskDisplayArea tda = mTargetRootTask.getTaskDisplayArea(); + final Task top = (tda != null ? tda.getTopRootTask() : null); + launchBehindDream = (top != null && top != mTargetRootTask) + && top.getActivityType() == WindowConfiguration.ACTIVITY_TYPE_DREAM + && top.getTopNonFinishingActivity() != null; + } else { + launchBehindDream = !mTargetRootTask.isTopRootTaskInDisplayArea() + && mService.isDreaming() + && !dreamStopping; + } + + if (launchBehindDream) { // Launching underneath dream activity (fullscreen, always-on-top). Run the // launch--behind transition so the Activity gets created and starts // in visible state. diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java index e178203fed92..8cc2fd1bb88d 100644 --- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java @@ -132,15 +132,15 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { } @Override - protected boolean isLeashReadyForDispatching(InsetsControlTarget target) { + protected boolean isLeashReadyForDispatching() { if (android.view.inputmethod.Flags.refactorInsetsController()) { final WindowState ws = mWindowContainer != null ? mWindowContainer.asWindowState() : null; final boolean isDrawn = ws != null && ws.isDrawn(); - return super.isLeashReadyForDispatching(target) + return super.isLeashReadyForDispatching() && mServerVisible && isDrawn && mGivenInsetsReady; } else { - return super.isLeashReadyForDispatching(target); + return super.isLeashReadyForDispatching(); } } @@ -636,7 +636,7 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { sb.append(", leash is: ").append(hasLeash ? "non-null" : "null"); if (!hasLeash) { sb.append(", control is: ").append(mControl != null ? "non-null" : "null"); - sb.append(", mIsLeashReadyForDispatching: ").append(mIsLeashReadyForDispatching); + sb.append(", mIsLeashInitialized: ").append(mIsLeashInitialized); } sb.append(", isImeLayeringTarget: "); sb.append(isImeLayeringTarget(mImeRequester, dcTarget)); diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index f0a4763796e3..4f8332a49750 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -71,11 +71,12 @@ class InsetsSourceProvider { protected @Nullable WindowContainer mWindowContainer; protected @Nullable InsetsSourceControl mControl; protected @Nullable InsetsControlTarget mControlTarget; - protected boolean mIsLeashReadyForDispatching; + protected boolean mIsLeashInitialized; private final Rect mTmpRect = new Rect(); private final InsetsSourceControl mFakeControl; - private final Consumer<Transaction> mSetLeashPositionConsumer; + private final Point mPosition = new Point(); + private final Consumer<Transaction> mSetControlPositionConsumer; private @Nullable InsetsControlTarget mPendingControlTarget; private @Nullable InsetsControlTarget mFakeControlTarget; @@ -126,13 +127,14 @@ class InsetsSourceProvider { source.getId(), source.getType(), null /* leash */, false /* initialVisible */, new Point(), Insets.NONE); mControllable = (InsetsPolicy.CONTROLLABLE_TYPES & source.getType()) != 0; - mSetLeashPositionConsumer = t -> { - if (mControl != null) { - final SurfaceControl leash = mControl.getLeash(); - if (leash != null) { - final Point position = mControl.getSurfacePosition(); - t.setPosition(leash, position.x, position.y); - } + mSetControlPositionConsumer = t -> { + if (mControl == null || mControlTarget == null) { + return; + } + boolean changed = mControl.setSurfacePosition(mPosition.x, mPosition.y); + final SurfaceControl leash = mControl.getLeash(); + if (changed && leash != null) { + t.setPosition(leash, mPosition.x, mPosition.y); } if (mHasPendingPosition) { mHasPendingPosition = false; @@ -140,9 +142,22 @@ class InsetsSourceProvider { mStateController.notifyControlTargetChanged(mPendingControlTarget, this); } } + changed |= updateInsetsHint(); + if (changed) { + mStateController.notifyControlChanged(mControlTarget, this); + } }; } + private boolean updateInsetsHint() { + final Insets insetsHint = getInsetsHint(); + if (!mControl.getInsetsHint().equals(insetsHint)) { + mControl.setInsetsHint(insetsHint); + return true; + } + return false; + } + InsetsSource getSource() { return mSource; } @@ -363,26 +378,32 @@ class InsetsSourceProvider { } final boolean serverVisibleChanged = mServerVisible != isServerVisible; setServerVisible(isServerVisible); - updateInsetsControlPosition(windowState, serverVisibleChanged); - } - - void updateInsetsControlPosition(WindowState windowState) { - updateInsetsControlPosition(windowState, false); + final boolean positionChanged = updateInsetsControlPosition(windowState); + if (mControl != null && !positionChanged + // The insets hint would be updated if the position is changed. Here updates it for + // the possible change of the bounds or the server visibility. + && (updateInsetsHint() + || serverVisibleChanged + && android.view.inputmethod.Flags.refactorInsetsController())) { + // Only call notifyControlChanged here when the position is not changed. Otherwise, it + // is called or is scheduled to be called during updateInsetsControlPosition. + mStateController.notifyControlChanged(mControlTarget, this); + } } - private void updateInsetsControlPosition(WindowState windowState, - boolean serverVisibleChanged) { + /** + * @return {#code true} if the surface position of the control is changed. + */ + boolean updateInsetsControlPosition(WindowState windowState) { if (mControl == null) { - return; + return false; } - boolean changed = false; final Point position = getWindowFrameSurfacePosition(); - if (mControl.setSurfacePosition(position.x, position.y) && mControlTarget != null) { - changed = true; + if (!mPosition.equals(position)) { + mPosition.set(position.x, position.y); if (windowState != null && windowState.getWindowFrames().didFrameSizeChange() && windowState.mWinAnimator.getShown() && mWindowContainer.okToDisplay()) { - mHasPendingPosition = true; - windowState.applyWithNextDraw(mSetLeashPositionConsumer); + windowState.applyWithNextDraw(mSetControlPositionConsumer); } else { Transaction t = mWindowContainer.getSyncTransaction(); if (windowState != null) { @@ -399,20 +420,11 @@ class InsetsSourceProvider { } } } - mSetLeashPositionConsumer.accept(t); + mSetControlPositionConsumer.accept(t); } + return true; } - final Insets insetsHint = getInsetsHint(); - if (!mControl.getInsetsHint().equals(insetsHint)) { - mControl.setInsetsHint(insetsHint); - changed = true; - } - if (android.view.inputmethod.Flags.refactorInsetsController() && serverVisibleChanged) { - changed = true; - } - if (changed) { - mStateController.notifyControlChanged(mControlTarget, this); - } + return false; } private Point getWindowFrameSurfacePosition() { @@ -553,8 +565,8 @@ class InsetsSourceProvider { ANIMATION_TYPE_INSETS_CONTROL); // The leash was just created. We cannot dispatch it until its surface transaction is - // applied. Otherwise, the client's operation to the leash might be overwritten by us. - mIsLeashReadyForDispatching = false; + // committed. Otherwise, the client's operation to the leash might be overwritten by us. + mIsLeashInitialized = false; final SurfaceControl leash = mAdapter.mCapturedLeash; mControlTarget = target; @@ -590,7 +602,7 @@ class InsetsSourceProvider { * @param id Indicates which transaction is committed so that stale callbacks can be dropped. */ void onSurfaceTransactionCommitted(long id) { - if (mIsLeashReadyForDispatching) { + if (mIsLeashInitialized) { return; } if (mControl == null) { @@ -599,7 +611,7 @@ class InsetsSourceProvider { if (id != getSurfaceTransactionId(mControl.getLeash())) { return; } - mIsLeashReadyForDispatching = true; + mIsLeashInitialized = true; mStateController.notifySurfaceTransactionReady(this, 0, false); } @@ -650,9 +662,12 @@ class InsetsSourceProvider { mServerVisible, mClientVisible); } - protected boolean isLeashReadyForDispatching(InsetsControlTarget target) { - // If the target is not the control target, we are ready for dispatching a null-leash to it. - return target != mControlTarget || mIsLeashReadyForDispatching; + protected boolean isLeashReadyForDispatching() { + return isLeashInitialized(); + } + + boolean isLeashInitialized() { + return mIsLeashInitialized; } /** @@ -665,7 +680,7 @@ class InsetsSourceProvider { @Nullable InsetsSourceControl getControl(InsetsControlTarget target) { if (target == mControlTarget) { - if (!isLeashReadyForDispatching(target) && mControl != null) { + if (!isLeashReadyForDispatching() && mControl != null) { // The surface transaction of preparing leash is not applied yet. We don't send it // to the client in case that the client applies its transaction sooner than ours // that we could unexpectedly overwrite the surface state. @@ -690,7 +705,7 @@ class InsetsSourceProvider { */ @Nullable protected SurfaceControl getLeash(@NonNull InsetsControlTarget target) { - return target == mControlTarget && mIsLeashReadyForDispatching && mControl != null + return target == mControlTarget && mIsLeashInitialized && mControl != null ? mControl.getLeash() : null; } @@ -739,7 +754,7 @@ class InsetsSourceProvider { pw.println(); } pw.print(prefix); - pw.print("mIsLeashReadyForDispatching="); pw.print(mIsLeashReadyForDispatching); + pw.print("mIsLeashInitialized="); pw.print(mIsLeashInitialized); pw.print(" mHasPendingPosition="); pw.print(mHasPendingPosition); pw.println(); if (mWindowContainer != null) { @@ -785,7 +800,7 @@ class InsetsSourceProvider { if (mAdapter != null && mAdapter.mCapturedLeash != null) { mAdapter.mCapturedLeash.dumpDebug(proto, CAPTURED_LEASH); } - proto.write(IS_LEASH_READY_FOR_DISPATCHING, mIsLeashReadyForDispatching); + proto.write(IS_LEASH_READY_FOR_DISPATCHING, isLeashReadyForDispatching()); proto.write(CLIENT_VISIBLE, mClientVisible); proto.write(SERVER_VISIBLE, mServerVisible); proto.write(SEAMLESS_ROTATING, mSeamlessRotating); diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index 3e39a45fa5f3..03fadba30ae4 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -420,7 +420,7 @@ class InsetsStateController { final ArrayList<InsetsSourceProvider> providers = pendingControlMap.valueAt(i); for (int p = providers.size() - 1; p >= 0; p--) { final InsetsSourceProvider provider = providers.get(p); - if (provider.isLeashReadyForDispatching(target)) { + if (provider.isLeashInitialized() || provider.getControlTarget() != target) { // Stop waiting for this provider. providers.remove(p); } diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java index 2394da91684d..4aa4f22ec148 100644 --- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java +++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java @@ -22,6 +22,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.PackageManagerInternal; import android.graphics.Rect; import android.os.Environment; +import android.os.Process; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; @@ -50,6 +51,9 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; import java.util.function.IntFunction; /** @@ -84,6 +88,12 @@ class LaunchParamsPersister { private PackageList mPackageList; /** + * A map from user ID to the active {@link LoadingTask} when we're loading the launch params for + * that user. + */ + private final SparseArray<LoadingTask> mLoadingTaskMap = new SparseArray<>(); + + /** * A dual layer map that first maps user ID to a secondary map, which maps component name (the * launching activity of tasks) to {@link PersistableLaunchParams} that stores launch metadata * that are stable across reboots. @@ -117,113 +127,33 @@ class LaunchParamsPersister { } void onUnlockUser(int userId) { - loadLaunchParams(userId); + if (mLoadingTaskMap.contains(userId)) { + Slog.e(TAG, "Duplicated onUnlockUser " + userId); + return; + } + + final LoadingTask task = new LoadingTask(userId); + mLoadingTaskMap.put(userId, task); + task.execute(); } void onCleanupUser(int userId) { + // There is no need to abort the task itself. Just let the loading task finish silently + // without modifying any state. + mLoadingTaskMap.remove(userId); mLaunchParamsMap.remove(userId); } - private void loadLaunchParams(int userId) { - final List<File> filesToDelete = new ArrayList<>(); - final File launchParamsFolder = getLaunchParamFolder(userId); - if (!launchParamsFolder.isDirectory()) { - Slog.i(TAG, "Didn't find launch param folder for user " + userId); + private void waitAndMoveResultIfLoading(int userId) { + final LoadingTask task = mLoadingTaskMap.removeReturnOld(userId); + if (task == null) { return; } - - final Set<String> packages = new ArraySet<>(mPackageList.getPackageNames()); - - final File[] paramsFiles = launchParamsFolder.listFiles(); - final ArrayMap<ComponentName, PersistableLaunchParams> map = - new ArrayMap<>(paramsFiles.length); - mLaunchParamsMap.put(userId, map); - - for (File paramsFile : paramsFiles) { - if (!paramsFile.isFile()) { - Slog.w(TAG, paramsFile.getAbsolutePath() + " is not a file."); - continue; - } - if (!paramsFile.getName().endsWith(LAUNCH_PARAMS_FILE_SUFFIX)) { - Slog.w(TAG, "Unexpected params file name: " + paramsFile.getName()); - filesToDelete.add(paramsFile); - continue; - } - String paramsFileName = paramsFile.getName(); - // Migrate all records from old separator to new separator. - final int oldSeparatorIndex = - paramsFileName.indexOf(OLD_ESCAPED_COMPONENT_SEPARATOR); - if (oldSeparatorIndex != -1) { - if (paramsFileName.indexOf( - OLD_ESCAPED_COMPONENT_SEPARATOR, oldSeparatorIndex + 1) != -1) { - // Rare case. We have more than one old escaped component separator probably - // because this app uses underscore in their package name. We can't distinguish - // which one is the real separator so let's skip it. - filesToDelete.add(paramsFile); - continue; - } - paramsFileName = paramsFileName.replace( - OLD_ESCAPED_COMPONENT_SEPARATOR, ESCAPED_COMPONENT_SEPARATOR); - final File newFile = new File(launchParamsFolder, paramsFileName); - if (paramsFile.renameTo(newFile)) { - paramsFile = newFile; - } else { - // Rare case. For some reason we can't rename the file. Let's drop this record - // instead. - filesToDelete.add(paramsFile); - continue; - } - } - final String componentNameString = paramsFileName.substring( - 0 /* beginIndex */, - paramsFileName.length() - LAUNCH_PARAMS_FILE_SUFFIX.length()) - .replace(ESCAPED_COMPONENT_SEPARATOR, ORIGINAL_COMPONENT_SEPARATOR); - final ComponentName name = ComponentName.unflattenFromString( - componentNameString); - if (name == null) { - Slog.w(TAG, "Unexpected file name: " + paramsFileName); - filesToDelete.add(paramsFile); - continue; - } - - if (!packages.contains(name.getPackageName())) { - // Rare case. PersisterQueue doesn't have a chance to remove files for removed - // packages last time. - filesToDelete.add(paramsFile); - continue; - } - - try (InputStream in = new FileInputStream(paramsFile)) { - final PersistableLaunchParams params = new PersistableLaunchParams(); - final TypedXmlPullParser parser = Xml.resolvePullParser(in); - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT - && event != XmlPullParser.END_TAG) { - if (event != XmlPullParser.START_TAG) { - continue; - } - - final String tagName = parser.getName(); - if (!TAG_LAUNCH_PARAMS.equals(tagName)) { - Slog.w(TAG, "Unexpected tag name: " + tagName); - continue; - } - - params.restore(paramsFile, parser); - } - - map.put(name, params); - addComponentNameToLaunchParamAffinityMapIfNotNull( - name, params.mWindowLayoutAffinity); - } catch (Exception e) { - Slog.w(TAG, "Failed to restore launch params for " + name, e); - filesToDelete.add(paramsFile); - } - } - - if (!filesToDelete.isEmpty()) { - mPersisterQueue.addItem(new CleanUpComponentQueueItem(filesToDelete), true); + final ArrayMap<ComponentName, PersistableLaunchParams> map = task.get(); + if (map == null) { + return; } + mLaunchParamsMap.put(userId, map); } void saveTask(Task task) { @@ -236,6 +166,7 @@ class LaunchParamsPersister { return; } final int userId = task.mUserId; + waitAndMoveResultIfLoading(userId); PersistableLaunchParams params; ArrayMap<ComponentName, PersistableLaunchParams> map = mLaunchParamsMap.get(userId); if (map == null) { @@ -297,6 +228,7 @@ class LaunchParamsPersister { void getLaunchParams(Task task, ActivityRecord activity, LaunchParams outParams) { final ComponentName name = task != null ? task.realActivity : activity.mActivityComponent; final int userId = task != null ? task.mUserId : activity.mUserId; + waitAndMoveResultIfLoading(userId); final String windowLayoutAffinity; if (task != null) { windowLayoutAffinity = task.mWindowLayoutAffinity; @@ -394,6 +326,137 @@ class LaunchParamsPersister { } } + private class LoadingTask + implements Callable<ArrayMap<ComponentName, PersistableLaunchParams>> { + private final int mUserId; + private final FutureTask<ArrayMap<ComponentName, PersistableLaunchParams>> mFutureTask; + + private LoadingTask(int userId) { + mUserId = userId; + mFutureTask = new FutureTask<>(this); + } + + private void execute() { + new Thread(mFutureTask).start(); + } + + private ArrayMap<ComponentName, PersistableLaunchParams> get() { + try { + return mFutureTask.get(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } catch (ExecutionException e) { + Slog.e(TAG, "Failed to load launch params for user#" + mUserId, e); + return null; + } + } + + @Override + public ArrayMap<ComponentName, PersistableLaunchParams> call() { + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + + final List<File> filesToDelete = new ArrayList<>(); + final File launchParamsFolder = getLaunchParamFolder(mUserId); + if (!launchParamsFolder.isDirectory()) { + Slog.i(TAG, "Didn't find launch param folder for user " + mUserId); + return null; + } + + final Set<String> packages = new ArraySet<>(mPackageList.getPackageNames()); + + final File[] paramsFiles = launchParamsFolder.listFiles(); + final ArrayMap<ComponentName, PersistableLaunchParams> map = + new ArrayMap<>(paramsFiles.length); + + for (File paramsFile : paramsFiles) { + if (!paramsFile.isFile()) { + Slog.w(TAG, paramsFile.getAbsolutePath() + " is not a file."); + continue; + } + if (!paramsFile.getName().endsWith(LAUNCH_PARAMS_FILE_SUFFIX)) { + Slog.w(TAG, "Unexpected params file name: " + paramsFile.getName()); + filesToDelete.add(paramsFile); + continue; + } + String paramsFileName = paramsFile.getName(); + // Migrate all records from old separator to new separator. + final int oldSeparatorIndex = + paramsFileName.indexOf(OLD_ESCAPED_COMPONENT_SEPARATOR); + if (oldSeparatorIndex != -1) { + if (paramsFileName.indexOf( + OLD_ESCAPED_COMPONENT_SEPARATOR, oldSeparatorIndex + 1) != -1) { + // Rare case. We have more than one old escaped component separator probably + // because this app uses underscore in their package name. We can't + // distinguish which one is the real separator so let's skip it. + filesToDelete.add(paramsFile); + continue; + } + paramsFileName = paramsFileName.replace( + OLD_ESCAPED_COMPONENT_SEPARATOR, ESCAPED_COMPONENT_SEPARATOR); + final File newFile = new File(launchParamsFolder, paramsFileName); + if (paramsFile.renameTo(newFile)) { + paramsFile = newFile; + } else { + // Rare case. For some reason we can't rename the file. Let's drop this + // record instead. + filesToDelete.add(paramsFile); + continue; + } + } + final String componentNameString = paramsFileName.substring( + 0 /* beginIndex */, + paramsFileName.length() - LAUNCH_PARAMS_FILE_SUFFIX.length()) + .replace(ESCAPED_COMPONENT_SEPARATOR, ORIGINAL_COMPONENT_SEPARATOR); + final ComponentName name = ComponentName.unflattenFromString( + componentNameString); + if (name == null) { + Slog.w(TAG, "Unexpected file name: " + paramsFileName); + filesToDelete.add(paramsFile); + continue; + } + + if (!packages.contains(name.getPackageName())) { + // Rare case. PersisterQueue doesn't have a chance to remove files for removed + // packages last time. + filesToDelete.add(paramsFile); + continue; + } + + try (InputStream in = new FileInputStream(paramsFile)) { + final PersistableLaunchParams params = new PersistableLaunchParams(); + final TypedXmlPullParser parser = Xml.resolvePullParser(in); + int event; + while ((event = parser.next()) != XmlPullParser.END_DOCUMENT + && event != XmlPullParser.END_TAG) { + if (event != XmlPullParser.START_TAG) { + continue; + } + + final String tagName = parser.getName(); + if (!TAG_LAUNCH_PARAMS.equals(tagName)) { + Slog.w(TAG, "Unexpected tag name: " + tagName); + continue; + } + + params.restore(paramsFile, parser); + } + + map.put(name, params); + addComponentNameToLaunchParamAffinityMapIfNotNull( + name, params.mWindowLayoutAffinity); + } catch (Exception e) { + Slog.w(TAG, "Failed to restore launch params for " + name, e); + filesToDelete.add(paramsFile); + } + } + + if (!filesToDelete.isEmpty()) { + mPersisterQueue.addItem(new CleanUpComponentQueueItem(filesToDelete), true); + } + return map; + } + } + private class LaunchParamsWriteQueueItem implements PersisterQueue.WriteQueueItem<LaunchParamsWriteQueueItem> { private final int mUserId; @@ -466,7 +529,7 @@ class LaunchParamsPersister { } } - private class CleanUpComponentQueueItem implements PersisterQueue.WriteQueueItem { + private static class CleanUpComponentQueueItem implements PersisterQueue.WriteQueueItem { private final List<File> mComponentFiles; private CleanUpComponentQueueItem(List<File> componentFiles) { @@ -483,7 +546,7 @@ class LaunchParamsPersister { } } - private class PersistableLaunchParams { + private static class PersistableLaunchParams { private static final String ATTR_WINDOWING_MODE = "windowing_mode"; private static final String ATTR_DISPLAY_UNIQUE_ID = "display_unique_id"; private static final String ATTR_BOUNDS = "bounds"; diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index 7aede8b4a068..9da848aa05d8 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -38,6 +38,7 @@ import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; +import static com.android.launcher3.Flags.enableRefactorTaskThumbnail; import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS; @@ -1493,12 +1494,20 @@ class RecentTasks { if (isExcludeFromRecents) { if (DEBUG_RECENTS_TRIM_TASKS) { Slog.d(TAG, - "\texcludeFromRecents=true, taskIndex = " + taskIndex - + ", isOnHomeDisplay: " + task.isOnHomeDisplay()); + "\texcludeFromRecents=true," + + " taskIndex: " + taskIndex + + " getTopVisibleActivity: " + task.getTopVisibleActivity() + + " isOnHomeDisplay: " + task.isOnHomeDisplay()); } // The Recents is only supported on default display now, we should only keep the // most recent task of home display. - return (task.isOnHomeDisplay() && taskIndex == 0); + boolean isMostRecentTask; + if (enableRefactorTaskThumbnail()) { + isMostRecentTask = task.getTopVisibleActivity() != null; + } else { + isMostRecentTask = taskIndex == 0; + } + return (task.isOnHomeDisplay() && isMostRecentTask); } } diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 5550f3efaa3a..d295378a9b65 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -699,8 +699,10 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { final WindowState win = mService.windowForClientLocked(this, window, false /* throwOnError */); if (win != null) { - ImeTracker.forLogging().onProgress(imeStatsToken, - ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES); + if (android.view.inputmethod.Flags.refactorInsetsController()) { + ImeTracker.forLogging().onProgress(imeStatsToken, + ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES); + } win.setRequestedVisibleTypes(requestedVisibleTypes); win.getDisplayContent().getInsetsPolicy().onRequestedVisibleTypesChanged(win, imeStatsToken); diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java index 24fb20731c43..896612d3d27a 100644 --- a/services/core/java/com/android/server/wm/StartingData.java +++ b/services/core/java/com/android/server/wm/StartingData.java @@ -68,7 +68,9 @@ public abstract class StartingData { * window. * Note this isn't equal to transition playing, the period should be * Sync finishNow -> Start transaction apply. + * @deprecated TODO(b/362347290): cleanup after fix ramp up */ + @Deprecated boolean mWaitForSyncTransactionCommit; /** diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index a2fda0afb9c6..86bb75ab3f8c 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_RETAIN_IN_RECENTS; 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.Display.INVALID_DISPLAY; 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.IActivityController; 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 @@ class Task extends TaskFragment { 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 @@ class Task extends TaskFragment { intent = _intent; mMinWidth = minWidth; mMinHeight = minHeight; + updateAllowForceResizeOverride(); } mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity); mHandler = new ActivityTaskHandler(mTaskSupervisor.mLooper); @@ -1028,6 +1039,7 @@ class Task extends TaskFragment { mTaskSupervisor.mRecentTasks.remove(this); mTaskSupervisor.mRecentTasks.add(this); } + updateAllowForceResizeOverride(); } /** Sets the original minimal width and height. */ @@ -1823,6 +1835,17 @@ class Task extends TaskFragment { -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 @@ class Task extends TaskFragment { 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/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index 92953e5a5041..83e714d82dd2 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -429,7 +429,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } final IBinder activityToken; - if (activity.getPid() == mOrganizerPid) { + if (activity.getPid() == mOrganizerPid && activity.getUid() == mOrganizerUid) { // We only pass the actual token if the activity belongs to the organizer process. activityToken = activity.token; } else { @@ -458,7 +458,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr change.setTaskFragmentToken(lastParentTfToken); } // Only pass the activity token to the client if it belongs to the same process. - if (nextFillTaskActivity != null && nextFillTaskActivity.getPid() == mOrganizerPid) { + if (nextFillTaskActivity != null && nextFillTaskActivity.getPid() == mOrganizerPid + && nextFillTaskActivity.getUid() == mOrganizerUid) { change.setOtherActivityToken(nextFillTaskActivity.token); } return change; @@ -553,6 +554,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr "Replacing existing organizer currently unsupported"); } + if (pid <= 0) { + throw new IllegalStateException("Cannot register from invalid pid: " + pid); + } + if (restoreFromCachedStateIfPossible(organizer, pid, uid, outSavedState)) { return; } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 0a47522f7df6..bb80f69a5537 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -3498,14 +3498,14 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } boolean hasChanged() { + final boolean currVisible = mContainer.isVisibleRequested(); // the task including transient launch must promote to root task - if ((mFlags & ChangeInfo.FLAG_TRANSIENT_LAUNCH) != 0 - || (mFlags & ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH) != 0) { + if (currVisible && ((mFlags & ChangeInfo.FLAG_TRANSIENT_LAUNCH) != 0 + || (mFlags & ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH) != 0)) { return true; } // If it's invisible and hasn't changed visibility, always return false since even if // something changed, it wouldn't be a visible change. - final boolean currVisible = mContainer.isVisibleRequested(); if (currVisible == mVisible && !mVisible) return false; return currVisible != mVisible || mKnownConfigChanges != 0 diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 0a9cb1c38dab..1c03ba571923 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -4351,4 +4351,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< t.merge(mSyncTransaction); } + int getSyncTransactionCommitCallbackDepth() { + return mSyncTransactionCommitCallbackDepth; + } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 1640ad3f1958..4c4b4f65edf5 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3856,16 +3856,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } fillInsetsState(mLastReportedInsetsState, false /* copySources */); fillInsetsSourceControls(mLastReportedActiveControls, false /* copyControls */); - if (Flags.insetsControlChangedItem()) { - getProcess().scheduleClientTransactionItem(new WindowStateInsetsControlChangeItem( - mClient, mLastReportedInsetsState, mLastReportedActiveControls)); - } else { - try { - mClient.insetsControlChanged(mLastReportedInsetsState, mLastReportedActiveControls); - } catch (RemoteException e) { - Slog.w(TAG, "Failed to deliver inset control state change to w=" + this, e); - } - } + getProcess().scheduleClientTransactionItem(new WindowStateInsetsControlChangeItem( + mClient, mLastReportedInsetsState, mLastReportedActiveControls)); } @Override diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index d2493c513b5f..5cd117b512d4 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 @@ public: 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 @@ private: // 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 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon outConfig->stylusButtonMotionEventsEnabled = mLocked.stylusButtonMotionEventsEnabled; outConfig->stylusPointerIconEnabled = mLocked.stylusPointerIconEnabled; + + outConfig->keyRemapping = mLocked.keyRemapping; } // release lock } @@ -1910,6 +1916,16 @@ void NativeInputManager::setInputMethodConnectionIsActive(bool isActive) { 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) { @@ -1983,10 +1999,19 @@ static std::vector<int32_t> getIntArray(JNIEnv* env, jintArray arr) { 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, @@ -2491,7 +2516,7 @@ static jobject nativeGetLights(JNIEnv* env, jobject nativeImplObj, jint deviceId 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; } @@ -2955,7 +2980,7 @@ static const JNINativeMethod gInputManagerMethods[] = { {"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;", diff --git a/services/core/jni/com_android_server_utils_AnrTimer.cpp b/services/core/jni/com_android_server_utils_AnrTimer.cpp index cf9611468fab..2836d46b0f1a 100644 --- a/services/core/jni/com_android_server_utils_AnrTimer.cpp +++ b/services/core/jni/com_android_server_utils_AnrTimer.cpp @@ -19,6 +19,8 @@ #include <sys/timerfd.h> #include <inttypes.h> #include <sys/stat.h> +#include <unistd.h> +#include <regex.h> #include <algorithm> #include <list> @@ -26,6 +28,7 @@ #include <set> #include <string> #include <vector> +#include <map> #define LOG_TAG "AnrTimerService" #define ATRACE_TAG ATRACE_TAG_ACTIVITY_MANAGER @@ -33,8 +36,8 @@ #include <jni.h> #include <nativehelper/JNIHelp.h> -#include "android_runtime/AndroidRuntime.h" -#include "core_jni_helpers.h" +#include <android_runtime/AndroidRuntime.h> +#include <core_jni_helpers.h> #include <processgroup/processgroup.h> #include <utils/Log.h> @@ -109,30 +112,334 @@ bool processExists(pid_t pid) { // Return the name of the process whose pid is the input. If the process does not exist, the // name will "notfound". std::string getProcessName(pid_t pid) { - char buffer[PATH_MAX]; - snprintf(buffer, sizeof(buffer), "/proc/%d/cmdline", pid); - int fd = ::open(buffer, O_RDONLY); - if (fd >= 0) { - size_t pos = 0; - ssize_t result; - while (pos < sizeof(buffer)-1) { - result = ::read(fd, buffer + pos, (sizeof(buffer) - pos) - 1); - if (result <= 0) { - break; + char path[PATH_MAX]; + snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); + FILE* cmdline = fopen(path, "r"); + if (cmdline != nullptr) { + char name[PATH_MAX]; + char const *retval = fgets(name, sizeof(name), cmdline); + fclose(cmdline); + if (retval == nullptr) { + return std::string("unknown"); + } else { + return std::string(name); + } + } else { + return std::string("notfound"); + } +} + +/** + * Three wrappers of the trace utilities, which hard-code the timer track. + */ +void traceBegin(const char* msg, int cookie) { + ATRACE_ASYNC_FOR_TRACK_BEGIN(ANR_TIMER_TRACK, msg, cookie); +} + +void traceEnd(int cookie) { + ATRACE_ASYNC_FOR_TRACK_END(ANR_TIMER_TRACK, cookie); +} + +void traceEvent(const char* msg) { + ATRACE_INSTANT_FOR_TRACK(ANR_TIMER_TRACK, msg); +} + +/** + * This class captures tracing information for processes tracked by an AnrTimer. A user can + * configure tracing to have the AnrTimerService emit extra information for watched processes. + * singleton. + * + * The tracing configuration has two components: process selection and an optional early action. + * + * Processes are selected in one of three ways: + * 1. A list of numeric linux process IDs. + * 2. A regular expression, matched against process names. + * 3. The keyword "all", to trace every process that uses an AnrTimer. + * Perfetto trace events are always emitted for every operation on a traced process. + * + * An early action occurs before the scheduled timeout. The early timeout is specified as a + * percentage (integer value in the range 0:100) of the programmed timeout. The AnrTimer will + * execute the early action at the early timeout. The early action may terminate the timer. + * + * There is one early action: + * 1. Expire - consider the AnrTimer expired and report it to the upper layers. + */ +class AnrTimerTracer { + public: + // Actions that can be taken when an early timer expires. + enum EarlyAction { + // Take no action. This is the value used when tracing is disabled. + None, + // Trace the timer but take no other action. + Trace, + // Report timer expiration to the upper layers. This is terminal, in that + Expire, + }; + + // The trace information for a single timer. + struct TraceConfig { + bool enabled = false; + EarlyAction action = None; + int earlyTimeout = 0; + }; + + AnrTimerTracer() { + AutoMutex _l(lock_); + resetLocked(); + } + + // Return the TraceConfig for a process. + TraceConfig getConfig(int pid) { + AutoMutex _l(lock_); + // The most likely situation: no tracing is configured. + if (!config_.enabled) return {}; + if (matchAllPids_) return config_; + if (watched_.contains(pid)) return config_; + if (!matchNames_) return {}; + if (matchedPids_.contains(pid)) return config_; + if (unmatchedPids_.contains(pid)) return {}; + std::string proc_name = getProcessName(pid); + bool matched = regexec(®ex_, proc_name.c_str(), 0, 0, 0) == 0; + if (matched) { + matchedPids_.insert(pid); + return config_; + } else { + unmatchedPids_.insert(pid); + return {}; + } + } + + // Set the trace configuration. The input is a string that contains key/value pairs of the + // form "key=value". Pairs are separated by spaces. The function returns a string status. + // On success, the normalized config is returned. On failure, the configuration reset the + // result contains an error message. As a special case, an empty set of configs, or a + // config that contains only the keyword "show", will do nothing except return the current + // configuration. On any error, all tracing is disabled. + std::pair<bool, std::string> setConfig(const std::vector<std::string>& config) { + AutoMutex _l(lock_); + if (config.size() == 0) { + // Implicit "show" + return { true, currentConfigLocked() }; + } else if (config.size() == 1) { + // Process the one-word commands + const char* s = config[0].c_str(); + if (strcmp(s, "show") == 0) { + return { true, currentConfigLocked() }; + } else if (strcmp(s, "off") == 0) { + resetLocked(); + return { true, currentConfigLocked() }; + } else if (strcmp(s, "help") == 0) { + return { true, help() }; } + } else if (config.size() > 2) { + return { false, "unexpected values in config" }; + } + + // Barring an error in the remaining specification list, tracing will be enabled. + resetLocked(); + // Fetch the process specification. This must be the first configuration entry. + { + auto result = setTracedProcess(config[0]); + if (!result.first) return result; } - ::close(fd); - if (result >= 0) { - buffer[pos] = 0; + // Process optional actions. + if (config.size() > 1) { + auto result = setTracedAction(config[1]); + if (!result.first) return result; + } + + // Accept the result. + config_.enabled = true; + return { true, currentConfigLocked() }; + } + + private: + // Identify the processes to be traced. + std::pair<bool, std::string> setTracedProcess(std::string config) { + const char* s = config.c_str(); + const char* word = nullptr; + + if (strcmp(s, "pid=all") == 0) { + matchAllPids_ = true; + } else if ((word = startsWith(s, "pid=")) != nullptr) { + int p; + int n; + while (sscanf(word, "%d%n", &p, &n) == 1) { + watched_.insert(p); + word += n; + if (*word == ',') word++; + } + if (*word != 0) { + return { false, "invalid pid list" }; + } + config_.action = Trace; + } else if ((word = startsWith(s, "name=")) != nullptr) { + if (matchNames_) { + regfree(®ex_); + matchNames_ = false; + } + if (regcomp(®ex_, word, REG_EXTENDED) != 0) { + return { false, "invalid regex" }; + } + matchNames_ = true; + namePattern_ = word; + config_.action = Trace; } else { - snprintf(buffer, sizeof(buffer), "err: %s", strerror(errno)); + return { false, "no process specified" }; } - } else { - snprintf(buffer, sizeof(buffer), "notfound"); + return { true, "" }; + } + + // Set the action to be taken on a traced process. The incoming default action is Trace; + // this method may overwrite that action. + std::pair<bool, std::string> setTracedAction(std::string config) { + const char* s = config.c_str(); + const char* word = nullptr; + if (sscanf(s, "expire=%d", &config_.earlyTimeout) == 1) { + if (config_.earlyTimeout < 0) { + return { false, "invalid expire timeout" }; + } + config_.action = Expire; + } else { + return { false, std::string("cannot parse action ") + s }; + } + return { true, "" }; + } + + // Return the string value of an action. + static const char* toString(EarlyAction action) { + switch (action) { + case None: return "none"; + case Trace: return "trace"; + case Expire: return "expire"; + } + return "unknown"; + } + + // Return the action represented by the string. + static EarlyAction fromString(const char* action) { + if (strcmp(action, "expire") == 0) return Expire; + return None; } - return std::string(buffer); -} + + // Return the help message. This has everything except the invocation command. + static std::string help() { + static const char* msg = + "help show this message\n" + "show report the current configuration\n" + "off clear the current configuration, turning off all tracing\n" + "spec... configure tracing according to the specification list\n" + " action=<action> what to do when a split timer expires\n" + " expire expire the timer to the upper levels\n" + " event generate extra trace events\n" + " pid=<pid>[,<pid>] watch the processes in the pid list\n" + " pid=all watch every process in the system\n" + " name=<regex> watch the processes whose name matches the regex\n"; + return msg; + } + + // A small convenience function for parsing. If the haystack starts with the needle and the + // haystack has at least one more character following, return a pointer to the following + // character. Otherwise return null. + static const char* startsWith(const char* haystack, const char* needle) { + if (strncmp(haystack, needle, strlen(needle)) == 0 && strlen(haystack) + strlen(needle)) { + return haystack + strlen(needle); + } + return nullptr; + } + + // Return the currently watched pids. The lock must be held. + std::string watchedPidsLocked() const { + if (watched_.size() == 0) return "none"; + bool first = true; + std::string result = ""; + for (auto i = watched_.cbegin(); i != watched_.cend(); i++) { + if (first) { + result += StringPrintf("%d", *i); + } else { + result += StringPrintf(",%d", *i); + } + } + return result; + } + + // Return the current configuration, in a form that can be consumed by setConfig(). + std::string currentConfigLocked() const { + if (!config_.enabled) return "off"; + std::string result; + if (matchAllPids_) { + result = "pid=all"; + } else if (matchNames_) { + result = StringPrintf("name=\"%s\"", namePattern_.c_str()); + } else { + result = std::string("pid=") + watchedPidsLocked(); + } + switch (config_.action) { + case None: + break; + case Trace: + // The default action is Trace + break; + case Expire: + result += StringPrintf(" %s=%d", toString(config_.action), config_.earlyTimeout); + break; + } + return result; + } + + // Reset the current configuration. + void resetLocked() { + if (!config_.enabled) return; + + config_.enabled = false; + config_.earlyTimeout = 0; + config_.action = {}; + matchAllPids_ = false; + watched_.clear(); + if (matchNames_) regfree(®ex_); + matchNames_ = false; + namePattern_ = ""; + matchedPids_.clear(); + unmatchedPids_.clear(); + } + + // The lock for all operations + mutable Mutex lock_; + + // The current tracing information, when a process matches. + TraceConfig config_; + + // A short-hand flag that causes all processes to be tracing without the overhead of + // searching any of the maps. + bool matchAllPids_; + + // A set of process IDs that should be traced. This is updated directly in setConfig() + // and only includes pids that were explicitly called out in the configuration. + std::set<pid_t> watched_; + + // Name mapping is a relatively expensive operation, since the process name must be fetched + // from the /proc file system and then a regex must be evaluated. However, name mapping is + // useful to ensure processes are traced at the moment they start. To make this faster, a + // process's name is matched only once, and the result is stored in the matchedPids_ or + // unmatchedPids_ set, as appropriate. This can lead to confusion if a process changes its + // name after it starts. + + // The global flag that enables name matching. If this is disabled then all name matching + // is disabled. + bool matchNames_; + + // The regular expression that matches processes to be traced. This is saved for logging. + std::string namePattern_; + + // The compiled regular expression. + regex_t regex_; + + // The set of all pids that whose process names match (or do not match) the name regex. + // There is one set for pids that match and one set for pids that do not match. + std::set<pid_t> matchedPids_; + std::set<pid_t> unmatchedPids_; +}; /** * This class encapsulates the anr timer service. The service manages a list of individual @@ -177,7 +484,7 @@ class AnrTimerService { * traditional void* and Java object pointer. The remaining parameters are * configuration options. */ - AnrTimerService(char const* label, notifier_t notifier, void* cookie, jweak jtimer, Ticker*, + AnrTimerService(const char* label, notifier_t notifier, void* cookie, jweak jtimer, Ticker*, bool extend, bool freeze); // Delete the service and clean up memory. @@ -211,6 +518,11 @@ class AnrTimerService { // Release a timer. The timer must be in the expired list. bool release(timer_id_t); + // Configure a trace specification to trace selected timers. See AnrTimerTracer for details. + static std::pair<bool, std::string> trace(const std::vector<std::string>& spec) { + return tracer_.setConfig(spec); + } + // Return the Java object associated with this instance. jweak jtimer() const { return notifierObject_; @@ -221,7 +533,7 @@ class AnrTimerService { private: // The service cannot be copied. - AnrTimerService(AnrTimerService const&) = delete; + AnrTimerService(const AnrTimerService&) = delete; // Insert a timer into the running list. The lock must be held by the caller. void insertLocked(const Timer&); @@ -230,7 +542,7 @@ class AnrTimerService { Timer removeLocked(timer_id_t timerId); // Add a timer to the expired list. - void addExpiredLocked(Timer const&); + void addExpiredLocked(const Timer&); // Scrub the expired list by removing all entries for non-existent processes. The expired // lock must be held by the caller. @@ -240,10 +552,10 @@ class AnrTimerService { static const char* statusString(Status); // The name of this service, for logging. - std::string const label_; + const std::string label_; // The callback that is invoked when a timer expires. - notifier_t const notifier_; + const notifier_t notifier_; // The two cookies passed to the notifier. void* notifierCookie_; @@ -289,8 +601,13 @@ class AnrTimerService { // The clock used by this AnrTimerService. Ticker *ticker_; + + // The global tracing specification. + static AnrTimerTracer tracer_; }; +AnrTimerTracer AnrTimerService::tracer_; + class AnrTimerService::ProcessStats { public: nsecs_t cpu_time; @@ -337,14 +654,23 @@ class AnrTimerService::ProcessStats { class AnrTimerService::Timer { public: // A unique ID assigned when the Timer is created. - timer_id_t const id; + const timer_id_t id; // The creation parameters. The timeout is the original, relative timeout. - int const pid; - int const uid; - nsecs_t const timeout; - bool const extend; - bool const freeze; + const int pid; + const int uid; + const nsecs_t timeout; + // True if the timer may be extended. + const bool extend; + // True if process should be frozen when its timer expires. + const bool freeze; + // This is a percentage between 0 and 100. If it is non-zero then timer will fire at + // timeout*split/100, and the EarlyAction will be invoked. The timer may continue running + // or may expire, depending on the action. Thus, this value "splits" the timeout into two + // pieces. + const int split; + // The action to take if split (above) is non-zero, when the timer reaches the split point. + const AnrTimerTracer::EarlyAction action; // The state of this timer. Status status; @@ -355,6 +681,9 @@ class AnrTimerService::Timer { // The scheduled timeout. This is an absolute time. It may be extended. nsecs_t scheduled; + // True if this timer is split and in its second half + bool splitting; + // True if this timer has been extended. bool extended; @@ -367,22 +696,10 @@ class AnrTimerService::Timer { // The default constructor is used to create timers that are Invalid, representing the "not // found" condition when a collection is searched. - Timer() : - id(NOTIMER), - pid(0), - uid(0), - timeout(0), - extend(false), - freeze(false), - status(Invalid), - started(0), - scheduled(0), - extended(false), - frozen(false) { - } + Timer() : Timer(NOTIMER) { } - // This constructor creates a timer with the specified id. This can be used as the argument - // to find(). + // This constructor creates a timer with the specified id and everything else set to + // "empty". This can be used as the argument to find(). Timer(timer_id_t id) : id(id), pid(0), @@ -390,29 +707,37 @@ class AnrTimerService::Timer { timeout(0), extend(false), freeze(false), + split(0), + action(AnrTimerTracer::None), status(Invalid), started(0), scheduled(0), + splitting(false), extended(false), frozen(false) { } // Create a new timer. This starts the timer. - Timer(int pid, int uid, nsecs_t timeout, bool extend, bool freeze) : + Timer(int pid, int uid, nsecs_t timeout, bool extend, bool freeze, + AnrTimerTracer::TraceConfig trace) : id(nextId()), pid(pid), uid(uid), timeout(timeout), extend(extend), freeze(pid != 0 && freeze), + split(trace.earlyTimeout), + action(trace.action), status(Running), started(now()), - scheduled(started + timeout), + scheduled(started + (split > 0 ? (timeout*split)/100 : timeout)), + splitting(false), extended(false), frozen(false) { if (extend && pid != 0) { initial.fill(pid); } + // A zero-pid is odd but it means the upper layers will never ANR the process. Freezing // is always disabled. (It won't work anyway, but disabling it avoids error messages.) ALOGI_IF(DEBUG_ERROR && pid == 0, "error: zero-pid %s", toString().c_str()); @@ -434,6 +759,23 @@ class AnrTimerService::Timer { // returns false if the timer is eligible for extension. If the function returns false, the // scheduled time is updated. bool expire() { + if (split > 0 && !splitting) { + scheduled = started + timeout; + splitting = true; + event("split"); + switch (action) { + case AnrTimerTracer::None: + case AnrTimerTracer::Trace: + break; + case AnrTimerTracer::Expire: + status = Expired; + maybeFreezeProcess(); + event("expire"); + break; + } + return status == Expired; + } + nsecs_t extension = 0; if (extend && !extended) { // Only one extension is permitted. @@ -525,15 +867,15 @@ class AnrTimerService::Timer { char tag[PATH_MAX]; snprintf(tag, sizeof(tag), "freeze(pid=%d,uid=%d)", pid, uid); - ATRACE_ASYNC_FOR_TRACK_BEGIN(ANR_TIMER_TRACK, tag, cookie); + traceBegin(tag, cookie); if (SetProcessProfiles(uid, pid, {"Frozen"})) { ALOGI("freeze %s name=%s", toString().c_str(), getName().c_str()); frozen = true; - ATRACE_ASYNC_FOR_TRACK_BEGIN(ANR_TIMER_TRACK, "frozen", cookie+1); + traceBegin("frozen", cookie+1); } else { ALOGE("error: freezing %s name=%s error=%s", toString().c_str(), getName().c_str(), strerror(errno)); - ATRACE_ASYNC_FOR_TRACK_END(ANR_TIMER_TRACK, cookie); + traceEnd(cookie); } } @@ -543,7 +885,7 @@ class AnrTimerService::Timer { // See maybeFreezeProcess for an explanation of the cookie. const uint32_t cookie = id << 1; - ATRACE_ASYNC_FOR_TRACK_END(ANR_TIMER_TRACK, cookie+1); + traceEnd(cookie+1); if (SetProcessProfiles(uid, pid, {"Unfrozen"})) { ALOGI("unfreeze %s name=%s", toString().c_str(), getName().c_str()); frozen = false; @@ -551,7 +893,7 @@ class AnrTimerService::Timer { ALOGE("error: unfreezing %s name=%s error=%s", toString().c_str(), getName().c_str(), strerror(errno)); } - ATRACE_ASYNC_FOR_TRACK_END(ANR_TIMER_TRACK, cookie); + traceEnd(cookie); } // Get the next free ID. NOTIMER is never returned. @@ -564,12 +906,17 @@ class AnrTimerService::Timer { } // Log an event, non-verbose. - void event(char const* tag) { + void event(const char* tag) { event(tag, false); } // Log an event, guarded by the debug flag. - void event(char const* tag, bool verbose) { + void event(const char* tag, bool verbose) { + if (action != AnrTimerTracer::None) { + char msg[PATH_MAX]; + snprintf(msg, sizeof(msg), "%s(pid=%d)", tag, pid); + traceEvent(msg); + } if (verbose) { char name[PATH_MAX]; ALOGI_IF(DEBUG_TIMER, "event %s %s name=%s", @@ -594,12 +941,12 @@ class AnrTimerService::Ticker { struct Entry { const nsecs_t scheduled; const timer_id_t id; - AnrTimerService* const service; + AnrTimerService* service; Entry(nsecs_t scheduled, timer_id_t id, AnrTimerService* service) : scheduled(scheduled), id(id), service(service) {}; - bool operator<(const Entry &r) const { + bool operator<(const Entry& r) const { return scheduled == r.scheduled ? id < r.id : scheduled < r.scheduled; } }; @@ -664,7 +1011,7 @@ class AnrTimerService::Ticker { } // Remove every timer associated with the service. - void remove(AnrTimerService const* service) { + void remove(const AnrTimerService* service) { AutoMutex _l(lock_); timer_id_t front = headTimerId(); for (auto i = running_.begin(); i != running_.end(); ) { @@ -746,7 +1093,7 @@ class AnrTimerService::Ticker { // scheduled expiration time of the first entry. void restartLocked() { if (!running_.empty()) { - Entry const x = *(running_.cbegin()); + const Entry x = *(running_.cbegin()); nsecs_t delay = x.scheduled - now(); // Force a minimum timeout of 10ns. if (delay < 10) delay = 10; @@ -807,7 +1154,7 @@ class AnrTimerService::Ticker { std::atomic<size_t> AnrTimerService::Ticker::idGen_; -AnrTimerService::AnrTimerService(char const* label, notifier_t notifier, void* cookie, +AnrTimerService::AnrTimerService(const char* label, notifier_t notifier, void* cookie, jweak jtimer, Ticker* ticker, bool extend, bool freeze) : label_(label), notifier_(notifier), @@ -841,7 +1188,7 @@ const char* AnrTimerService::statusString(Status s) { AnrTimerService::timer_id_t AnrTimerService::start(int pid, int uid, nsecs_t timeout) { AutoMutex _l(lock_); - Timer t(pid, uid, timeout, extend_, freeze_); + Timer t(pid, uid, timeout, extend_, freeze_, tracer_.getConfig(pid)); insertLocked(t); t.start(); counters_.started++; @@ -918,7 +1265,7 @@ bool AnrTimerService::release(timer_id_t id) { return okay; } -void AnrTimerService::addExpiredLocked(Timer const& timer) { +void AnrTimerService::addExpiredLocked(const Timer& timer) { scrubExpiredLocked(); expired_.insert(timer); } @@ -1077,7 +1424,7 @@ jlong anrTimerCreate(JNIEnv* env, jobject jtimer, jstring jname, ScopedUtfChars name(env, jname); jobject timer = env->NewWeakGlobalRef(jtimer); AnrTimerService* service = new AnrTimerService(name.c_str(), - anrNotify, &gAnrArgs, timer, gAnrArgs.ticker, extend, freeze); + anrNotify, &gAnrArgs, timer, gAnrArgs.ticker, extend, freeze); return reinterpret_cast<jlong>(service); } @@ -1122,6 +1469,19 @@ jboolean anrTimerRelease(JNIEnv* env, jclass, jlong ptr, jint timerId) { return toService(ptr)->release(timerId); } +jstring anrTimerTrace(JNIEnv* env, jclass, jobjectArray jconfig) { + if (!nativeSupportEnabled) return nullptr; + std::vector<std::string> config; + const jsize jlen = jconfig == nullptr ? 0 : env->GetArrayLength(jconfig); + for (size_t i = 0; i < jlen; i++) { + jstring je = static_cast<jstring>(env->GetObjectArrayElement(jconfig, i)); + ScopedUtfChars e(env, je); + config.push_back(e.c_str()); + } + auto r = AnrTimerService::trace(config); + return env->NewStringUTF(r.second.c_str()); +} + jobjectArray anrTimerDump(JNIEnv *env, jclass, jlong ptr) { if (!nativeSupportEnabled) return nullptr; std::vector<std::string> stats = toService(ptr)->getDump(); @@ -1134,22 +1494,23 @@ jobjectArray anrTimerDump(JNIEnv *env, jclass, jlong ptr) { } static const JNINativeMethod methods[] = { - {"nativeAnrTimerSupported", "()Z", (void*) anrTimerSupported}, - {"nativeAnrTimerCreate", "(Ljava/lang/String;ZZ)J", (void*) anrTimerCreate}, - {"nativeAnrTimerClose", "(J)I", (void*) anrTimerClose}, - {"nativeAnrTimerStart", "(JIIJ)I", (void*) anrTimerStart}, - {"nativeAnrTimerCancel", "(JI)Z", (void*) anrTimerCancel}, - {"nativeAnrTimerAccept", "(JI)Z", (void*) anrTimerAccept}, - {"nativeAnrTimerDiscard", "(JI)Z", (void*) anrTimerDiscard}, - {"nativeAnrTimerRelease", "(JI)Z", (void*) anrTimerRelease}, - {"nativeAnrTimerDump", "(J)[Ljava/lang/String;", (void*) anrTimerDump}, + {"nativeAnrTimerSupported", "()Z", (void*) anrTimerSupported}, + {"nativeAnrTimerCreate", "(Ljava/lang/String;ZZ)J", (void*) anrTimerCreate}, + {"nativeAnrTimerClose", "(J)I", (void*) anrTimerClose}, + {"nativeAnrTimerStart", "(JIIJ)I", (void*) anrTimerStart}, + {"nativeAnrTimerCancel", "(JI)Z", (void*) anrTimerCancel}, + {"nativeAnrTimerAccept", "(JI)Z", (void*) anrTimerAccept}, + {"nativeAnrTimerDiscard", "(JI)Z", (void*) anrTimerDiscard}, + {"nativeAnrTimerRelease", "(JI)Z", (void*) anrTimerRelease}, + {"nativeAnrTimerTrace", "([Ljava/lang/String;)Ljava/lang/String;", (void*) anrTimerTrace}, + {"nativeAnrTimerDump", "(J)[Ljava/lang/String;", (void*) anrTimerDump}, }; } // anonymous namespace int register_android_server_utils_AnrTimer(JNIEnv* env) { - static const char *className = "com/android/server/utils/AnrTimer"; + static const char* className = "com/android/server/utils/AnrTimer"; jniRegisterNativeMethods(env, className, methods, NELEM(methods)); nativeSupportEnabled = NATIVE_SUPPORT; diff --git a/services/supervision/Android.bp b/services/supervision/Android.bp index 93a0c4af7891..aefbbcadcc1d 100644 --- a/services/supervision/Android.bp +++ b/services/supervision/Android.bp @@ -19,4 +19,7 @@ java_library_static { defaults: ["platform_service_defaults"], srcs: [":services.supervision-sources"], libs: ["services.core"], + lint: { + baseline_filename: "lint-baseline.xml", + }, } diff --git a/services/supervision/lint-baseline.xml b/services/supervision/lint-baseline.xml new file mode 100644 index 000000000000..f2a501037447 --- /dev/null +++ b/services/supervision/lint-baseline.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<issues format="6" by="lint 8.4.0-alpha08" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha08"> + + <issue + id="MissingPermissionAnnotation" + message="isSupervisionEnabled should be annotated with either @EnforcePermission, @RequiresNoPermission or @PermissionManuallyEnforced." + errorLine1=" @Override" + errorLine2=" ^"> + <location + file="frameworks/base/services/supervision/java/com/android/server/supervision/SupervisionService.java" + line="45" + column="5"/> + </issue> + + <issue + id="MissingPermissionAnnotation" + message="onShellCommand should be annotated with either @EnforcePermission, @RequiresNoPermission or @PermissionManuallyEnforced." + errorLine1=" @Override" + errorLine2=" ^"> + <location + file="frameworks/base/services/supervision/java/com/android/server/supervision/SupervisionService.java" + line="50" + column="5"/> + </issue> + + <issue + id="MissingPermissionAnnotation" + message="dump should be annotated with either @EnforcePermission, @RequiresNoPermission or @PermissionManuallyEnforced." + errorLine1=" @Override" + errorLine2=" ^"> + <location + file="frameworks/base/services/supervision/java/com/android/server/supervision/SupervisionService.java" + line="62" + column="5"/> + </issue> + + <issue + id="SimpleRequiresNoPermission" + message="Method isSupervisionEnabled doesn't perform any permission checks, meaning it should be annotated with @RequiresNoPermission." + errorLine1=" @Override" + errorLine2=" ^"> + <location + file="frameworks/base/services/supervision/java/com/android/server/supervision/SupervisionService.java" + line="45" + column="5"/> + </issue> + +</issues> diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java index bf5a692ef8ca..c70bf8abaef6 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java @@ -2127,6 +2127,48 @@ public final class DisplayPowerControllerTest { } @Test + public void testManualBrightness_stateDozePolicyOnUseNormalBrightnessForDozeTrue_brightnessDoze() { + when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true); + when(mDisplayManagerFlagsMock.isNormalBrightnessForDozeParameterEnabled()).thenReturn(true); + mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL); + float brightness = 0.277f; + when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); + when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness); + when(mHolder.hbmController.getCurrentBrightnessMax()) + .thenReturn(PowerManager.BRIGHTNESS_MAX); + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); + // Start with state=DOZE. + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE); + DisplayPowerRequest dprInit = new DisplayPowerRequest(); + dprInit.policy = DisplayPowerRequest.POLICY_DOZE; + mHolder.dpc.requestPowerState(dprInit, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState; initialize to DOZE + // Go to state=ON. But state change would be blocked. so, state=DOZE. + when(mDisplayOffloadSession.blockScreenOn(any())).thenReturn(true); + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.dozeScreenState = Display.STATE_ON; + dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; + dpr.useNormalBrightnessForDoze = true; + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState; process turning on. + + ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor = + ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); + verify(mHolder.brightnessSetting).registerListener(listenerCaptor.capture()); + BrightnessSetting.BrightnessSettingListener listener = listenerCaptor.getValue(); + listener.onBrightnessChanged(brightness); + advanceTime(1); // Send messages, run updatePowerState + + // When state=DOZE, force doze brightness regardless the requested policy. + verify(mHolder.animator).animateTo(eq(brightness * DOZE_SCALE_FACTOR), + /* linearSecondTarget= */ anyFloat(), /* rate= */ anyFloat(), + /* ignoreAnimationLimits= */ anyBoolean()); + } + + @Test public void testDozeManualBrightness_AbcIsNull() { when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true); mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ true, diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java index 50f814da6488..efa8b3ef775f 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java @@ -397,9 +397,9 @@ public class AutomaticBrightnessStrategyTest { mAutomaticBrightnessStrategy.setAutoBrightnessState(Display.STATE_DOZE, allowAutoBrightnessWhileDozing, brightnessReason, policy, useNormalBrightnessForDoze, lastUserSetBrightness, userSetBrightnessChanged); - // 1st AUTO_BRIGHTNESS_MODE_DEFAULT - verify(mAutomaticBrightnessController).switchMode( - AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT, + // 3rd AUTO_BRIGHTNESS_MODE_DOZE + verify(mAutomaticBrightnessController, times(3)).switchMode( + AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE, /* sendUpdate= */ false); // Validate interaction when automaticBrightnessController is in non-idle mode, display @@ -407,8 +407,8 @@ public class AutomaticBrightnessStrategyTest { mAutomaticBrightnessStrategy.setAutoBrightnessState(Display.STATE_ON, allowAutoBrightnessWhileDozing, brightnessReason, policy, useNormalBrightnessForDoze, lastUserSetBrightness, userSetBrightnessChanged); - // 2nd AUTO_BRIGHTNESS_MODE_DEFAULT - verify(mAutomaticBrightnessController, times(2)).switchMode( + // AUTO_BRIGHTNESS_MODE_DEFAULT + verify(mAutomaticBrightnessController).switchMode( AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT, /* sendUpdate= */ false); } 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 3dd2f24aa4e4..e863f1574932 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java @@ -40,7 +40,9 @@ import android.os.FileUtils; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; +import android.platform.test.flag.junit.SetFlagsRule; import android.text.TextUtils; import com.android.internal.os.Clock; @@ -87,6 +89,7 @@ public class ApplicationStartInfoTest { private static final String APP_1_PACKAGE_NAME = "com.android.test.stub1"; @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule(); + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @Mock private AppOpsService mAppOpsService; @Mock private PackageManagerInternal mPackageManagerInt; @@ -144,6 +147,7 @@ public class ApplicationStartInfoTest { } @Test + @EnableFlags(android.app.Flags.FLAG_APP_START_INFO_COMPONENT) public void testApplicationStartInfo() throws Exception { // Make sure we can write to the file. assertTrue(FileUtils.createDir(mAppStartInfoTracker.mProcStartStoreDir)); @@ -167,7 +171,7 @@ public class ApplicationStartInfoTest { ArrayList<ApplicationStartInfo> list = new ArrayList<ApplicationStartInfo>(); // Case 1: Activity start intent failed - mAppStartInfoTracker.onIntentStarted(buildIntent(COMPONENT), + mAppStartInfoTracker.onActivityIntentStarted(buildIntent(COMPONENT), appStartTimestampIntentStarted); mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID, APP_1_PID_1, 0, list); verifyInProgressRecordsSize(1); @@ -185,7 +189,7 @@ public class ApplicationStartInfoTest { ApplicationStartInfo.START_TYPE_UNSET, // state type ApplicationStartInfo.LAUNCH_MODE_STANDARD); // launch mode - mAppStartInfoTracker.onIntentFailed(appStartTimestampIntentStarted); + mAppStartInfoTracker.onActivityIntentFailed(appStartTimestampIntentStarted); list.clear(); mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID, APP_1_PID_1, 0, list); verifyInProgressRecordsSize(0); @@ -194,7 +198,7 @@ public class ApplicationStartInfoTest { mAppStartInfoTracker.clearProcessStartInfo(true); // Case 2: Activity start launch cancelled - mAppStartInfoTracker.onIntentStarted(buildIntent(COMPONENT), + mAppStartInfoTracker.onActivityIntentStarted(buildIntent(COMPONENT), appStartTimestampIntentStarted); list.clear(); mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID, APP_1_PID_1, 0, list); @@ -236,12 +240,13 @@ public class ApplicationStartInfoTest { ApplicationStartInfo.START_REASON_START_ACTIVITY, // reason ApplicationStartInfo.STARTUP_STATE_ERROR, // startup state ApplicationStartInfo.START_TYPE_COLD, // state type - ApplicationStartInfo.LAUNCH_MODE_STANDARD); // launch mode + ApplicationStartInfo.LAUNCH_MODE_STANDARD, // launch mode + ApplicationStartInfo.START_COMPONENT_ACTIVITY); // start component mAppStartInfoTracker.clearProcessStartInfo(true); // Case 3: Activity start success - mAppStartInfoTracker.onIntentStarted(buildIntent(COMPONENT), + mAppStartInfoTracker.onActivityIntentStarted(buildIntent(COMPONENT), appStartTimestampIntentStarted); list.clear(); mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID, APP_1_PID_1, 0, list); @@ -255,6 +260,7 @@ public class ApplicationStartInfoTest { verifyInProgressRecordsSize(1); assertEquals(list.size(), 1); + // The records will now be in both backing data structures, so verify in each. verifyInProgressApplicationStartInfo( 0, // index APP_1_PID_1, // pid @@ -277,7 +283,8 @@ public class ApplicationStartInfoTest { ApplicationStartInfo.START_REASON_START_ACTIVITY, // reason ApplicationStartInfo.STARTUP_STATE_STARTED, // startup state ApplicationStartInfo.START_TYPE_COLD, // state type - ApplicationStartInfo.LAUNCH_MODE_STANDARD); // launch mode + ApplicationStartInfo.LAUNCH_MODE_STANDARD, // launch mode + ApplicationStartInfo.START_COMPONENT_ACTIVITY); // start component mAppStartInfoTracker.onActivityLaunchFinished(appStartTimestampIntentStarted, COMPONENT, appStartTimestampActivityLaunchFinished, ApplicationStartInfo.LAUNCH_MODE_STANDARD); @@ -300,7 +307,7 @@ public class ApplicationStartInfoTest { ApplicationStartInfo.START_TYPE_COLD, // state type ApplicationStartInfo.LAUNCH_MODE_STANDARD); // launch mode - mAppStartInfoTracker.onReportFullyDrawn(appStartTimestampIntentStarted, + mAppStartInfoTracker.onActivityReportFullyDrawn(appStartTimestampIntentStarted, appStartTimestampReportFullyDrawn); list.clear(); mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID, APP_1_PID_1, 0, list); @@ -317,7 +324,8 @@ public class ApplicationStartInfoTest { ApplicationStartInfo.START_REASON_START_ACTIVITY, // reason ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN, // startup state ApplicationStartInfo.START_TYPE_COLD, // state type - ApplicationStartInfo.LAUNCH_MODE_STANDARD); // launch mode + ApplicationStartInfo.LAUNCH_MODE_STANDARD, // launch mode + ApplicationStartInfo.START_COMPONENT_ACTIVITY); // start component // Don't clear records for use in subsequent cases. @@ -347,7 +355,8 @@ public class ApplicationStartInfoTest { ApplicationStartInfo.START_REASON_SERVICE, // reason ApplicationStartInfo.STARTUP_STATE_STARTED, // startup state ApplicationStartInfo.START_TYPE_COLD, // state type - ApplicationStartInfo.LAUNCH_MODE_STANDARD); // launch mode + ApplicationStartInfo.LAUNCH_MODE_STANDARD, // launch mode + ApplicationStartInfo.START_COMPONENT_SERVICE); // start component // Case 5: Create an instance of app1 with a different user started for a broadcast sleep(1); @@ -376,7 +385,8 @@ public class ApplicationStartInfoTest { ApplicationStartInfo.START_REASON_BROADCAST, // reason ApplicationStartInfo.STARTUP_STATE_STARTED, // startup state ApplicationStartInfo.START_TYPE_COLD, // state type - ApplicationStartInfo.LAUNCH_MODE_STANDARD); // launch mode + ApplicationStartInfo.LAUNCH_MODE_STANDARD, // launch mode + ApplicationStartInfo.START_COMPONENT_BROADCAST); // start component // Case 6: User 2 gets removed mAppStartInfoTracker.onPackageRemoved(APP_1_PACKAGE_NAME, APP_1_UID_USER_2, false); @@ -422,7 +432,9 @@ public class ApplicationStartInfoTest { ApplicationStartInfo.START_REASON_CONTENT_PROVIDER, // reason ApplicationStartInfo.STARTUP_STATE_STARTED, // startup state ApplicationStartInfo.START_TYPE_COLD, // state type - ApplicationStartInfo.LAUNCH_MODE_STANDARD); // launch mode + ApplicationStartInfo.LAUNCH_MODE_STANDARD, // launch mode + ApplicationStartInfo.START_COMPONENT_CONTENT_PROVIDER // start component + ); // Case 8: Save and load again ArrayList<ApplicationStartInfo> original = new ArrayList<ApplicationStartInfo>(); @@ -453,6 +465,7 @@ public class ApplicationStartInfoTest { */ @SuppressWarnings("GuardedBy") @Test + @EnableFlags(android.app.Flags.FLAG_APP_START_INFO_COMPONENT) public void testInProgressRecordsLimit() throws Exception { ProcessRecord app = makeProcessRecord( APP_1_PID_1, // pid @@ -466,7 +479,7 @@ public class ApplicationStartInfoTest { // never exceeds the expected size of MAX_IN_PROGRESS_RECORDS. for (int i = 0; i < AppStartInfoTracker.MAX_IN_PROGRESS_RECORDS * 2; i++) { Long startTime = Long.valueOf(i); - mAppStartInfoTracker.onIntentStarted(buildIntent(COMPONENT), startTime); + mAppStartInfoTracker.onActivityIntentStarted(buildIntent(COMPONENT), startTime); verifyInProgressRecordsSize( Math.min(i + 1, AppStartInfoTracker.MAX_IN_PROGRESS_RECORDS)); @@ -509,8 +522,12 @@ public class ApplicationStartInfoTest { 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 +574,10 @@ public class ApplicationStartInfoTest { // 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) { @@ -613,6 +631,10 @@ public class ApplicationStartInfoTest { } } + /** + * Convenience helper to access the record from the in progress data structure. Only applies for + * activity starts. + */ private void verifyInProgressApplicationStartInfo(int index, Integer pid, Integer uid, Integer packageUid, Integer definingUid, String processName, @@ -620,14 +642,15 @@ public class ApplicationStartInfoTest { synchronized (mAppStartInfoTracker.mLock) { verifyApplicationStartInfo(mAppStartInfoTracker.mInProgressRecords.valueAt(index), pid, uid, packageUid, definingUid, processName, reason, startupState, - startType, launchMode); + startType, launchMode, ApplicationStartInfo.START_COMPONENT_ACTIVITY); } } private void verifyApplicationStartInfo(ApplicationStartInfo info, Integer pid, Integer uid, Integer packageUid, Integer definingUid, String processName, - Integer reason, Integer startupState, Integer startType, Integer launchMode) { + Integer reason, Integer startupState, Integer startType, Integer launchMode, + Integer startComponent) { assertNotNull(info); if (pid != null) { @@ -657,6 +680,9 @@ public class ApplicationStartInfoTest { if (launchMode != null) { assertEquals(launchMode.intValue(), info.getLaunchMode()); } + if (startComponent != null) { + assertEquals(startComponent.intValue(), info.getStartComponent()); + } } private class TestInjector extends Injector { 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 f6ad07d03673..2107406f9b13 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 @@ public class MockingOomAdjusterTests { 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/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java index b58c28bfbe62..54a02cf3cda3 100644 --- a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java @@ -268,6 +268,10 @@ public class PowerManagerServiceTest { mClock = new OffsettableClock.Stopped(); mTestLooper = new TestLooper(mClock::now); + DisplayInfo displayInfo = Mockito.mock(DisplayInfo.class); + displayInfo.displayGroupId = Display.DEFAULT_DISPLAY_GROUP; + when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)) + .thenReturn(displayInfo); } private PowerManagerService createService() { @@ -794,6 +798,57 @@ public class PowerManagerServiceTest { assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); } + @Test + public void testWakefulnessPerGroup_IPowerManagerWakeUpWithDisplayId() { + final int nonDefaultPowerGroupId = Display.DEFAULT_DISPLAY_GROUP + 1; + int displayInNonDefaultGroup = 1; + final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener = + new AtomicReference<>(); + long eventTime1 = 10; + long eventTime2 = eventTime1 + 1; + long eventTime3 = eventTime2 + 1; + doAnswer((Answer<Void>) invocation -> { + listener.set(invocation.getArgument(0)); + return null; + }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any()); + + createService(); + startSystem(); + listener.get().onDisplayGroupAdded(nonDefaultPowerGroupId); + + // Verify the global wakefulness is AWAKE + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); + + // Transition default display to doze, and verify the global wakefulness + mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_DOZING, eventTime1, + 0, PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE, 0, null, null); + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); + + // Transition the display from non default power group to doze, and verify the change in + // the global wakefulness + mService.setWakefulnessLocked(nonDefaultPowerGroupId, WAKEFULNESS_DOZING, eventTime2, + 0, PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null); + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING); + assertThat(mService.getWakefulnessLocked(nonDefaultPowerGroupId)) + .isEqualTo(WAKEFULNESS_DOZING); + + // Wakeup the display from the non default power group + DisplayInfo displayInfo = Mockito.mock(DisplayInfo.class); + displayInfo.displayGroupId = nonDefaultPowerGroupId; + when(mDisplayManagerInternalMock.getDisplayInfo(displayInNonDefaultGroup)) + .thenReturn(displayInfo); + mClock.fastForward(eventTime3); + mService.getBinderServiceInstance().wakeUpWithDisplayId(eventTime3, + PowerManager.WAKE_REASON_APPLICATION, "testing IPowerManager.wakeUp()", + "pkg.name", displayInNonDefaultGroup); + + assertThat(mService.getWakefulnessLocked(nonDefaultPowerGroupId)) + .isEqualTo(WAKEFULNESS_AWAKE); + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); + assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY)) + .isEqualTo(WAKEFULNESS_DOZING); + } + /** * Tests a series of variants that control whether a device wakes-up when it is plugged in * or docked. diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MouseKeysInterceptorTest.kt b/services/tests/servicestests/src/com/android/server/accessibility/MouseKeysInterceptorTest.kt index 019ccf93fa11..c76392b30276 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/MouseKeysInterceptorTest.kt +++ b/services/tests/servicestests/src/com/android/server/accessibility/MouseKeysInterceptorTest.kt @@ -61,7 +61,6 @@ class MouseKeysInterceptorTest { companion object { const val DISPLAY_ID = 1 const val DEVICE_ID = 123 - const val MOUSE_POINTER_MOVEMENT_STEP = 1.8f // This delay is required for key events to be sent and handled correctly. // The handler only performs a move/scroll event if it receives the key event // at INTERVAL_MILLIS (which happens in practice). Hence, we need this delay in the tests. @@ -159,8 +158,8 @@ class MouseKeysInterceptorTest { testLooper.dispatchAll() // Verify the sendRelativeEvent method is called once and capture the arguments - verifyRelativeEvents(arrayOf(-MOUSE_POINTER_MOVEMENT_STEP / sqrt(2.0f)), - arrayOf(MOUSE_POINTER_MOVEMENT_STEP / sqrt(2.0f))) + verifyRelativeEvents(arrayOf(-MouseKeysInterceptor.MOUSE_POINTER_MOVEMENT_STEP / sqrt(2.0f)), + arrayOf(MouseKeysInterceptor.MOUSE_POINTER_MOVEMENT_STEP / sqrt(2.0f))) } @Test @@ -232,7 +231,8 @@ class MouseKeysInterceptorTest { testLooper.dispatchAll() // Verify the sendScrollEvent method is called once and capture the arguments - verifyScrollEvents(arrayOf<Float>(0f), arrayOf<Float>(1.0f)) + verifyScrollEvents(arrayOf<Float>(0f), + arrayOf<Float>(MouseKeysInterceptor.MOUSE_SCROLL_STEP)) } @Test @@ -247,7 +247,8 @@ class MouseKeysInterceptorTest { testLooper.dispatchAll() // Verify the sendRelativeEvent method is called once and capture the arguments - verifyRelativeEvents(arrayOf<Float>(0f), arrayOf<Float>(-MOUSE_POINTER_MOVEMENT_STEP)) + verifyRelativeEvents(arrayOf<Float>(0f), + arrayOf<Float>(-MouseKeysInterceptor.MOUSE_POINTER_MOVEMENT_STEP)) } private fun verifyRelativeEvents(expectedX: Array<Float>, expectedY: Array<Float>) { diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java index 598d3a3a9f8a..b745e6a7d4a5 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java @@ -32,6 +32,7 @@ import static com.android.server.testutils.TestUtils.strictMock; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -64,6 +65,7 @@ import android.graphics.Rect; import android.graphics.Region; import android.os.Handler; import android.os.Message; +import android.os.SystemClock; import android.os.UserHandle; import android.os.VibrationEffect; import android.os.Vibrator; @@ -105,6 +107,7 @@ import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.function.IntConsumer; @@ -700,6 +703,15 @@ public class FullScreenMagnificationGestureHandlerTest { } @Test + public void testIntervalsOf_sendMotionEventInfo_returnMatchIntervals() { + FullScreenMagnificationGestureHandler.MotionEventInfo upEventQueue = + createEventQueue(ACTION_UP, 0, 100, 300); + + List<Long> upIntervals = mMgh.mDetectingState.intervalsOf(upEventQueue, ACTION_UP); + assertEquals(Arrays.asList(100L, 200L), upIntervals); + } + + @Test public void testMagnifierDeactivates_shortcutTriggeredState_returnToIdleState() { goFromStateIdleTo(STATE_SHORTCUT_TRIGGERED); @@ -2294,6 +2306,31 @@ public class FullScreenMagnificationGestureHandlerTest { return event; } + private FullScreenMagnificationGestureHandler.MotionEventInfo createEventQueue( + int eventType, long... delays) { + FullScreenMagnificationGestureHandler.MotionEventInfo eventQueue = null; + long currentTime = SystemClock.uptimeMillis(); + + for (int i = 0; i < delays.length; i++) { + MotionEvent event = MotionEvent.obtain(currentTime + delays[i], + currentTime + delays[i], eventType, 0, 0, 0); + + FullScreenMagnificationGestureHandler.MotionEventInfo info = + FullScreenMagnificationGestureHandler.MotionEventInfo + .obtain(event, MotionEvent.obtain(event), 0); + + if (eventQueue == null) { + eventQueue = info; + } else { + FullScreenMagnificationGestureHandler.MotionEventInfo tail = eventQueue; + while (tail.getNext() != null) { + tail = tail.getNext(); + } + tail.setNext(info); + } + } + return eventQueue; + } private String stateDump() { return "\nCurrent state dump:\n" + mMgh + "\n" + mHandler.getPendingMessages(); diff --git a/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java b/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java index b09e9b119984..54282ff7fadb 100644 --- a/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java +++ b/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java @@ -119,7 +119,7 @@ public class AnrTimerTest { */ private class TestInjector extends AnrTimer.Injector { @Override - boolean anrTimerServiceEnabled() { + boolean serviceEnabled() { return mEnabled; } } 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 b8f9767b5512..130690d80b70 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -38,6 +38,7 @@ import static android.app.Notification.FLAG_NO_CLEAR; import static android.app.Notification.FLAG_NO_DISMISS; import static android.app.Notification.FLAG_ONGOING_EVENT; import static android.app.Notification.FLAG_ONLY_ALERT_ONCE; +import static android.app.Notification.FLAG_PROMOTED_ONGOING; import static android.app.Notification.FLAG_USER_INITIATED_JOB; import static android.app.Notification.GROUP_ALERT_CHILDREN; import static android.app.Notification.VISIBILITY_PRIVATE; @@ -53,6 +54,7 @@ import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_HIGH; import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_MAX; +import static android.app.NotificationManager.IMPORTANCE_MIN; import static android.app.NotificationManager.IMPORTANCE_NONE; import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS; @@ -468,6 +470,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { NotificationChannel mSilentChannel = new NotificationChannel("low", "low", IMPORTANCE_LOW); + NotificationChannel mMinChannel = new NotificationChannel("min", "min", IMPORTANCE_MIN); + private static final int NOTIFICATION_LOCATION_UNKNOWN = 0; private static final String VALID_CONVO_SHORTCUT_ID = "shortcut"; @@ -558,8 +562,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Parameters(name = "{0}") public static List<FlagsParameterization> getParams() { - return FlagsParameterization.allCombinationsOf( - FLAG_ALL_NOTIFS_NEED_TTL); + return FlagsParameterization.allCombinationsOf(); } public NotificationManagerServiceTest(FlagsParameterization flags) { @@ -856,15 +859,17 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mInternalService = mService.getInternalService(); mBinderService.createNotificationChannels(mPkg, new ParceledListSlice( - Arrays.asList(mTestNotificationChannel, mSilentChannel))); + Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel))); mBinderService.createNotificationChannels(PKG_P, new ParceledListSlice( - Arrays.asList(mTestNotificationChannel, mSilentChannel))); + Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel))); mBinderService.createNotificationChannels(PKG_O, new ParceledListSlice( - Arrays.asList(mTestNotificationChannel, mSilentChannel))); + Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel))); assertNotNull(mBinderService.getNotificationChannel( mPkg, mContext.getUserId(), mPkg, TEST_CHANNEL_ID)); assertNotNull(mBinderService.getNotificationChannel( mPkg, mContext.getUserId(), mPkg, mSilentChannel.getId())); + assertNotNull(mBinderService.getNotificationChannel( + mPkg, mContext.getUserId(), mPkg, mMinChannel.getId())); clearInvocations(mRankingHandler); when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); @@ -943,6 +948,16 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } } + private ShortcutInfo createMockConvoShortcut() { + ShortcutInfo info = mock(ShortcutInfo.class); + when(info.getPackage()).thenReturn(mPkg); + when(info.getId()).thenReturn(VALID_CONVO_SHORTCUT_ID); + when(info.getUserId()).thenReturn(USER_SYSTEM); + when(info.isLongLived()).thenReturn(true); + when(info.isEnabled()).thenReturn(true); + return info; + } + private void simulatePackageSuspendBroadcast(boolean suspend, String pkg, int uid) { // mimics receive broadcast that package is (un)suspended @@ -16540,13 +16555,298 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID); } - private ShortcutInfo createMockConvoShortcut() { - ShortcutInfo info = mock(ShortcutInfo.class); - when(info.getPackage()).thenReturn(mPkg); - when(info.getId()).thenReturn(VALID_CONVO_SHORTCUT_ID); - when(info.getUserId()).thenReturn(USER_SYSTEM); - when(info.isLongLived()).thenReturn(true); - when(info.isEnabled()).thenReturn(true); - return info; + @Test + @EnableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING) + public void testSetCanBePromoted_granted() throws Exception { + mContext.getTestablePermissions().setPermission( + android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED); + // qualifying posted notification + Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) + .setColor(Color.WHITE) + .setColorized(true) + .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post + .build(); + + StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + // qualifying enqueued notification + Notification n1 = new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) + .setColor(Color.WHITE) + .setColorized(true) + .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post + .build(); + StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 7, null, mUid, 0, + n1, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r1 = new NotificationRecord(mContext, sbn1, mTestNotificationChannel); + + // another package but otherwise would qualify + Notification n2 = new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) + .setColor(Color.WHITE) + .setColorized(true) + .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post + .build(); + StatusBarNotification sbn2 = new StatusBarNotification(PKG_O, PKG_O, 7, null, UID_O, 0, + n2, UserHandle.getUserHandleForUid(UID_O), null, 0); + NotificationRecord r2 = new NotificationRecord(mContext, sbn2, mTestNotificationChannel); + + // not-qualifying posted notification + Notification n3 = new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .build(); + + StatusBarNotification sbn3 = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, + n3, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r3 = new NotificationRecord(mContext, sbn3, mTestNotificationChannel); + + mService.addNotification(r3); + mService.addNotification(r2); + mService.addNotification(r); + mService.addEnqueuedNotification(r1); + + mBinderService.setCanBePromoted(mPkg, mUid, true); + + waitForIdle(); + + ArgumentCaptor<NotificationRecord> captor = + ArgumentCaptor.forClass(NotificationRecord.class); + verify(mListeners, times(1)).prepareNotifyPostedLocked( + captor.capture(), any(), anyBoolean()); + + // the posted one + assertThat(mService.hasFlag(captor.getValue().getNotification().flags, + FLAG_PROMOTED_ONGOING)).isTrue(); + // the enqueued one + assertThat(mService.hasFlag(r1.getNotification().flags, FLAG_PROMOTED_ONGOING)).isTrue(); + // the other app + assertThat(mService.hasFlag(r2.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse(); + // same app, not qualifying + assertThat(mService.hasFlag(r3.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse(); + } + + @Test + @EnableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING) + public void testSetCanBePromoted_granted_onlyNotifiesOnce() throws Exception { + mContext.getTestablePermissions().setPermission( + android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED); + // qualifying posted notification + Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) + .setColor(Color.WHITE) + .setColorized(true) + .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post + .build(); + + StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + mService.addNotification(r); + + mBinderService.setCanBePromoted(mPkg, mUid, true); + waitForIdle(); + mBinderService.setCanBePromoted(mPkg, mUid, true); + waitForIdle(); + + ArgumentCaptor<NotificationRecord> captor = + ArgumentCaptor.forClass(NotificationRecord.class); + verify(mListeners, times(1)).prepareNotifyPostedLocked( + captor.capture(), any(), anyBoolean()); + } + + @Test + @EnableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING) + public void testSetCanBePromoted_revoked() throws Exception { + mContext.getTestablePermissions().setPermission( + android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED); + // start from true state + mBinderService.setCanBePromoted(mPkg, mUid, true); + + // qualifying posted notification + Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) + .setColor(Color.WHITE) + .setColorized(true) + .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post + .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post + .build(); + + StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + // qualifying enqueued notification + Notification n1 = new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) + .setColor(Color.WHITE) + .setColorized(true) + .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post + .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post + .build(); + StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 7, null, mUid, 0, + n1, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r1 = new NotificationRecord(mContext, sbn1, mTestNotificationChannel); + + // doesn't qualify, same package + Notification n2 = new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .build(); + StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, + n2, UserHandle.getUserHandleForUid(UID_O), null, 0); + NotificationRecord r2 = new NotificationRecord(mContext, sbn2, mTestNotificationChannel); + + mService.addNotification(r2); + mService.addNotification(r); + mService.addEnqueuedNotification(r1); + + mBinderService.setCanBePromoted(mPkg, mUid, false); + + waitForIdle(); + + ArgumentCaptor<NotificationRecord> captor = + ArgumentCaptor.forClass(NotificationRecord.class); + verify(mListeners, times(1)).prepareNotifyPostedLocked( + captor.capture(), any(), anyBoolean()); + + // the posted one + assertThat(mService.hasFlag(captor.getValue().getNotification().flags, + FLAG_PROMOTED_ONGOING)).isFalse(); + // the enqueued one + assertThat(mService.hasFlag(r1.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse(); + // the not qualifying one + assertThat(mService.hasFlag(r2.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse(); + } + + @Test + @EnableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING) + public void testSetCanBePromoted_revoked_onlyNotifiesOnce() throws Exception { + mContext.getTestablePermissions().setPermission( + android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED); + // start from true state + mBinderService.setCanBePromoted(mPkg, mUid, true); + + // qualifying posted notification + Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) + .setColor(Color.WHITE) + .setColorized(true) + .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post + .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post + .build(); + + StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + mService.addNotification(r); + + mBinderService.setCanBePromoted(mPkg, mUid, false); + waitForIdle(); + mBinderService.setCanBePromoted(mPkg, mUid, false); + waitForIdle(); + + ArgumentCaptor<NotificationRecord> captor = + ArgumentCaptor.forClass(NotificationRecord.class); + verify(mListeners, times(1)).prepareNotifyPostedLocked( + captor.capture(), any(), anyBoolean()); + } + + @Test + @EnableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING) + public void testPostPromotableNotification() throws Exception { + mBinderService.setCanBePromoted(mPkg, mUid, true); + assertThat(mBinderService.canBePromoted(mPkg, mUid)).isTrue(); + mContext.getTestablePermissions().setPermission( + android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED); + + Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) + .setColor(Color.WHITE) + .setColorized(true) + .build(); + //assertThat(n.hasPromotableCharacteristics()).isTrue(); + StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + + mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), + sbn.getId(), sbn.getNotification(), sbn.getUserId()); + waitForIdle(); + + ArgumentCaptor<NotificationRecord> captor = + ArgumentCaptor.forClass(NotificationRecord.class); + verify(mListeners, times(1)).prepareNotifyPostedLocked( + captor.capture(), any(), anyBoolean()); + + assertThat(mService.hasFlag(captor.getValue().getNotification().flags, + FLAG_PROMOTED_ONGOING)).isTrue(); + } + + @Test + @EnableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING) + public void testPostPromotableNotification_noPermission() throws Exception { + mContext.getTestablePermissions().setPermission( + android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED); + Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) + .setColor(Color.WHITE) + .setColorized(true) + .build(); + + StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + + mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), + sbn.getId(), sbn.getNotification(), sbn.getUserId()); + waitForIdle(); + + ArgumentCaptor<NotificationRecord> captor = + ArgumentCaptor.forClass(NotificationRecord.class); + verify(mListeners, times(1)).prepareNotifyPostedLocked( + captor.capture(), any(), anyBoolean()); + + assertThat(mService.hasFlag(captor.getValue().getNotification().flags, + FLAG_PROMOTED_ONGOING)).isFalse(); + } + + @Test + @EnableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING) + public void testPostPromotableNotification_unimportantNotification() throws Exception { + mBinderService.setCanBePromoted(mPkg, mUid, true); + mContext.getTestablePermissions().setPermission( + android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED); + Notification n = new Notification.Builder(mContext, mMinChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) + .setColor(Color.WHITE) + .setColorized(true) + .build(); + + StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + + mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), + sbn.getId(), sbn.getNotification(), sbn.getUserId()); + waitForIdle(); + + ArgumentCaptor<NotificationRecord> captor = + ArgumentCaptor.forClass(NotificationRecord.class); + verify(mListeners, times(1)).prepareNotifyPostedLocked( + captor.capture(), any(), anyBoolean()); + + assertThat(mService.hasFlag(captor.getValue().getNotification().flags, + FLAG_PROMOTED_ONGOING)).isFalse(); } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 1905ae4aec4b..7d63062784f9 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -518,6 +518,17 @@ public class PreferencesHelperTest extends UiServiceTestCase { doneLatch.await(); } + private static NotificationChannel cloneChannel(NotificationChannel original) { + Parcel parcel = Parcel.obtain(); + try { + original.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + return NotificationChannel.CREATOR.createFromParcel(parcel); + } finally { + parcel.recycle(); + } + } + @Test public void testWriteXml_onlyBackupsTargetUser() throws Exception { // Setup package notifications. @@ -631,6 +642,9 @@ public class PreferencesHelperTest extends UiServiceTestCase { } mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true); + if (android.app.Flags.uiRichOngoing()) { + mHelper.setCanBePromoted(PKG_N_MR1, UID_N_MR1, true); + } ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false, UserHandle.USER_ALL, channel1.getId(), channel2.getId(), @@ -641,6 +655,9 @@ public class PreferencesHelperTest extends UiServiceTestCase { loadStreamXml(baos, false, UserHandle.USER_ALL); assertTrue(mXmlHelper.canShowBadge(PKG_N_MR1, UID_N_MR1)); + if (android.app.Flags.uiRichOngoing()) { + assertThat(mXmlHelper.canBePromoted(PKG_N_MR1, UID_N_MR1)).isTrue(); + } assertEquals(channel1, mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false)); compareChannels(channel2, @@ -6293,14 +6310,21 @@ public class PreferencesHelperTest extends UiServiceTestCase { }, 20, 50); } - private static NotificationChannel cloneChannel(NotificationChannel original) { - Parcel parcel = Parcel.obtain(); - try { - original.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - return NotificationChannel.CREATOR.createFromParcel(parcel); - } finally { - parcel.recycle(); - } + @Test + @EnableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING) + public void testNoAppHasPermissionToPromoteByDefault() { + mHelper.setShowBadge(PKG_P, UID_P, true); + assertThat(mHelper.canBePromoted(PKG_P, UID_P)).isFalse(); + } + + @Test + @EnableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING) + public void testSetCanBePromoted() { + mHelper.setCanBePromoted(PKG_P, UID_P, true); + assertThat(mHelper.canBePromoted(PKG_P, UID_P)).isTrue(); + + mHelper.setCanBePromoted(PKG_P, UID_P, false); + assertThat(mHelper.canBePromoted(PKG_P, UID_P)).isFalse(); + verify(mHandler, never()).requestSort(); } } 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 9b87947b6980..d4cba8d726fb 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -18,7 +18,7 @@ package com.android.server.notification; import static android.app.AutomaticZenRule.TYPE_BEDTIME; import static android.app.AutomaticZenRule.TYPE_IMMERSIVE; -import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR; +import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME; import static android.app.AutomaticZenRule.TYPE_UNKNOWN; import static android.app.Flags.FLAG_MODES_API; import static android.app.Flags.FLAG_MODES_UI; @@ -221,7 +221,7 @@ import platform.test.runner.parameterized.Parameters; @TestableLooper.RunWithLooper public class ZenModeHelperTest extends UiServiceTestCase { - private static final String EVENTS_DEFAULT_RULE_ID = ZenModeConfig.EVENTS_DEFAULT_RULE_ID; + private static final String EVENTS_DEFAULT_RULE_ID = ZenModeConfig.EVENTS_OBSOLETE_RULE_ID; private static final String SCHEDULE_DEFAULT_RULE_ID = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID; private static final String CUSTOM_PKG_NAME = "not.android"; @@ -1216,7 +1216,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { // list for tracking which ids we've seen in the pulled atom output List<String> ids = new ArrayList<>(); - ids.addAll(ZenModeConfig.DEFAULT_RULE_IDS); + ids.addAll(ZenModeConfig.getDefaultRuleIds()); ids.add(""); // empty string for root config for (StatsEvent ev : events) { @@ -1793,14 +1793,13 @@ public class ZenModeHelperTest extends UiServiceTestCase { // check default rules ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules; assertTrue(rules.size() != 0); - for (String defaultId : ZenModeConfig.DEFAULT_RULE_IDS) { + for (String defaultId : ZenModeConfig.getDefaultRuleIds()) { assertTrue(rules.containsKey(defaultId)); } assertEquals(originalPolicy, mZenModeHelper.getNotificationPolicy()); } - @Test public void testReadXmlAllDisabledRulesResetDefaultRules() throws Exception { setupZenConfig(); @@ -1830,7 +1829,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { // check default rules ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules; assertTrue(rules.size() != 0); - for (String defaultId : ZenModeConfig.DEFAULT_RULE_IDS) { + for (String defaultId : ZenModeConfig.getDefaultRuleIds()) { assertTrue(rules.containsKey(defaultId)); } assertFalse(rules.containsKey("customRule")); @@ -1839,6 +1838,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { } @Test + @DisableFlags(FLAG_MODES_UI) // modes_ui has only 1 default rule public void testReadXmlOnlyOneDefaultRuleExists() throws Exception { setupZenConfig(); Policy originalPolicy = mZenModeHelper.getNotificationPolicy(); @@ -1882,11 +1882,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { // check default rules ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules; - assertTrue(rules.size() != 0); - for (String defaultId : ZenModeConfig.DEFAULT_RULE_IDS) { - assertTrue(rules.containsKey(defaultId)); + assertThat(rules).isNotEmpty(); + for (String defaultId : ZenModeConfig.getDefaultRuleIds()) { + assertThat(rules).containsKey(defaultId); } - assertFalse(rules.containsKey("customRule")); + assertThat(rules).doesNotContainKey("customRule"); assertEquals(originalPolicy, mZenModeHelper.getNotificationPolicy()); } @@ -1932,13 +1932,13 @@ public class ZenModeHelperTest extends UiServiceTestCase { defaultEventRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; defaultEventRule.conditionId = ZenModeConfig.toScheduleConditionId( defaultEventRuleInfo); - defaultEventRule.id = ZenModeConfig.EVENTS_DEFAULT_RULE_ID; + defaultEventRule.id = ZenModeConfig.EVENTS_OBSOLETE_RULE_ID; defaultScheduleRule.zenPolicy = new ZenPolicy.Builder() .allowAlarms(false) .allowMedia(false) .allowRepeatCallers(false) .build(); - automaticRules.put(ZenModeConfig.EVENTS_DEFAULT_RULE_ID, defaultEventRule); + automaticRules.put(ZenModeConfig.EVENTS_OBSOLETE_RULE_ID, defaultEventRule); mZenModeHelper.mConfig.automaticRules = automaticRules; @@ -1951,18 +1951,19 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL); // check default rules + int expectedNumAutoRules = 1 + ZenModeConfig.getDefaultRuleIds().size(); // custom + default ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules; - assertEquals(3, rules.size()); - for (String defaultId : ZenModeConfig.DEFAULT_RULE_IDS) { - assertTrue(rules.containsKey(defaultId)); + assertThat(rules).hasSize(expectedNumAutoRules); + for (String defaultId : ZenModeConfig.getDefaultRuleIds()) { + assertThat(rules).containsKey(defaultId); } - assertTrue(rules.containsKey("customRule")); + assertThat(rules).containsKey("customRule"); assertEquals(originalPolicy, mZenModeHelper.getNotificationPolicy()); List<StatsEvent> events = new LinkedList<>(); mZenModeHelper.pullRules(events); - assertEquals(4, events.size()); + assertThat(events).hasSize(expectedNumAutoRules + 1); // auto + manual } @Test @@ -2151,8 +2152,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { defaultEventRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; defaultEventRule.conditionId = ZenModeConfig.toScheduleConditionId( defaultEventRuleInfo); - defaultEventRule.id = ZenModeConfig.EVENTS_DEFAULT_RULE_ID; - automaticRules.put(ZenModeConfig.EVENTS_DEFAULT_RULE_ID, defaultEventRule); + defaultEventRule.id = ZenModeConfig.EVENTS_OBSOLETE_RULE_ID; + automaticRules.put(ZenModeConfig.EVENTS_OBSOLETE_RULE_ID, defaultEventRule); mZenModeHelper.mConfig.automaticRules = automaticRules; @@ -2167,7 +2168,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { // check default rules ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules; assertThat(rules.size()).isGreaterThan(0); - for (String defaultId : ZenModeConfig.DEFAULT_RULE_IDS) { + for (String defaultId : ZenModeConfig.getDefaultRuleIds()) { assertThat(rules).containsKey(defaultId); ZenRule rule = rules.get(defaultId); assertThat(rule.zenPolicy).isNotNull(); @@ -2371,7 +2372,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { // Find default rules; check they have non-null policies; check that they match the default // and not whatever has been set up in setupZenConfig. ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules; - for (String defaultId : ZenModeConfig.DEFAULT_RULE_IDS) { + for (String defaultId : ZenModeConfig.getDefaultRuleIds()) { assertThat(rules).containsKey(defaultId); ZenRule rule = rules.get(defaultId); assertThat(rule.zenPolicy).isNotNull(); @@ -6884,7 +6885,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelper.onUserSwitched(101); ZenRule eventsRule = mZenModeHelper.mConfig.automaticRules.get( - ZenModeConfig.EVENTS_DEFAULT_RULE_ID); + ZenModeConfig.EVENTS_OBSOLETE_RULE_ID); assertThat(eventsRule).isNotNull(); assertThat(eventsRule.zenPolicy).isNull(); @@ -6900,7 +6901,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelper.onUserSwitched(201); ZenRule eventsRule = mZenModeHelper.mConfig.automaticRules.get( - ZenModeConfig.EVENTS_DEFAULT_RULE_ID); + ZenModeConfig.EVENTS_OBSOLETE_RULE_ID); assertThat(eventsRule).isNotNull(); assertThat(eventsRule.zenPolicy).isEqualTo(mZenModeHelper.getDefaultZenPolicy()); @@ -6915,11 +6916,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelper.onUserSwitched(301); ZenRule eventsRule = mZenModeHelper.mConfig.automaticRules.get( - ZenModeConfig.EVENTS_DEFAULT_RULE_ID); + ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID); assertThat(eventsRule).isNotNull(); assertThat(eventsRule.zenPolicy).isEqualTo(mZenModeHelper.getDefaultZenPolicy()); - assertThat(eventsRule.type).isEqualTo(TYPE_SCHEDULE_CALENDAR); + assertThat(eventsRule.type).isEqualTo(TYPE_SCHEDULE_TIME); assertThat(eventsRule.triggerDescription).isNotEmpty(); } @@ -6992,6 +6993,62 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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()); + } + + @Test + @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI}) + public void readXml_withDisabledEventsRule_deletesIt() throws Exception { + ZenRule rule = new ZenRule(); + rule.id = ZenModeConfig.EVENTS_OBSOLETE_RULE_ID; + rule.name = "Events"; + rule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + rule.conditionId = Uri.parse("events"); + + rule.enabled = false; + mZenModeHelper.mConfig.automaticRules.put(ZenModeConfig.EVENTS_OBSOLETE_RULE_ID, rule); + ByteArrayOutputStream xmlBytes = writeXmlAndPurge(ZenModeConfig.XML_VERSION_MODES_UI); + TypedXmlPullParser parser = getParserForByteStream(xmlBytes); + + mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL); + + assertThat(mZenModeHelper.mConfig.automaticRules).doesNotContainKey( + ZenModeConfig.EVENTS_OBSOLETE_RULE_ID); + } + + @Test + @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI}) + public void readXml_withEnabledEventsRule_keepsIt() throws Exception { + ZenRule rule = new ZenRule(); + rule.id = ZenModeConfig.EVENTS_OBSOLETE_RULE_ID; + rule.name = "Events"; + rule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + rule.conditionId = Uri.parse("events"); + + rule.enabled = true; + mZenModeHelper.mConfig.automaticRules.put(ZenModeConfig.EVENTS_OBSOLETE_RULE_ID, rule); + ByteArrayOutputStream xmlBytes = writeXmlAndPurge(ZenModeConfig.XML_VERSION_MODES_UI); + TypedXmlPullParser parser = getParserForByteStream(xmlBytes); + + mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL); + + assertThat(mZenModeHelper.mConfig.automaticRules).containsKey( + ZenModeConfig.EVENTS_OBSOLETE_RULE_ID); + } + private static void addZenRule(ZenModeConfig config, String id, String ownerPkg, int zenMode, @Nullable ZenPolicy zenPolicy) { ZenRule rule = new ZenRule(); diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java index 4012575cda88..d99b20c689dd 100644 --- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -1538,7 +1538,6 @@ public class VibratorManagerServiceTest { PrebakedSegment segment = (PrebakedSegment) playedSegments.get(0); assertEquals(VibrationEffect.EFFECT_CLICK, segment.getEffectId()); VibrationAttributes attrs = vibration.callerInfo.attrs; - assertEquals(VibrationAttributes.USAGE_HARDWARE_FEEDBACK, attrs.getUsage()); assertTrue(attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)); assertTrue(attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY)); } @@ -1560,11 +1559,11 @@ public class VibratorManagerServiceTest { HapticFeedbackConstants.SCROLL_TICK, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)); mHapticFeedbackVibrationMapSourceTouchScreen.put( - HapticFeedbackConstants.DRAG_START, - VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK)); + HapticFeedbackConstants.SCROLL_ITEM_FOCUS, + VibrationEffect.createPredefined(VibrationEffect.EFFECT_THUD)); mockVibrators(1); FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); - fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_TICK); + fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_THUD); VibratorManagerService service = createSystemReadyService(); HalVibration vibrationByRotary = @@ -1573,7 +1572,7 @@ public class VibratorManagerServiceTest { InputDevice.SOURCE_ROTARY_ENCODER, /* always= */ true); HalVibration vibrationByTouchScreen = performHapticFeedbackForInputDeviceAndWaitUntilFinished( - service, HapticFeedbackConstants.DRAG_START, /* inputDeviceId= */ 0, + service, HapticFeedbackConstants.SCROLL_ITEM_FOCUS, /* inputDeviceId= */ 0, InputDevice.SOURCE_TOUCHSCREEN, /* always= */ true); List<VibrationEffectSegment> playedSegments = fakeVibrator.getAllEffectSegments(); @@ -1583,18 +1582,17 @@ public class VibratorManagerServiceTest { PrebakedSegment segmentByRotary = (PrebakedSegment) playedSegments.get(0); assertEquals(VibrationEffect.EFFECT_CLICK, segmentByRotary.getEffectId()); VibrationAttributes attrsByRotary = vibrationByRotary.callerInfo.attrs; - assertEquals(VibrationAttributes.USAGE_HARDWARE_FEEDBACK, attrsByRotary.getUsage()); assertTrue(attrsByRotary.isFlagSet( VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)); assertTrue(attrsByRotary.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY)); // Verify feedback by touch screen input PrebakedSegment segmentByTouchScreen = (PrebakedSegment) playedSegments.get(1); - assertEquals(VibrationEffect.EFFECT_TICK, segmentByTouchScreen.getEffectId()); + assertEquals(VibrationEffect.EFFECT_THUD, segmentByTouchScreen.getEffectId()); VibrationAttributes attrsByTouchScreen = vibrationByTouchScreen.callerInfo.attrs; - assertEquals(VibrationAttributes.USAGE_TOUCH, attrsByTouchScreen.getUsage()); - assertTrue(attrsByRotary.isFlagSet( + assertTrue(attrsByTouchScreen.isFlagSet( VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)); - assertTrue(attrsByRotary.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY)); + assertTrue( + attrsByTouchScreen.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY)); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java index e8d089c61362..457058849fca 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java @@ -188,7 +188,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { assertNull(mProvider.getLeash(target)); // Set the leash to be ready for dispatching. - mProvider.mIsLeashReadyForDispatching = true; + mProvider.mIsLeashInitialized = true; assertNotNull(mProvider.getLeash(target)); // We do have fake control for the fake control target, but that has no leash. diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java index 1be61c36f272..66d7963946b9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java @@ -494,6 +494,21 @@ public class LaunchParamsPersisterTests extends WindowTestsBase { assertTrue("Result should be empty.", mResult.isEmpty()); } + @Test + public void testAbortsLoadingWhenUserCleansUpBeforeLoadingFinishes() { + mTarget.saveTask(mTestTask); + mPersisterQueue.flush(); + + final LaunchParamsPersister target = new LaunchParamsPersister(mPersisterQueue, mSupervisor, + mUserFolderGetter); + target.onSystemReady(); + target.onUnlockUser(TEST_USER_ID); + target.onCleanupUser(TEST_USER_ID); + + target.getLaunchParams(mTestTask, null, mResult); + assertTrue("Result should be empty.", mResult.isEmpty()); + } + private static boolean deleteRecursively(File file) { boolean result = true; if (file.isDirectory()) { diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index 8f3d3c5a86e9..e0344d73f540 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -70,7 +70,10 @@ import android.os.Bundle; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserManager; +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.util.ArraySet; import android.util.IntArray; import android.util.SparseBooleanArray; @@ -79,9 +82,12 @@ import android.window.TaskSnapshot; import androidx.test.filters.MediumTest; +import com.android.launcher3.Flags; import com.android.server.wm.RecentTasks.Callbacks; import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -122,6 +128,10 @@ public class RecentTasksTest extends WindowTestsBase { private CallbacksRecorder mCallbacksRecorder; + @Rule + public SetFlagsRule mSetFlagsRule = + new SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT); + @Before public void setUp() throws Exception { mTaskPersister = new TestTaskPersister(mContext.getFilesDir()); @@ -697,14 +707,31 @@ public class RecentTasksTest extends WindowTestsBase { } @Test + @DisableFlags(Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL) public void testVisibleTasks_excludedFromRecents() { + testVisibleTasks_excludedFromRecents_internal(); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL) + public void testVisibleTasks_excludedFromRecents_withRefactorFlag() { + testVisibleTasks_excludedFromRecents_internal(); + } + + private void testVisibleTasks_excludedFromRecents_internal() { mRecentTasks.setParameters(-1 /* min */, 4 /* max */, -1 /* ms */); - Task excludedTask1 = createTaskBuilder(".ExcludedTask1") + Task invisibleExcludedTask = createTaskBuilder(".ExcludedTask1") .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + .setCreateActivity(true) .build(); - Task excludedTask2 = createTaskBuilder(".ExcludedTask2") + ActivityRecord activityRecord = invisibleExcludedTask.getTopMostActivity(); + activityRecord.setVisibleRequested(false); + activityRecord.setVisible(false); + + Task visibleExcludedTask = createTaskBuilder(".ExcludedTask2") .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + .setCreateActivity(true) .build(); Task detachedExcludedTask = createTaskBuilder(".DetachedExcludedTask") .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) @@ -718,18 +745,79 @@ public class RecentTasksTest extends WindowTestsBase { assertFalse(detachedExcludedTask.isAttached()); mRecentTasks.add(detachedExcludedTask); - mRecentTasks.add(excludedTask1); + mRecentTasks.add(invisibleExcludedTask); mRecentTasks.add(mTasks.get(0)); mRecentTasks.add(mTasks.get(1)); mRecentTasks.add(mTasks.get(2)); - mRecentTasks.add(excludedTask2); + mRecentTasks.add(visibleExcludedTask); - // Except the first-most excluded task, other excluded tasks should be trimmed. - triggerTrimAndAssertTrimmed(excludedTask1, detachedExcludedTask); + // Excluded tasks should be trimmed, except those with a visible activity. + triggerTrimAndAssertTrimmed(invisibleExcludedTask, detachedExcludedTask); } @Test + @Ignore("b/342627272") + @DisableFlags(Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL) + public void testVisibleTasks_excludedFromRecents_visibleTaskNotFirstTask() { + testVisibleTasks_excludedFromRecents_visibleTaskNotFirstTask_internal(); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL) + public void testVisibleTasks_excludedFromRecents_visibleTaskNotFirstTask_withRefactorFlag() { + testVisibleTasks_excludedFromRecents_visibleTaskNotFirstTask_internal(); + } + + private void testVisibleTasks_excludedFromRecents_visibleTaskNotFirstTask_internal() { + mRecentTasks.setParameters(-1 /* min */, 4 /* max */, -1 /* ms */); + + Task invisibleExcludedTask = createTaskBuilder(".ExcludedTask1") + .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + .setCreateActivity(true) + .build(); + ActivityRecord activityRecord = invisibleExcludedTask.getTopMostActivity(); + activityRecord.setVisibleRequested(false); + activityRecord.setVisible(false); + + Task visibleExcludedTask = createTaskBuilder(".ExcludedTask2") + .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + .setCreateActivity(true) + .build(); + Task detachedExcludedTask = createTaskBuilder(".DetachedExcludedTask") + .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + .build(); + + // Move home to front so other task can satisfy the condition in RecentTasks#isTrimmable. + mRootWindowContainer.getDefaultTaskDisplayArea().getRootHomeTask().moveToFront("test"); + // Avoid Task#autoRemoveFromRecents when removing from parent. + detachedExcludedTask.setHasBeenVisible(true); + detachedExcludedTask.removeImmediately(); + assertFalse(detachedExcludedTask.isAttached()); + + mRecentTasks.add(detachedExcludedTask); + mRecentTasks.add(visibleExcludedTask); + mRecentTasks.add(mTasks.get(0)); + mRecentTasks.add(mTasks.get(1)); + mRecentTasks.add(mTasks.get(2)); + mRecentTasks.add(invisibleExcludedTask); + + // Excluded tasks should be trimmed, except those with a visible activity. + triggerTrimAndAssertTrimmed(invisibleExcludedTask, detachedExcludedTask); + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL) public void testVisibleTasks_excludedFromRecents_firstTaskNotVisible() { + testVisibleTasks_excludedFromRecents_firstTaskNotVisible_internal(); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL) + public void testVisibleTasks_excludedFromRecents_firstTaskNotVisible_withRefactorFlag() { + testVisibleTasks_excludedFromRecents_firstTaskNotVisible_internal(); + } + + private void testVisibleTasks_excludedFromRecents_firstTaskNotVisible_internal() { // Create some set of tasks, some of which are visible and some are not Task homeTask = createTaskBuilder("com.android.pkg1", ".HomeTask") .setParentTask(mTaskContainer.getRootHomeTask()) @@ -738,11 +826,12 @@ public class RecentTasksTest extends WindowTestsBase { mRecentTasks.add(homeTask); Task excludedTask1 = createTaskBuilder(".ExcludedTask1") .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + .setCreateActivity(true) .build(); excludedTask1.mUserSetupComplete = true; mRecentTasks.add(excludedTask1); - // Expect that the first visible excluded-from-recents task is visible + // Expect that the visible excluded-from-recents task is visible assertGetRecentTasksOrder(0 /* flags */, excludedTask1); } @@ -1439,9 +1528,9 @@ public class RecentTasksTest extends WindowTestsBase { */ private void assertGetRecentTasksOrder(int getRecentTaskFlags, Task... expectedTasks) { List<RecentTaskInfo> infos = getRecentTasks(getRecentTaskFlags); - assertTrue(expectedTasks.length == infos.size()); - for (int i = 0; i < infos.size(); i++) { - assertTrue(expectedTasks[i].mTaskId == infos.get(i).taskId); + assertEquals(expectedTasks.length, infos.size()); + for (int i = 0; i < infos.size(); i++) { + assertEquals(expectedTasks[i].mTaskId, infos.get(i).taskId); } } 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 7ff2e50926a5..4b03483d43b9 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.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 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.ActivityManager; 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 androidx.test.filters.MediumTest; 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 @@ import java.io.Reader; @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 @@ public class TaskTests extends WindowTestsBase { } @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/telephony/common/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java index a6781478a765..0f4809c2918d 100644 --- a/telephony/common/android/telephony/LocationAccessPolicy.java +++ b/telephony/common/android/telephony/LocationAccessPolicy.java @@ -33,6 +33,7 @@ import android.util.Log; import android.widget.Toast; import com.android.internal.telephony.TelephonyPermissions; +import com.android.internal.telephony.flags.Flags; import com.android.internal.telephony.util.TelephonyUtils; /** @@ -283,6 +284,8 @@ public final class LocationAccessPolicy { int minSdkVersion = Manifest.permission.ACCESS_FINE_LOCATION.equals(permissionToCheck) ? query.minSdkVersionForFine : query.minSdkVersionForCoarse; + UserHandle callingUserHandle = UserHandle.getUserHandleForUid(query.callingUid); + // If the app fails for some reason, see if it should be allowed to proceed. if (minSdkVersion > MAX_SDK_FOR_ANY_ENFORCEMENT) { String errorMsg = "Allowing " + query.callingPackage + " " + locationTypeForLog @@ -291,7 +294,8 @@ public final class LocationAccessPolicy { + query.method; logError(context, query, errorMsg); return null; - } else if (!isAppAtLeastSdkVersion(context, query.callingPackage, minSdkVersion)) { + } else if (!isAppAtLeastSdkVersion(context, callingUserHandle, query.callingPackage, + minSdkVersion)) { String errorMsg = "Allowing " + query.callingPackage + " " + locationTypeForLog + " because it doesn't target API " + minSdkVersion + " yet." + " Please fix this app. Called from " + query.method; @@ -420,11 +424,19 @@ public final class LocationAccessPolicy { } } - private static boolean isAppAtLeastSdkVersion(Context context, String pkgName, int sdkVersion) { + private static boolean isAppAtLeastSdkVersion(Context context, + @NonNull UserHandle callingUserHandle, String pkgName, int sdkVersion) { try { - if (context.getPackageManager().getApplicationInfo(pkgName, 0).targetSdkVersion - >= sdkVersion) { - return true; + if (Flags.hsumPackageManager()) { + if (context.getPackageManager().getApplicationInfoAsUser( + pkgName, 0, callingUserHandle).targetSdkVersion >= sdkVersion) { + return true; + } + } else { + if (context.getPackageManager().getApplicationInfo(pkgName, 0).targetSdkVersion + >= sdkVersion) { + return true; + } } } catch (PackageManager.NameNotFoundException e) { // In case of exception, assume known app (more strict checking) diff --git a/telephony/java/android/telephony/BarringInfo.java b/telephony/java/android/telephony/BarringInfo.java index e20e4d200251..e42b41f90f4a 100644 --- a/telephony/java/android/telephony/BarringInfo.java +++ b/telephony/java/android/telephony/BarringInfo.java @@ -159,7 +159,7 @@ public final class BarringInfo implements Parcelable { /** * @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 2ef057350033..47f6764dba98 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -9763,7 +9763,7 @@ public class CarrierConfigManager { * users to switch to using satellite emergency messaging.</li> * </ul> * <p> - * The default value is 300 seconds. + * The default value is 180 seconds. */ @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public static final String KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT = @@ -11257,7 +11257,7 @@ public class CarrierConfigManager { KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE, PersistableBundle.EMPTY); sDefaults.putBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, false); - sDefaults.putInt(KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT, 300); + sDefaults.putInt(KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT, 180); sDefaults.putIntArray(KEY_NTN_LTE_RSRP_THRESHOLDS_INT_ARRAY, // Boundaries: [-140 dBm, -44 dBm] new int[]{ diff --git a/tests/FlickerTests/ActivityEmbedding/OWNERS b/tests/FlickerTests/ActivityEmbedding/OWNERS new file mode 100644 index 000000000000..981b3168cdbb --- /dev/null +++ b/tests/FlickerTests/ActivityEmbedding/OWNERS @@ -0,0 +1 @@ +# Bug component: 1168918 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 b3a998ebca0d..b5258dfc9c3c 100644 --- a/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java +++ b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java @@ -57,6 +57,8 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.function.Consumer; + /** * Build/Install/Run: * atest TouchpadDebugViewTest @@ -99,10 +101,12 @@ public class TouchpadDebugViewTest { when(mInputManager.getInputDevice(TOUCHPAD_DEVICE_ID)).thenReturn(inputDevice); + Consumer<Integer> touchpadSwitchHandler = id -> {}; + mTouchpadDebugView = new TouchpadDebugView(mTestableContext, TOUCHPAD_DEVICE_ID, new TouchpadHardwareProperties.Builder(0f, 0f, 500f, 500f, 45f, 47f, -4f, 5f, (short) 10, true, - true).build()); + true).build(), touchpadSwitchHandler); mTouchpadDebugView.measure( View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), @@ -321,26 +325,30 @@ public class TouchpadDebugViewTest { 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.parseColor("#769763")); 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.parseColor("#5455A9")); 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.parseColor("#769763")); // 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.parseColor("#769763")); } @Test diff --git a/tests/broadcasts/OWNERS b/tests/broadcasts/OWNERS new file mode 100644 index 000000000000..d2e1f815e8dc --- /dev/null +++ b/tests/broadcasts/OWNERS @@ -0,0 +1,2 @@ +# Bug component: 316181 +include platform/frameworks/base:/BROADCASTS_OWNERS diff --git a/tests/broadcasts/unit/Android.bp b/tests/broadcasts/unit/Android.bp new file mode 100644 index 000000000000..47166a713580 --- /dev/null +++ b/tests/broadcasts/unit/Android.bp @@ -0,0 +1,45 @@ +// +// 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 { + // 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"], + default_team: "trendy_team_framework_backstage_power", +} + +android_test { + name: "BroadcastUnitTests", + srcs: ["src/**/*.java"], + defaults: [ + "modules-utils-extended-mockito-rule-defaults", + ], + static_libs: [ + "androidx.test.runner", + "androidx.test.rules", + "androidx.test.ext.junit", + "mockito-target-extended-minus-junit4", + "truth", + "flag-junit", + "android.app.flags-aconfig-java", + ], + certificate: "platform", + platform_apis: true, + test_suites: ["device-tests"], +} diff --git a/tests/broadcasts/unit/AndroidManifest.xml b/tests/broadcasts/unit/AndroidManifest.xml new file mode 100644 index 000000000000..e9c5248e4d98 --- /dev/null +++ b/tests/broadcasts/unit/AndroidManifest.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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.broadcasts.unit" > + + <application android:debuggable="true"> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.broadcasts.unit" + android:label="Broadcasts Unit Tests"/> +</manifest>
\ No newline at end of file diff --git a/tests/broadcasts/unit/AndroidTest.xml b/tests/broadcasts/unit/AndroidTest.xml new file mode 100644 index 000000000000..b91e4783b69e --- /dev/null +++ b/tests/broadcasts/unit/AndroidTest.xml @@ -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. +--> +<configuration description="Runs Broadcasts tests"> + <option name="test-suite-tag" value="apct" /> + <option name="test-tag" value="BroadcastUnitTests" /> + + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="BroadcastUnitTests.apk" /> + </target_preparer> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.broadcasts.unit" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> + <option name="hidden-api-checks" value="false"/> + </test> +</configuration>
\ No newline at end of file diff --git a/tests/broadcasts/unit/TEST_MAPPING b/tests/broadcasts/unit/TEST_MAPPING new file mode 100644 index 000000000000..0e824c54e92e --- /dev/null +++ b/tests/broadcasts/unit/TEST_MAPPING @@ -0,0 +1,15 @@ +{ + "postsubmit": [ + { + "name": "BroadcastUnitTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation": "org.junit.Ignore" + } + ] + } + ] +} diff --git a/tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java b/tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java new file mode 100644 index 000000000000..b7c412dea999 --- /dev/null +++ b/tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java @@ -0,0 +1,258 @@ +/* + * 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.app; + +import static android.content.Intent.ACTION_BATTERY_CHANGED; +import static android.content.Intent.ACTION_DEVICE_STORAGE_LOW; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; + +import android.content.Intent; +import android.content.IntentFilter; +import android.os.BatteryManager; +import android.os.Bundle; +import android.os.SystemProperties; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; +import android.util.ArrayMap; + +import androidx.annotation.GuardedBy; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.modules.utils.testing.ExtendedMockitoRule; + +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +@EnableFlags(Flags.FLAG_USE_STICKY_BCAST_CACHE) +@RunWith(AndroidJUnit4.class) +@SmallTest +public class BroadcastStickyCacheTest { + @ClassRule + public static final SetFlagsRule.ClassRule mClassRule = new SetFlagsRule.ClassRule(); + @Rule + public final SetFlagsRule mSetFlagsRule = mClassRule.createSetFlagsRule(); + + @Rule + public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this) + .mockStatic(SystemProperties.class) + .build(); + + private static final String PROP_KEY_BATTERY_CHANGED = BroadcastStickyCache.getKey( + ACTION_BATTERY_CHANGED); + + private final TestSystemProps mTestSystemProps = new TestSystemProps(); + + @Before + public void setUp() { + doAnswer(invocation -> { + final String name = invocation.getArgument(0); + final long value = Long.parseLong(invocation.getArgument(1)); + mTestSystemProps.add(name, value); + return null; + }).when(() -> SystemProperties.set(anyString(), anyString())); + doAnswer(invocation -> { + final String name = invocation.getArgument(0); + final TestSystemProps.Handle testHandle = mTestSystemProps.query(name); + if (testHandle == null) { + return null; + } + final SystemProperties.Handle handle = Mockito.mock(SystemProperties.Handle.class); + doAnswer(handleInvocation -> testHandle.getLong(-1)).when(handle).getLong(anyLong()); + return handle; + }).when(() -> SystemProperties.find(anyString())); + } + + @After + public void tearDown() { + mTestSystemProps.clear(); + BroadcastStickyCache.clearForTest(); + } + + @Test + public void testUseCache_nullFilter() { + assertThat(BroadcastStickyCache.useCache(null)).isEqualTo(false); + } + + @Test + public void testUseCache_noActions() { + final IntentFilter filter = new IntentFilter(); + assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(false); + } + + @Test + public void testUseCache_multipleActions() { + final IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_DEVICE_STORAGE_LOW); + filter.addAction(ACTION_BATTERY_CHANGED); + assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(false); + } + + @Test + public void testUseCache_valueNotSet() { + final IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED); + assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(false); + } + + @Test + public void testUseCache() { + final IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED); + final Intent intent = new Intent(ACTION_BATTERY_CHANGED) + .putExtra(BatteryManager.EXTRA_LEVEL, 90); + BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED); + BroadcastStickyCache.add(filter, intent); + assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(true); + } + + @Test + public void testUseCache_versionMismatch() { + final IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED); + final Intent intent = new Intent(ACTION_BATTERY_CHANGED) + .putExtra(BatteryManager.EXTRA_LEVEL, 90); + BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED); + BroadcastStickyCache.add(filter, intent); + BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED); + + assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(false); + } + + @Test + public void testAdd() { + final IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED); + Intent intent = new Intent(ACTION_BATTERY_CHANGED) + .putExtra(BatteryManager.EXTRA_LEVEL, 90); + BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED); + BroadcastStickyCache.add(filter, intent); + assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(true); + Intent actualIntent = BroadcastStickyCache.getIntentUnchecked(filter); + assertThat(actualIntent).isNotNull(); + assertEquals(actualIntent, intent); + + intent = new Intent(ACTION_BATTERY_CHANGED) + .putExtra(BatteryManager.EXTRA_LEVEL, 99); + BroadcastStickyCache.add(filter, intent); + actualIntent = BroadcastStickyCache.getIntentUnchecked(filter); + assertThat(actualIntent).isNotNull(); + assertEquals(actualIntent, intent); + } + + @Test + public void testIncrementVersion_propExists() { + SystemProperties.set(PROP_KEY_BATTERY_CHANGED, String.valueOf(100)); + + BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED); + assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(101); + BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED); + assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(102); + } + + @Test + public void testIncrementVersion_propNotExists() { + // Verify that the property doesn't exist + assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(-1); + + BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED); + assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(1); + BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED); + assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(2); + } + + @Test + public void testIncrementVersionIfExists_propExists() { + BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED); + + BroadcastStickyCache.incrementVersionIfExists(ACTION_BATTERY_CHANGED); + assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(2); + BroadcastStickyCache.incrementVersionIfExists(ACTION_BATTERY_CHANGED); + assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(3); + } + + @Test + public void testIncrementVersionIfExists_propNotExists() { + // Verify that the property doesn't exist + assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(-1); + + BroadcastStickyCache.incrementVersionIfExists(ACTION_BATTERY_CHANGED); + assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(-1); + // Verify that property is not added as part of the querying. + BroadcastStickyCache.incrementVersionIfExists(ACTION_BATTERY_CHANGED); + assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(-1); + } + + private void assertEquals(Intent actualIntent, Intent expectedIntent) { + assertThat(actualIntent.getAction()).isEqualTo(expectedIntent.getAction()); + assertEquals(actualIntent.getExtras(), expectedIntent.getExtras()); + } + + private void assertEquals(Bundle actualExtras, Bundle expectedExtras) { + assertWithMessage("Extras expected=%s, actual=%s", expectedExtras, actualExtras) + .that(actualExtras.kindofEquals(expectedExtras)).isTrue(); + } + + private static final class TestSystemProps { + @GuardedBy("mSysProps") + private final ArrayMap<String, Long> mSysProps = new ArrayMap<>(); + + public void add(String name, long value) { + synchronized (mSysProps) { + mSysProps.put(name, value); + } + } + + public long get(String name, long defaultValue) { + synchronized (mSysProps) { + final int idx = mSysProps.indexOfKey(name); + return idx >= 0 ? mSysProps.valueAt(idx) : defaultValue; + } + } + + public Handle query(String name) { + synchronized (mSysProps) { + return mSysProps.containsKey(name) ? new Handle(name) : null; + } + } + + public void clear() { + synchronized (mSysProps) { + mSysProps.clear(); + } + } + + public class Handle { + private final String mName; + + Handle(String name) { + mName = name; + } + + public long getLong(long defaultValue) { + return get(mName, defaultValue); + } + } + } +} diff --git a/tools/systemfeatures/Android.bp b/tools/systemfeatures/Android.bp index a9e63289ee93..590f7190881a 100644 --- a/tools/systemfeatures/Android.bp +++ b/tools/systemfeatures/Android.bp @@ -30,8 +30,8 @@ genrule { name: "systemfeatures-gen-tests-srcs", cmd: "$(location systemfeatures-gen-tool) com.android.systemfeatures.RwNoFeatures --readonly=false > $(location RwNoFeatures.java) && " + "$(location systemfeatures-gen-tool) com.android.systemfeatures.RoNoFeatures --readonly=true --feature-apis=WATCH > $(location RoNoFeatures.java) && " + - "$(location systemfeatures-gen-tool) com.android.systemfeatures.RwFeatures --readonly=false --feature=WATCH:1 --feature=WIFI:0 --feature=VULKAN:-1 --feature=AUTO: > $(location RwFeatures.java) && " + - "$(location systemfeatures-gen-tool) com.android.systemfeatures.RoFeatures --readonly=true --feature=WATCH:1 --feature=WIFI:0 --feature=VULKAN:-1 --feature=AUTO: --feature-apis=WATCH,PC > $(location RoFeatures.java)", + "$(location systemfeatures-gen-tool) com.android.systemfeatures.RwFeatures --readonly=false --feature=WATCH:1 --feature=WIFI:0 --feature=VULKAN:UNAVAILABLE --feature=AUTO: > $(location RwFeatures.java) && " + + "$(location systemfeatures-gen-tool) com.android.systemfeatures.RoFeatures --readonly=true --feature=WATCH:1 --feature=WIFI:0 --feature=VULKAN:UNAVAILABLE --feature=AUTO: --feature-apis=WATCH,PC > $(location RoFeatures.java)", out: [ "RwNoFeatures.java", "RoNoFeatures.java", diff --git a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt index 5df453deaf2a..cba521e639cb 100644 --- a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt +++ b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt @@ -20,7 +20,10 @@ import com.google.common.base.CaseFormat import com.squareup.javapoet.ClassName import com.squareup.javapoet.JavaFile import com.squareup.javapoet.MethodSpec +import com.squareup.javapoet.ParameterizedTypeName import com.squareup.javapoet.TypeSpec +import java.util.HashMap +import java.util.Map import javax.lang.model.element.Modifier /* @@ -31,7 +34,7 @@ import javax.lang.model.element.Modifier * * <pre> * <cmd> com.foo.RoSystemFeatures --readonly=true \ - * --feature=WATCH:0 --feature=AUTOMOTIVE: --feature=VULKAN:9348 + * --feature=WATCH:0 --feature=AUTOMOTIVE: --feature=VULKAN:9348 --feature=PC:UNAVAILABLE * --feature-apis=WATCH,PC,LEANBACK * </pre> * @@ -43,12 +46,13 @@ import javax.lang.model.element.Modifier * @AssumeTrueForR8 * public static boolean hasFeatureWatch(Context context); * @AssumeFalseForR8 - * public static boolean hasFeatureAutomotive(Context context); + * public static boolean hasFeaturePc(Context context); * @AssumeTrueForR8 * public static boolean hasFeatureVulkan(Context context); - * public static boolean hasFeaturePc(Context context); + * public static boolean hasFeatureAutomotive(Context context); * public static boolean hasFeatureLeanback(Context context); * public static Boolean maybeHasFeature(String feature, int version); + * public static ArrayMap<String, FeatureInfo> getCompileTimeAvailableFeatures(); * } * </pre> */ @@ -58,6 +62,7 @@ object SystemFeaturesGenerator { private const val READONLY_ARG = "--readonly=" private val PACKAGEMANAGER_CLASS = ClassName.get("android.content.pm", "PackageManager") private val CONTEXT_CLASS = ClassName.get("android.content", "Context") + private val FEATUREINFO_CLASS = ClassName.get("android.content.pm", "FeatureInfo") private val ASSUME_TRUE_CLASS = ClassName.get("com.android.aconfig.annotations", "AssumeTrueForR8") private val ASSUME_FALSE_CLASS = @@ -67,7 +72,10 @@ object SystemFeaturesGenerator { println("Usage: SystemFeaturesGenerator <outputClassName> [options]") println(" Options:") println(" --readonly=true|false Whether to encode features as build-time constants") - println(" --feature=\$NAME:\$VER A feature+version pair (blank version == disabled)") + println(" --feature=\$NAME:\$VER A feature+version pair, where \$VER can be:") + println(" * blank/empty == undefined (variable API)") + println(" * valid int == enabled (constant API)") + println(" * UNAVAILABLE == disabled (constant API)") println(" This will always generate associated query APIs,") println(" adding to or replacing those from `--feature-apis=`.") println(" --feature-apis=\$NAME_1,\$NAME_2") @@ -89,7 +97,7 @@ object SystemFeaturesGenerator { var readonly = false var outputClassName: ClassName? = null - val featureArgs = mutableListOf<FeatureArg>() + val featureArgs = mutableListOf<FeatureInfo>() // We could just as easily hardcode this list, as the static API surface should change // somewhat infrequently, but this decouples the codegen from the framework completely. val featureApiArgs = mutableSetOf<String>() @@ -122,7 +130,7 @@ object SystemFeaturesGenerator { featureArgs.associateByTo( features, { it.name }, - { FeatureInfo(it.name, it.version, readonly) }, + { FeatureInfo(it.name, it.version, it.readonly && readonly) }, ) outputClassName @@ -139,6 +147,7 @@ object SystemFeaturesGenerator { addFeatureMethodsToClass(classBuilder, features.values) addMaybeFeatureMethodToClass(classBuilder, features.values) + addGetFeaturesMethodToClass(classBuilder, features.values) // TODO(b/203143243): Add validation of build vs runtime values to ensure consistency. JavaFile.builder(outputClassName.packageName(), classBuilder.build()) @@ -154,13 +163,17 @@ object SystemFeaturesGenerator { * Parses a feature argument of the form "--feature=$NAME:$VER", where "$VER" is optional. * * "--feature=WATCH:0" -> Feature enabled w/ version 0 (default version when enabled) * * "--feature=WATCH:7" -> Feature enabled w/ version 7 - * * "--feature=WATCH:" -> Feature disabled + * * "--feature=WATCH:" -> Feature status undefined, runtime API generated + * * "--feature=WATCH:UNAVAILABLE" -> Feature disabled */ - private fun parseFeatureArg(arg: String): FeatureArg { + private fun parseFeatureArg(arg: String): FeatureInfo { val featureArgs = arg.substring(FEATURE_ARG.length).split(":") val name = parseFeatureName(featureArgs[0]) - val version = featureArgs.getOrNull(1)?.toIntOrNull() - return FeatureArg(name, version) + return when (featureArgs.getOrNull(1)) { + null, "" -> FeatureInfo(name, null, readonly = false) + "UNAVAILABLE" -> FeatureInfo(name, null, readonly = true) + else -> FeatureInfo(name, featureArgs[1].toIntOrNull(), readonly = true) + } } private fun parseFeatureName(name: String): String = @@ -218,7 +231,7 @@ object SystemFeaturesGenerator { /* * Adds a generic query method to the class with the form: {@code public static boolean * maybeHasFeature(String featureName, int version)}, returning null if the feature version is - * undefined or not readonly. + * undefined or not (compile-time) readonly. * * This method is useful for internal usage within the framework, e.g., from the implementation * of {@link android.content.pm.PackageManager#hasSystemFeature(Context)}, when we may only @@ -267,7 +280,41 @@ object SystemFeaturesGenerator { builder.addMethod(methodBuilder.build()) } - private data class FeatureArg(val name: String, val version: Int?) + /* + * Adds a method to get all compile-time enabled features. + * + * This method is useful for internal usage within the framework to augment + * any system features that are parsed from the various partitions. + */ + private fun addGetFeaturesMethodToClass( + builder: TypeSpec.Builder, + features: Collection<FeatureInfo>, + ) { + val methodBuilder = + MethodSpec.methodBuilder("getCompileTimeAvailableFeatures") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .addAnnotation(ClassName.get("android.annotation", "NonNull")) + .addJavadoc("Gets features marked as available at compile-time, keyed by name." + + "\n\n@hide") + .returns(ParameterizedTypeName.get( + ClassName.get(Map::class.java), + ClassName.get(String::class.java), + FEATUREINFO_CLASS)) + + val availableFeatures = features.filter { it.readonly && it.version != null } + methodBuilder.addStatement("Map<String, FeatureInfo> features = new \$T<>(\$L)", + HashMap::class.java, availableFeatures.size) + if (!availableFeatures.isEmpty()) { + methodBuilder.addStatement("FeatureInfo fi = new FeatureInfo()") + } + for (feature in availableFeatures) { + methodBuilder.addStatement("fi.name = \$T.\$N", PACKAGEMANAGER_CLASS, feature.name) + methodBuilder.addStatement("fi.version = \$L", feature.version) + methodBuilder.addStatement("features.put(fi.name, new FeatureInfo(fi))") + } + methodBuilder.addStatement("return features") + builder.addMethod(methodBuilder.build()) + } private data class FeatureInfo(val name: String, val version: Int?, val readonly: Boolean) } diff --git a/tools/systemfeatures/tests/golden/RoFeatures.java.gen b/tools/systemfeatures/tests/golden/RoFeatures.java.gen index 724639b52d23..edbfc4237547 100644 --- a/tools/systemfeatures/tests/golden/RoFeatures.java.gen +++ b/tools/systemfeatures/tests/golden/RoFeatures.java.gen @@ -3,16 +3,20 @@ // --readonly=true \ // --feature=WATCH:1 \ // --feature=WIFI:0 \ -// --feature=VULKAN:-1 \ +// --feature=VULKAN:UNAVAILABLE \ // --feature=AUTO: \ // --feature-apis=WATCH,PC package com.android.systemfeatures; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.pm.FeatureInfo; import android.content.pm.PackageManager; import com.android.aconfig.annotations.AssumeFalseForR8; import com.android.aconfig.annotations.AssumeTrueForR8; +import java.util.HashMap; +import java.util.Map; /** * @hide @@ -62,9 +66,8 @@ public final class RoFeatures { * * @hide */ - @AssumeFalseForR8 public static boolean hasFeatureAuto(Context context) { - return false; + return hasFeatureFallback(context, PackageManager.FEATURE_AUTO); } private static boolean hasFeatureFallback(Context context, String featureName) { @@ -79,10 +82,27 @@ public final class RoFeatures { switch (featureName) { case PackageManager.FEATURE_WATCH: return 1 >= version; case PackageManager.FEATURE_WIFI: return 0 >= version; - case PackageManager.FEATURE_VULKAN: return -1 >= version; - case PackageManager.FEATURE_AUTO: return false; + case PackageManager.FEATURE_VULKAN: return false; default: break; } return null; } + + /** + * Gets features marked as available at compile-time, keyed by name. + * + * @hide + */ + @NonNull + public static Map<String, FeatureInfo> getCompileTimeAvailableFeatures() { + Map<String, FeatureInfo> features = new HashMap<>(2); + FeatureInfo fi = new FeatureInfo(); + fi.name = PackageManager.FEATURE_WATCH; + fi.version = 1; + features.put(fi.name, new FeatureInfo(fi)); + fi.name = PackageManager.FEATURE_WIFI; + fi.version = 0; + features.put(fi.name, new FeatureInfo(fi)); + return features; + } } diff --git a/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen b/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen index 59c5b4e8fecb..bf7a00679fa6 100644 --- a/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen +++ b/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen @@ -4,9 +4,13 @@ // --feature-apis=WATCH package com.android.systemfeatures; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.pm.FeatureInfo; import android.content.pm.PackageManager; +import java.util.HashMap; +import java.util.Map; /** * @hide @@ -32,4 +36,15 @@ public final class RoNoFeatures { public static Boolean maybeHasFeature(String featureName, int version) { return null; } + + /** + * Gets features marked as available at compile-time, keyed by name. + * + * @hide + */ + @NonNull + public static Map<String, FeatureInfo> getCompileTimeAvailableFeatures() { + Map<String, FeatureInfo> features = new HashMap<>(0); + return features; + } } diff --git a/tools/systemfeatures/tests/golden/RwFeatures.java.gen b/tools/systemfeatures/tests/golden/RwFeatures.java.gen index 6f897591e48f..b20b228f9814 100644 --- a/tools/systemfeatures/tests/golden/RwFeatures.java.gen +++ b/tools/systemfeatures/tests/golden/RwFeatures.java.gen @@ -3,13 +3,17 @@ // --readonly=false \ // --feature=WATCH:1 \ // --feature=WIFI:0 \ -// --feature=VULKAN:-1 \ +// --feature=VULKAN:UNAVAILABLE \ // --feature=AUTO: package com.android.systemfeatures; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.pm.FeatureInfo; import android.content.pm.PackageManager; +import java.util.HashMap; +import java.util.Map; /** * @hide @@ -62,4 +66,15 @@ public final class RwFeatures { public static Boolean maybeHasFeature(String featureName, int version) { return null; } + + /** + * Gets features marked as available at compile-time, keyed by name. + * + * @hide + */ + @NonNull + public static Map<String, FeatureInfo> getCompileTimeAvailableFeatures() { + Map<String, FeatureInfo> features = new HashMap<>(0); + return features; + } } diff --git a/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen b/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen index 2111d564f28d..d91f5b62d8d4 100644 --- a/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen +++ b/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen @@ -3,8 +3,12 @@ // --readonly=false package com.android.systemfeatures; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.pm.FeatureInfo; +import java.util.HashMap; +import java.util.Map; /** * @hide @@ -21,4 +25,15 @@ public final class RwNoFeatures { public static Boolean maybeHasFeature(String featureName, int version) { return null; } + + /** + * Gets features marked as available at compile-time, keyed by name. + * + * @hide + */ + @NonNull + public static Map<String, FeatureInfo> getCompileTimeAvailableFeatures() { + Map<String, FeatureInfo> features = new HashMap<>(0); + return features; + } } diff --git a/tools/systemfeatures/tests/src/FeatureInfo.java b/tools/systemfeatures/tests/src/FeatureInfo.java new file mode 100644 index 000000000000..9d57edc64ca5 --- /dev/null +++ b/tools/systemfeatures/tests/src/FeatureInfo.java @@ -0,0 +1,30 @@ +/* + * 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.content.pm; + +/** Stub for testing */ +public final class FeatureInfo { + public String name; + public int version; + + public FeatureInfo() {} + + public FeatureInfo(FeatureInfo orig) { + name = orig.name; + version = orig.version; + } +} diff --git a/tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java b/tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java index 6dfd244a807b..39f8fc44fe23 100644 --- a/tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java +++ b/tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java @@ -25,6 +25,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; +import android.content.pm.FeatureInfo; import android.content.pm.PackageManager; import org.junit.Before; @@ -36,6 +37,8 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import java.util.Map; + @RunWith(JUnit4.class) public class SystemFeaturesGeneratorTest { @@ -57,6 +60,7 @@ public class SystemFeaturesGeneratorTest { assertThat(RwNoFeatures.maybeHasFeature(PackageManager.FEATURE_VULKAN, 0)).isNull(); assertThat(RwNoFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, 0)).isNull(); assertThat(RwNoFeatures.maybeHasFeature("com.arbitrary.feature", 0)).isNull(); + assertThat(RwNoFeatures.getCompileTimeAvailableFeatures()).isEmpty(); } @Test @@ -68,6 +72,7 @@ public class SystemFeaturesGeneratorTest { assertThat(RoNoFeatures.maybeHasFeature(PackageManager.FEATURE_VULKAN, 0)).isNull(); assertThat(RoNoFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, 0)).isNull(); assertThat(RoNoFeatures.maybeHasFeature("com.arbitrary.feature", 0)).isNull(); + assertThat(RoNoFeatures.getCompileTimeAvailableFeatures()).isEmpty(); // Also ensure we fall back to the PackageManager for feature APIs without an accompanying // versioned feature definition. @@ -101,6 +106,7 @@ public class SystemFeaturesGeneratorTest { assertThat(RwFeatures.maybeHasFeature(PackageManager.FEATURE_VULKAN, 0)).isNull(); assertThat(RwFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, 0)).isNull(); assertThat(RwFeatures.maybeHasFeature("com.arbitrary.feature", 0)).isNull(); + assertThat(RwFeatures.getCompileTimeAvailableFeatures()).isEmpty(); } @Test @@ -110,10 +116,13 @@ public class SystemFeaturesGeneratorTest { assertThat(RoFeatures.hasFeatureWatch(mContext)).isTrue(); assertThat(RoFeatures.hasFeatureWifi(mContext)).isTrue(); assertThat(RoFeatures.hasFeatureVulkan(mContext)).isFalse(); - assertThat(RoFeatures.hasFeatureAuto(mContext)).isFalse(); verify(mPackageManager, never()).hasSystemFeature(anyString(), anyInt()); - // For defined feature types, conditional queries should reflect the build-time versions. + // For defined feature types, conditional queries should reflect either: + // * Enabled if the feature version is specified + // * Disabled if UNAVAILABLE is specified + // * Unknown if no version value is provided + // VERSION=1 assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_WATCH, -1)).isTrue(); assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_WATCH, 0)).isTrue(); @@ -124,15 +133,19 @@ public class SystemFeaturesGeneratorTest { assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_WIFI, 0)).isTrue(); assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_WIFI, 100)).isFalse(); - // VERSION=-1 - assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_VULKAN, -1)).isTrue(); + // VERSION=UNAVAILABLE + assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_VULKAN, -1)).isFalse(); assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_VULKAN, 0)).isFalse(); assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_VULKAN, 100)).isFalse(); - // DISABLED - assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, -1)).isFalse(); - assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, 0)).isFalse(); - assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, 100)).isFalse(); + // VERSION= + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTO, 0)).thenReturn(false); + assertThat(RoFeatures.hasFeatureAuto(mContext)).isFalse(); + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTO, 0)).thenReturn(true); + assertThat(RoFeatures.hasFeatureAuto(mContext)).isTrue(); + assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, -1)).isNull(); + assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, 0)).isNull(); + assertThat(RoFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, 100)).isNull(); // For feature APIs without an associated feature definition, conditional queries should // report null, and explicit queries should report runtime-defined versions. @@ -148,5 +161,12 @@ public class SystemFeaturesGeneratorTest { assertThat(RoFeatures.maybeHasFeature("com.arbitrary.feature", -1)).isNull(); assertThat(RoFeatures.maybeHasFeature("com.arbitrary.feature", 0)).isNull(); assertThat(RoFeatures.maybeHasFeature("com.arbitrary.feature", 100)).isNull(); + assertThat(RoFeatures.maybeHasFeature("", 0)).isNull(); + + Map<String, FeatureInfo> compiledFeatures = RoFeatures.getCompileTimeAvailableFeatures(); + assertThat(compiledFeatures.keySet()) + .containsExactly(PackageManager.FEATURE_WATCH, PackageManager.FEATURE_WIFI); + assertThat(compiledFeatures.get(PackageManager.FEATURE_WATCH).version).isEqualTo(1); + assertThat(compiledFeatures.get(PackageManager.FEATURE_WIFI).version).isEqualTo(0); } } |