diff options
676 files changed, 11698 insertions, 3307 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index c30164c065af..003b7f87fa23 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -42,6 +42,7 @@ aconfig_srcjars = [      ":android.credentials.flags-aconfig-java{.generated_srcjars}",      ":android.view.contentprotection.flags-aconfig-java{.generated_srcjars}",      ":android.service.voice.flags-aconfig-java{.generated_srcjars}", +    ":android.service.autofill.flags-aconfig-java{.generated_srcjars}",  ]  filegroup { @@ -416,3 +417,19 @@ java_aconfig_library {      aconfig_declarations: "android.service.voice.flags-aconfig",      defaults: ["framework-minus-apex-aconfig-java-defaults"],  } + +// Autofill +aconfig_declarations { +    name: "android.service.autofill.flags-aconfig", +    package: "android.service.autofill", +    srcs: [ +        "services/autofill/bugfixes.aconfig", +        "services/autofill/features.aconfig" +    ], +} + +java_aconfig_library { +    name: "android.service.autofill.flags-aconfig-java", +    aconfig_declarations: "android.service.autofill.flags-aconfig", +    defaults: ["framework-minus-apex-aconfig-java-defaults"], +} diff --git a/apex/jobscheduler/service/Android.bp b/apex/jobscheduler/service/Android.bp index a4a0b4b29200..887f7fe3a0e2 100644 --- a/apex/jobscheduler/service/Android.bp +++ b/apex/jobscheduler/service/Android.bp @@ -13,6 +13,10 @@ java_library {      name: "service-jobscheduler",      installable: true, +    defaults: [ +        "service-jobscheduler-aconfig-libraries", +    ], +      srcs: [          "java/**/*.java",          ":framework-jobscheduler-shared-srcs", diff --git a/apex/jobscheduler/service/aconfig/Android.bp b/apex/jobscheduler/service/aconfig/Android.bp new file mode 100644 index 000000000000..24ecd3d73814 --- /dev/null +++ b/apex/jobscheduler/service/aconfig/Android.bp @@ -0,0 +1,29 @@ +// JobScheduler +aconfig_declarations { +    name: "service-job.flags-aconfig", +    package: "com.android.server.job", +    srcs: [ +        "job.aconfig", +    ], +} + +java_aconfig_library { +    name: "service-jobscheduler-job.flags-aconfig-java", +    aconfig_declarations: "service-job.flags-aconfig", +    defaults: ["framework-minus-apex-aconfig-java-defaults"], +    visibility: ["//frameworks/base:__subpackages__"], +} + +service_jobscheduler_aconfig_srcjars = [ +    ":service-jobscheduler-job.flags-aconfig-java{.generated_srcjars}", +] + +// Aconfig declarations and libraries for the core framework +java_defaults { +    name: "service-jobscheduler-aconfig-libraries", +    // Add java_aconfig_libraries to here to add them to the core framework +    srcs: service_jobscheduler_aconfig_srcjars, +    // Add aconfig-annotations-lib as a dependency for the optimization +    libs: ["aconfig-annotations-lib"], +    visibility: ["//frameworks/base:__subpackages__"], +} diff --git a/apex/jobscheduler/service/aconfig/job.aconfig b/apex/jobscheduler/service/aconfig/job.aconfig new file mode 100644 index 000000000000..4e3cb7d83451 --- /dev/null +++ b/apex/jobscheduler/service/aconfig/job.aconfig @@ -0,0 +1,8 @@ +package: "com.android.server.job" + +flag { +    name: "relax_prefetch_connectivity_constraint_only_on_charger" +    namespace: "backstagepower" +    description: "Only relax a prefetch job's connectivity constraint when the device is charging" +    bug: "299329948" +}
\ No newline at end of file diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index f252a0ba48cf..158d914575c6 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -1030,6 +1030,12 @@ public class DeviceIdleController extends SystemService                  "light_idle_to_initial_flex";          private static final String KEY_LIGHT_IDLE_TIMEOUT_MAX_FLEX = "light_max_idle_to_flex";          private static final String KEY_LIGHT_IDLE_FACTOR = "light_idle_factor"; +        private static final String KEY_LIGHT_IDLE_INCREASE_LINEARLY = +                "light_idle_increase_linearly"; +        private static final String KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS = +                "light_idle_linear_increase_factor_ms"; +        private static final String KEY_LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS = +                "light_idle_flex_linear_increase_factor_ms";          private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT = "light_max_idle_to";          private static final String KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET =                  "light_idle_maintenance_min_budget"; @@ -1079,6 +1085,10 @@ public class DeviceIdleController extends SystemService          private long mDefaultLightIdleTimeoutMaxFlex =                  !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;          private float mDefaultLightIdleFactor = 2f; +        private boolean mDefaultLightIdleIncreaseLinearly; +        private long mDefaultLightIdleLinearIncreaseFactorMs = mDefaultLightIdleTimeout; +        private long mDefaultLightIdleFlexLinearIncreaseFactorMs = +                mDefaultLightIdleTimeoutInitialFlex;          private long mDefaultLightMaxIdleTimeout =                  !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;          private long mDefaultLightIdleMaintenanceMinBudget = @@ -1174,6 +1184,37 @@ public class DeviceIdleController extends SystemService          public float LIGHT_IDLE_FACTOR = mDefaultLightIdleFactor;          /** +         * Whether to increase the light idle mode time linearly or exponentially. +         * If true, will increase linearly +         * (i.e. {@link #LIGHT_IDLE_TIMEOUT} + x * {@link #LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS}). +         * If false, will increase by exponentially +         * (i.e. {@link #LIGHT_IDLE_TIMEOUT} * ({@link #LIGHT_IDLE_FACTOR} ^ x)). +         * This will also impact how the light idle flex value +         * ({@link #LIGHT_IDLE_TIMEOUT_INITIAL_FLEX}) is increased (using +         * {@link #LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS} for the linear increase).. +         * +         * @see #KEY_LIGHT_IDLE_INCREASE_LINEARLY +         */ +        public boolean LIGHT_IDLE_INCREASE_LINEARLY = mDefaultLightIdleIncreaseLinearly; + +        /** +         * Amount of time to increase the light idle time by, if increasing it linearly. +         * +         * @see #KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS +         * @see #LIGHT_IDLE_INCREASE_LINEARLY +         */ +        public long LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS = mDefaultLightIdleLinearIncreaseFactorMs; + +        /** +         * Amount of time to increase the light idle flex time by, if increasing it linearly. +         * +         * @see #KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS +         * @see #LIGHT_IDLE_INCREASE_LINEARLY +         */ +        public long LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS = +                mDefaultLightIdleFlexLinearIncreaseFactorMs; + +        /**           * This is the maximum time we will stay in light idle mode.           *           * @see #KEY_LIGHT_MAX_IDLE_TIMEOUT @@ -1409,6 +1450,16 @@ public class DeviceIdleController extends SystemService                      mDefaultLightIdleTimeoutMaxFlex);              mDefaultLightIdleFactor = res.getFloat(                      com.android.internal.R.integer.device_idle_light_idle_factor); +            mDefaultLightIdleIncreaseLinearly = res.getBoolean( +                    com.android.internal.R.bool.device_idle_light_idle_increase_linearly); +            mDefaultLightIdleLinearIncreaseFactorMs = getTimeout(res.getInteger( +                    com.android.internal.R.integer +                            .device_idle_light_idle_linear_increase_factor_ms), +                    mDefaultLightIdleLinearIncreaseFactorMs); +            mDefaultLightIdleFlexLinearIncreaseFactorMs = getTimeout(res.getInteger( +                    com.android.internal.R.integer +                            .device_idle_light_idle_flex_linear_increase_factor_ms), +                    mDefaultLightIdleFlexLinearIncreaseFactorMs);              mDefaultLightMaxIdleTimeout = getTimeout(                      res.getInteger(com.android.internal.R.integer.device_idle_light_max_idle_to_ms),                      mDefaultLightMaxIdleTimeout); @@ -1487,6 +1538,9 @@ public class DeviceIdleController extends SystemService              LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = mDefaultLightIdleTimeoutInitialFlex;              LIGHT_IDLE_TIMEOUT_MAX_FLEX = mDefaultLightIdleTimeoutMaxFlex;              LIGHT_IDLE_FACTOR = mDefaultLightIdleFactor; +            LIGHT_IDLE_INCREASE_LINEARLY = mDefaultLightIdleIncreaseLinearly; +            LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS = mDefaultLightIdleLinearIncreaseFactorMs; +            LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS = mDefaultLightIdleFlexLinearIncreaseFactorMs;              LIGHT_MAX_IDLE_TIMEOUT = mDefaultLightMaxIdleTimeout;              LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = mDefaultLightIdleMaintenanceMinBudget;              LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = mDefaultLightIdleMaintenanceMaxBudget; @@ -1556,6 +1610,21 @@ public class DeviceIdleController extends SystemService                              LIGHT_IDLE_FACTOR = Math.max(1, properties.getFloat(                                      KEY_LIGHT_IDLE_FACTOR, mDefaultLightIdleFactor));                              break; +                        case KEY_LIGHT_IDLE_INCREASE_LINEARLY: +                            LIGHT_IDLE_INCREASE_LINEARLY = properties.getBoolean( +                                    KEY_LIGHT_IDLE_INCREASE_LINEARLY, +                                    mDefaultLightIdleIncreaseLinearly); +                            break; +                        case KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS: +                            LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS = properties.getLong( +                                    KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS, +                                    mDefaultLightIdleLinearIncreaseFactorMs); +                            break; +                        case KEY_LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS: +                            LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS = properties.getLong( +                                    KEY_LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS, +                                    mDefaultLightIdleFlexLinearIncreaseFactorMs); +                            break;                          case KEY_LIGHT_MAX_IDLE_TIMEOUT:                              LIGHT_MAX_IDLE_TIMEOUT = properties.getLong(                                      KEY_LIGHT_MAX_IDLE_TIMEOUT, mDefaultLightMaxIdleTimeout); @@ -1716,6 +1785,20 @@ public class DeviceIdleController extends SystemService              pw.print(LIGHT_IDLE_FACTOR);              pw.println(); +            pw.print("    "); pw.print(KEY_LIGHT_IDLE_INCREASE_LINEARLY); pw.print("="); +            pw.print(LIGHT_IDLE_INCREASE_LINEARLY); +            pw.println(); + +            pw.print("    "); pw.print(KEY_LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS); +            pw.print("="); +            pw.print(LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS); +            pw.println(); + +            pw.print("    "); pw.print(KEY_LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS); +            pw.print("="); +            pw.print(LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS); +            pw.println(); +              pw.print("    "); pw.print(KEY_LIGHT_MAX_IDLE_TIMEOUT); pw.print("=");              TimeUtils.formatDuration(LIGHT_MAX_IDLE_TIMEOUT, pw);              pw.println(); @@ -3694,10 +3777,18 @@ public class DeviceIdleController extends SystemService                  }                  mMaintenanceStartTime = 0;                  scheduleLightAlarmLocked(mNextLightIdleDelay, mNextLightIdleDelayFlex, true); -                mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT, -                        (long) (mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR)); -                mNextLightIdleDelayFlex = Math.min(mConstants.LIGHT_IDLE_TIMEOUT_MAX_FLEX, -                        (long) (mNextLightIdleDelayFlex * mConstants.LIGHT_IDLE_FACTOR)); +                if (!mConstants.LIGHT_IDLE_INCREASE_LINEARLY) { +                    mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT, +                            (long) (mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR)); +                    mNextLightIdleDelayFlex = Math.min(mConstants.LIGHT_IDLE_TIMEOUT_MAX_FLEX, +                            (long) (mNextLightIdleDelayFlex * mConstants.LIGHT_IDLE_FACTOR)); +                } else { +                    mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT, +                            mNextLightIdleDelay + mConstants.LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS); +                    mNextLightIdleDelayFlex = Math.min(mConstants.LIGHT_IDLE_TIMEOUT_MAX_FLEX, +                            mNextLightIdleDelayFlex +                                    + mConstants.LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS); +                }                  moveToLightStateLocked(LIGHT_STATE_IDLE, reason);                  addEvent(EVENT_LIGHT_IDLE, null);                  mGoingIdleWakeLock.acquire(); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java index 6d938debde10..45f15db93a0d 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java @@ -22,6 +22,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_MET  import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;  import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; +import static com.android.server.job.Flags.FLAG_RELAX_PREFETCH_CONNECTIVITY_CONSTRAINT_ONLY_ON_CHARGER; +import static com.android.server.job.Flags.relaxPrefetchConnectivityConstraintOnlyOnCharger;  import android.annotation.NonNull;  import android.annotation.Nullable; @@ -929,6 +931,11 @@ public final class ConnectivityController extends RestrictingController implemen              // Need to at least know the estimated download bytes for a prefetch job.              return false;          } +        if (relaxPrefetchConnectivityConstraintOnlyOnCharger()) { +            if (!mService.isBatteryCharging()) { +                return false; +            } +        }          // See if we match after relaxing any unmetered request          final NetworkCapabilities.Builder builder = @@ -1735,6 +1742,14 @@ public final class ConnectivityController extends RestrictingController implemen              Predicate<JobStatus> predicate) {          final long nowElapsed = sElapsedRealtimeClock.millis(); +        pw.println("Aconfig flags:"); +        pw.increaseIndent(); +        pw.print(FLAG_RELAX_PREFETCH_CONNECTIVITY_CONSTRAINT_ONLY_ON_CHARGER, +                relaxPrefetchConnectivityConstraintOnlyOnCharger()); +        pw.println(); +        pw.decreaseIndent(); +        pw.println(); +          if (mRequestedWhitelistJobs.size() > 0) {              pw.print("Requested standby exceptions:");              for (int i = 0; i < mRequestedWhitelistJobs.size(); i++) { diff --git a/api/Android.bp b/api/Android.bp index 45e70719e6c0..222275f9a4e4 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -82,7 +82,6 @@ combined_apis {          "framework-media",          "framework-mediaprovider",          "framework-ondevicepersonalization", -        "framework-pdf",          "framework-permission",          "framework-permission-s",          "framework-scheduling", diff --git a/api/ApiDocs.bp b/api/ApiDocs.bp index 6461c00b1dcd..8d8fc12ebc4d 100644 --- a/api/ApiDocs.bp +++ b/api/ApiDocs.bp @@ -195,6 +195,8 @@ framework_docs_only_args = " -android -manifest $(location :frameworks-base-core  doc_defaults {      name: "framework-docs-default", +    sdk_version: "none", +    system_modules: "none",      libs: framework_docs_only_libs + [          "stub-annotations",          "unsupportedappusage", diff --git a/api/javadoc-lint-baseline b/api/javadoc-lint-baseline index 201843c4edf7..762d9d1c3da1 100644 --- a/api/javadoc-lint-baseline +++ b/api/javadoc-lint-baseline @@ -50,9 +50,14 @@ android/adservices/ondevicepersonalization/WebViewEventInput.java:21: lint: Unre  android/adservices/ondevicepersonalization/WebViewEventInput.java:30: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onExecute() IsolatedWorker#onExecute()" in android.adservices.ondevicepersonalization.WebViewEventInput [101]  android/adservices/ondevicepersonalization/WebViewEventInput.java:41: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.EventUrlProvider#createEventTrackingUrlWithResponse() EventUrlProvider#createEventTrackingUrlWithResponse()" in android.adservices.ondevicepersonalization.WebViewEventInput [101]  android/adservices/ondevicepersonalization/WebViewEventOutput.java:21: lint: Unresolved link/see tag "android.adservices.ondevicepersonalization.IsolatedWorker#onWebViewEvent() IsolatedWorker#onWebViewEvent()" in android.adservices.ondevicepersonalization.WebViewEventOutput [101] +android/app/ActivityOptions.java:366: lint: Unresolved link/see tag "android.app.ComponentOptions.BackgroundActivityStartMode" in android.app.ActivityOptions [101] +android/app/ActivityOptions.java:370: lint: Unresolved link/see tag "android.app.ComponentOptions.BackgroundActivityStartMode" in android.app.ActivityOptions [101] +android/app/ActivityOptions.java:384: lint: Unresolved link/see tag "android.app.ComponentOptions.BackgroundActivityStartMode" in android.app.ActivityOptions [101]  android/app/ApplicationStartInfo.java:96: lint: Unresolved link/see tag "#START_TIMESTAMP_JAVA_CLASSLOADING_COMPLETE" in android.app.ApplicationStartInfo [101]  android/app/BroadcastOptions.java:132: lint: Unresolved link/see tag "#setDeliveryGroupMatchingFilter(android.content.IntentFilter)" in android.app.BroadcastOptions [101]  android/app/GrammaticalInflectionManager.java:60: lint: Unresolved link/see tag "android.os.Environment#getDataSystemCeDirectory(int)" in android.app.GrammaticalInflectionManager [101] +android/app/Notification.java:509: lint: Unresolved link/see tag "android.annotation.ColorInt ColorInt" in android.app.Notification [101] +android/app/Notification.java:650: lint: Unresolved link/see tag "android.annotation.ColorInt ColorInt" in android.app.Notification [101]  android/app/Notification.java:1866: lint: Unresolved link/see tag "/*missing*/" in android.app.Notification.Action [101]  android/app/Notification.java:4796: lint: Unresolved link/see tag "android.content.pm.ShortcutInfo#setLongLived() ShortcutInfo#setLongLived()" in android.app.Notification.MessagingStyle [101]  android/app/admin/DevicePolicyManager.java:2670: lint: Unresolved link/see tag "android.os.UserManager#DISALLOW_CAMERA UserManager#DISALLOW_CAMERA" in android.app.admin.DevicePolicyManager [101] @@ -81,14 +86,20 @@ android/app/sdksandbox/SdkSandboxManager.java:112: lint: Unresolved link/see tag  android/companion/CompanionDeviceService.java:273: lint: Unresolved link/see tag "android.companion.AssociationInfo#isSelfManaged() self-managed" in android.companion.CompanionDeviceService [101]  android/companion/CompanionDeviceService.java:282: lint: Unresolved link/see tag "android.companion.AssociationInfo#isSelfManaged() self-managed" in android.companion.CompanionDeviceService [101]  android/companion/virtual/VirtualDevice.java:15: lint: Unresolved link/see tag "android.companion.virtual.VirtualDeviceManager.VirtualDevice VirtualDeviceManager.VirtualDevice" in android.companion.virtual.VirtualDevice [101] +android/companion/virtual/VirtualDevice.java:70: lint: Unresolved link/see tag "android.companion.virtual.VirtualDeviceParams.Builder#setName(String)" in android.companion.virtual.VirtualDevice [101]  android/content/AttributionSource.java:291: lint: Unresolved link/see tag "setNextAttributionSource" in android.content.AttributionSource.Builder [101]  android/content/Context.java:2872: lint: Unresolved link/see tag "android.telephony.MmsManager" in android.content.Context [101] +android/content/Intent.java:4734: lint: Unresolved link/see tag "android.content.pm.UserInfo#isProfile()" in android.content.Intent [101] +android/content/Intent.java:4760: lint: Unresolved link/see tag "android.content.pm.UserInfo#isProfile()" in android.content.Intent [101] +android/content/Intent.java:4778: lint: Unresolved link/see tag "android.content.pm.UserInfo#isProfile()" in android.content.Intent [101] +android/content/Intent.java:4802: lint: Unresolved link/see tag "android.content.pm.UserInfo#isProfile()" in android.content.Intent [101]  android/content/om/OverlayIdentifier.java:20: lint: Unresolved link/see tag "android.content.om.OverlayManagerTransaction.Builder#unregisterFabricatedOverlay(OverlayIdentifier)" in android.content.om.OverlayIdentifier [101]  android/content/om/OverlayInfo.java:78: lint: Unresolved link/see tag "android.content.om.OverlayManagerTransaction.Builder#unregisterFabricatedOverlay(OverlayIdentifier)" in android.content.om.OverlayInfo [101]  android/content/om/OverlayManager.java:9: lint: Unresolved link/see tag "android.content.om.OverlayManagerTransaction#commit()" in android.content.om.OverlayManager [101]  android/content/pm/PackageInstaller.java:2232: lint: Unresolved link/see tag "android.Manifest.permission#INSTALL_GRANT_RUNTIME_PERMISSIONS INSTALL_GRANT_RUNTIME_PERMISSIONS" in android.content.pm.PackageInstaller.SessionParams [101]  android/content/pm/ServiceInfo.java:176: lint: Unresolved link/see tag "android.app.job.JobInfo.Builder#setDataTransfer" in android.content.pm.ServiceInfo [101]  android/content/pm/verify/domain/DomainVerificationUserState.java:82: lint: Unresolved link/see tag "android.content.pm.verify.domain.DomainVerificationUserState.DomainState DomainState" in android.content.pm.verify.domain.DomainVerificationUserState [101] +android/content/res/Resources.java:958: lint: Unresolved link/see tag "android.annotation.UiContext" in android.content.res.Resources [101]  android/credentials/CreateCredentialException.java:22: lint: Unresolved link/see tag "android.credentials.CredentialManager#createCredential(android.credentials.CreateCredentialRequest,android.app.Activity,android.os.CancellationSignal,java.util.concurrent.Executor,android.os.OutcomeReceiver) CredentialManager#createCredential(CreateCredentialRequest, Activity, CancellationSignal, Executor, OutcomeReceiver)" in android.credentials.CreateCredentialException [101]  android/credentials/CreateCredentialException.java:101: lint: Unresolved link/see tag "android.credentials.CredentialManager#createCredential(android.credentials.CreateCredentialRequest,android.app.Activity,android.os.CancellationSignal,java.util.concurrent.Executor,android.os.OutcomeReceiver) CredentialManager#createCredential(CreateCredentialRequest, Activity, CancellationSignal, Executor, OutcomeReceiver)" in android.credentials.CreateCredentialException [101]  android/credentials/CreateCredentialRequest.java:107: lint: Unresolved link/see tag "androidx.credentials.CreateCredentialRequest" in android.credentials.CreateCredentialRequest.Builder [101] @@ -101,6 +112,7 @@ android/credentials/GetCredentialException.java:103: lint: Unresolved link/see t  android/credentials/PrepareGetCredentialResponse.java:20: lint: Unresolved link/see tag "android.credentials.CredentialManager#getCredential(android.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle,android.app.Activity,android.os.CancellationSignal,java.util.concurrent.Executor,android.os.OutcomeReceiver) CredentialManager#getCredential(PendingGetCredentialHandle, Activity, CancellationSignal, Executor, OutcomeReceiver)" in android.credentials.PrepareGetCredentialResponse [101]  android/credentials/PrepareGetCredentialResponse.java:68: lint: Unresolved link/see tag "android.credentials.CredentialManager#getCredential(android.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle,android.app.Activity,android.os.CancellationSignal,java.util.concurrent.Executor,android.os.OutcomeReceiver) CredentialManager#getCredential(PendingGetCredentialHandle, Activity, CancellationSignal, Executor, OutcomeReceiver)" in android.credentials.PrepareGetCredentialResponse [101]  android/credentials/PrepareGetCredentialResponse.java:83: lint: Unresolved link/see tag "android.credentials.CredentialManager#getCredential(android.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle,android.app.Activity,android.os.CancellationSignal,java.util.concurrent.Executor,android.os.OutcomeReceiver)" in android.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle [101] +android/graphics/Paint.java:838: lint: Unresolved link/see tag "android.annotation.ColorLong ColorLong" in android.graphics.Paint [101]  android/graphics/text/LineBreaker.java:246: lint: Unresolved link/see tag "StaticLayout.Builder#setUseBoundsForWidth(boolean)" in android.graphics.text.LineBreaker.Builder [101]  android/hardware/camera2/CameraCharacteristics.java:2169: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#stream-use-case-capability-additional-guaranteed-configurations guideline" in android.hardware.camera2.CameraCharacteristics [101]  android/hardware/camera2/CameraCharacteristics.java:2344: lint: Unresolved link/see tag "android.hardware.camera2.CameraDevice#concurrent-stream-guaranteed-configurations guideline" in android.hardware.camera2.CameraCharacteristics [101] @@ -127,6 +139,9 @@ android/hardware/camera2/CaptureRequest.java:704: lint: Unresolved link/see tag  android/hardware/camera2/CaptureRequest.java:1501: lint: Unresolved link/see tag "SessionConfiguration#setSessionParameters" in android.hardware.camera2.CaptureRequest [101]  android/hardware/camera2/CaptureResult.java:923: lint: Unresolved link/see tag "SessionConfiguration#setSessionParameters" in android.hardware.camera2.CaptureResult [101]  android/hardware/camera2/CaptureResult.java:2337: lint: Unresolved link/see tag "SessionConfiguration#setSessionParameters" in android.hardware.camera2.CaptureResult [101] +android/hardware/input/InputManager.java:215: lint: Unresolved link/see tag "android.hardware.input.InputManagerGlobal#getInputDevice InputManagerGlobal#getInputDevice" in android.hardware.input.InputManager.InputDeviceListener [101] +android/inputmethodservice/AbstractInputMethodService.java:155: lint: Unresolved link/see tag "android.app.ActivityThread ActivityThread" in android.inputmethodservice.AbstractInputMethodService [101] +android/inputmethodservice/InputMethodService.java:1078: lint: Unresolved link/see tag "android.widget.Editor" in android.inputmethodservice.InputMethodService [101]  android/location/GnssSignalType.java:14: lint: Unresolved link/see tag "android.location.GnssStatus.ConstellationType GnssStatus.ConstellationType" in android.location.GnssSignalType [101]  android/location/GnssSignalType.java:48: lint: Unresolved link/see tag "android.location.GnssStatus.ConstellationType GnssStatus.ConstellationType" in android.location.GnssSignalType [101]  android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_ALARM AttributeSdkUsage#USAGE_ALARM" in android.media.AudioAttributes.Builder [101] @@ -141,6 +156,11 @@ android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.m  android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_UNKNOWN AttributeSdkUsage#USAGE_UNKNOWN" in android.media.AudioAttributes.Builder [101]  android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_VOICE_COMMUNICATION AttributeSdkUsage#USAGE_VOICE_COMMUNICATION" in android.media.AudioAttributes.Builder [101]  android/media/AudioAttributes.java:443: lint: Unresolved link/see tag "android.media.AudioAttributes.AttributeSdkUsage#USAGE_VOICE_COMMUNICATION_SIGNALLING AttributeSdkUsage#USAGE_VOICE_COMMUNICATION_SIGNALLING" in android.media.AudioAttributes.Builder [101] +android/media/AudioFormat.java:963: lint: Unresolved link/see tag "android.media.AudioSystem#OUT_CHANNEL_COUNT_MAX AudioSystem#OUT_CHANNEL_COUNT_MAX" in android.media.AudioFormat.Builder [101] +android/media/AudioManager.java:275: lint: Unresolved link/see tag "android.media.audiopolicy.AudioVolumeGroup" in android.media.AudioManager [101] +android/media/AudioManager.java:287: lint: Unresolved link/see tag "android.media.audiopolicy.AudioVolumeGroup" in android.media.AudioManager [101] +android/media/AudioManager.java:311: lint: Unresolved link/see tag "android.media.audiopolicy.AudioVolumeGroup" in android.media.AudioManager [101] +android/media/AudioManager.java:313: lint: Unresolved link/see tag "android.media.audiopolicy.AudioVolumeGroup" in android.media.AudioManager [101]  android/media/AudioMetadata.java:118: lint: Unresolved link/see tag "android.media.AudioPresentation.ContentClassifier One of {@link android.media.AudioPresentation#CONTENT_UNKNOWN AudioPresentation#CONTENT_UNKNOWN},     {@link android.media.AudioPresentation#CONTENT_MAIN AudioPresentation#CONTENT_MAIN},     {@link android.media.AudioPresentation#CONTENT_MUSIC_AND_EFFECTS AudioPresentation#CONTENT_MUSIC_AND_EFFECTS},     {@link android.media.AudioPresentation#CONTENT_VISUALLY_IMPAIRED AudioPresentation#CONTENT_VISUALLY_IMPAIRED},     {@link android.media.AudioPresentation#CONTENT_HEARING_IMPAIRED AudioPresentation#CONTENT_HEARING_IMPAIRED},     {@link android.media.AudioPresentation#CONTENT_DIALOG AudioPresentation#CONTENT_DIALOG},     {@link android.media.AudioPresentation#CONTENT_COMMENTARY AudioPresentation#CONTENT_COMMENTARY},     {@link android.media.AudioPresentation#CONTENT_EMERGENCY AudioPresentation#CONTENT_EMERGENCY},     {@link android.media.AudioPresentation#CONTENT_VOICEOVER AudioPresentation#CONTENT_VOICEOVER}." in android.media.AudioMetadata.Format [101]  android/media/MediaRouter2.java:162: lint: Unresolved link/see tag "#getInstance(android.content.Context,java.lang.String)" in android.media.MediaRouter2 [101]  android/media/midi/MidiUmpDeviceService.java:-1: lint: Unresolved link/see tag "#MidiDeviceService" in android.media.midi.MidiUmpDeviceService [101] @@ -148,6 +168,7 @@ android/media/tv/SectionRequest.java:44: lint: Unresolved link/see tag "android.  android/media/tv/SectionResponse.java:39: lint: Unresolved link/see tag "android.media.tv.BroadcastInfoRequest.RequestOption BroadcastInfoRequest.RequestOption" in android.media.tv.SectionResponse [101]  android/media/tv/TableRequest.java:48: lint: Unresolved link/see tag "android.media.tv.BroadcastInfoRequest.RequestOption BroadcastInfoRequest.RequestOption" in android.media.tv.TableRequest [101]  android/media/tv/TableResponse.java:82: lint: Unresolved link/see tag "android.media.tv.BroadcastInfoRequest.RequestOption BroadcastInfoRequest.RequestOption" in android.media.tv.TableResponse [101] +android/net/EthernetNetworkSpecifier.java:21: lint: Unresolved link/see tag "android.net.EthernetManager" in android.net.EthernetNetworkSpecifier [101]  android/net/eap/EapSessionConfig.java:120: lint: Unresolved link/see tag "android.telephony.Annotation.UiccAppType UiccAppType" in android.net.eap.EapSessionConfig.Builder [101]  android/net/eap/EapSessionConfig.java:135: lint: Unresolved link/see tag "android.telephony.Annotation.UiccAppType UiccAppType" in android.net.eap.EapSessionConfig.Builder [101]  android/net/eap/EapSessionConfig.java:148: lint: Unresolved link/see tag "android.telephony.Annotation.UiccAppType UiccAppType" in android.net.eap.EapSessionConfig.Builder [101] @@ -155,6 +176,10 @@ android/net/eap/EapSessionConfig.java:161: lint: Unresolved link/see tag "androi  android/net/eap/EapSessionConfig.java:288: lint: Unresolved link/see tag "android.telephony.Annotation.UiccAppType UiccAppType" in android.net.eap.EapSessionConfig.EapAkaConfig [101]  android/net/eap/EapSessionConfig.java:390: lint: Unresolved link/see tag "android.telephony.Annotation.UiccAppType UiccAppType" in android.net.eap.EapSessionConfig.EapAkaPrimeConfig [101]  android/net/eap/EapSessionConfig.java:587: lint: Unresolved link/see tag "android.telephony.Annotation.UiccAppType UiccAppType" in android.net.eap.EapSessionConfig.EapSimConfig [101] +android/net/wifi/MloLink.java:32: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_24_GHZ WifiScanner#WIFI_BAND_24_GHZ" in android.net.wifi.MloLink [101] +android/net/wifi/MloLink.java:32: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_5_GHZ WifiScanner#WIFI_BAND_5_GHZ" in android.net.wifi.MloLink [101] +android/net/wifi/MloLink.java:32: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_6_GHZ WifiScanner#WIFI_BAND_6_GHZ" in android.net.wifi.MloLink [101] +android/net/wifi/MloLink.java:32: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_UNSPECIFIED WifiScanner#WIFI_BAND_UNSPECIFIED" in android.net.wifi.MloLink [101]  android/net/wifi/SoftApConfiguration.java:9: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder SoftApConfiguration.Builder" in android.net.wifi.SoftApConfiguration [101]  android/net/wifi/SoftApConfiguration.java:66: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setSsid(java.lang.String) Builder#setSsid(String)" in android.net.wifi.SoftApConfiguration [101]  android/net/wifi/SoftApConfiguration.java:85: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setWifiSsid(android.net.wifi.WifiSsid) Builder#setWifiSsid(WifiSsid)" in android.net.wifi.SoftApConfiguration [101] @@ -166,7 +191,21 @@ android/net/wifi/WifiManager.java:764: lint: Unresolved link/see tag "android.ne  android/net/wifi/WifiManager.java:779: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setBands(int[]) SoftApConfiguration.Builder#setBands(int[])" in android.net.wifi.WifiManager [101]  android/net/wifi/WifiManager.java:779: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray) SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray)" in android.net.wifi.WifiManager [101]  android/net/wifi/WifiManager.java:2466: lint: Unresolved link/see tag "TelephonyManager#hasCarrierPrivileges()." in android.net.wifi.WifiManager [101] +android/net/wifi/aware/PublishConfig.java:50: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_24_GHZ WifiScanner#WIFI_BAND_24_GHZ" in android.net.wifi.aware.PublishConfig [101] +android/net/wifi/aware/PublishConfig.java:50: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_5_GHZ WifiScanner#WIFI_BAND_5_GHZ" in android.net.wifi.aware.PublishConfig [101] +android/net/wifi/aware/PublishConfig.java:249: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_24_GHZ WifiScanner#WIFI_BAND_24_GHZ" in android.net.wifi.aware.PublishConfig.Builder [101] +android/net/wifi/aware/PublishConfig.java:249: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_5_GHZ WifiScanner#WIFI_BAND_5_GHZ" in android.net.wifi.aware.PublishConfig.Builder [101] +android/net/wifi/aware/SubscribeConfig.java:51: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_24_GHZ WifiScanner#WIFI_BAND_24_GHZ" in android.net.wifi.aware.SubscribeConfig [101] +android/net/wifi/aware/SubscribeConfig.java:51: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_5_GHZ WifiScanner#WIFI_BAND_5_GHZ" in android.net.wifi.aware.SubscribeConfig [101] +android/net/wifi/aware/SubscribeConfig.java:276: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_24_GHZ WifiScanner#WIFI_BAND_24_GHZ" in android.net.wifi.aware.SubscribeConfig.Builder [101] +android/net/wifi/aware/SubscribeConfig.java:276: lint: Unresolved link/see tag "android.net.wifi.WifiScanner#WIFI_BAND_5_GHZ WifiScanner#WIFI_BAND_5_GHZ" in android.net.wifi.aware.SubscribeConfig.Builder [101] +android/os/BugreportManager.java:146: lint: Unresolved link/see tag "android.os.BugreportParams#BUGREPORT_FLAG_DEFER_CONSENT BugreportParams#BUGREPORT_FLAG_DEFER_CONSENT" in android.os.BugreportManager.BugreportCallback [101] +android/os/PowerManager.java:796: lint: Unresolved link/see tag "android.os.Temperature" in android.os.PowerManager.OnThermalStatusChangedListener [101] +android/os/RemoteException.java:49: lint: Unresolved link/see tag "android.os.DeadSystemRuntimeException DeadSystemRuntimeException" in android.os.RemoteException [101]  android/provider/Settings.java:374: lint: Unresolved link/see tag "android.credentials.CredentialManager#isEnabledCredentialProviderService()" in android.provider.Settings [101] +android/provider/Settings.java:908: lint: Unresolved link/see tag "android.service.notification.NotificationAssistantService" in android.provider.Settings [101] +android/provider/Settings.java:2181: lint: Unresolved link/see tag "android.app.time.TimeManager" in android.provider.Settings.Global [101] +android/provider/Settings.java:2195: lint: Unresolved link/see tag "android.app.time.TimeManager" in android.provider.Settings.Global [101]  android/security/KeyStoreException.java:27: lint: Unresolved link/see tag "android.security.KeyStoreException.PublicErrorCode PublicErrorCode" in android.security.KeyStoreException [101]  android/service/autofill/FillResponse.java:86: lint: Unresolved link/see tag "setFieldClassificationIds" in android.service.autofill.FillResponse.Builder [101]  android/service/autofill/SaveInfo.java:623: lint: Unresolved link/see tag "FillRequest.getHints()" in android.service.autofill.SaveInfo.Builder [101] @@ -181,6 +220,10 @@ android/service/credentials/CredentialEntry.java:11: lint: Unresolved link/see t  android/service/credentials/CredentialEntry.java:11: lint: Unresolved link/see tag "androidx.credentials.provider.CredentialEntry" in android.service.credentials.CredentialEntry [101]  android/service/credentials/RemoteEntry.java:13: lint: Unresolved link/see tag "androidx.credentials.provider" in android.service.credentials.RemoteEntry [101]  android/service/credentials/RemoteEntry.java:13: lint: Unresolved link/see tag "androidx.credentials.provider.RemoteEntry" in android.service.credentials.RemoteEntry [101] +android/service/notification/NotificationListenerService.java:417: lint: Unresolved link/see tag "android.service.notification.NotificationAssistantService notification assistant" in android.service.notification.NotificationListenerService [101] +android/service/notification/NotificationListenerService.java:435: lint: Unresolved link/see tag "android.service.notification.NotificationAssistantService notification assistant" in android.service.notification.NotificationListenerService [101] +android/service/notification/NotificationListenerService.java:1155: lint: Unresolved link/see tag "android.service.notification.NotificationAssistantService NotificationAssistantService" in android.service.notification.NotificationListenerService.Ranking [101] +android/service/notification/NotificationListenerService.java:1166: lint: Unresolved link/see tag "android.service.notification.NotificationAssistantService NotificationAssistantService" in android.service.notification.NotificationListenerService.Ranking [101]  android/service/quickaccesswallet/WalletCard.java:285: lint: Unresolved link/see tag "PackageManager.FEATURE_WALLET_LOCATION_BASED_SUGGESTIONS" in android.service.quickaccesswallet.WalletCard.Builder [101]  android/service/voice/VoiceInteractionSession.java:293: lint: Unresolved link/see tag "android.service.voice.VoiceInteractionService#KEY_SHOW_SESSION_ID VoiceInteractionService#KEY_SHOW_SESSION_ID" in android.service.voice.VoiceInteractionSession [101]  android/telecom/Call.java:94: lint: unable to parse link/see tag: #playDtmfTone(char [101] @@ -190,19 +233,35 @@ android/telecom/PhoneAccountSuggestion.java:17: lint: Unresolved link/see tag "a  android/telephony/CarrierConfigManager.java:2934: lint: Unresolved link/see tag "android.telephony.TelephonyManager.PremiumCapability TelephonyManager.PremiumCapability" in android.telephony.CarrierConfigManager [101]  android/telephony/CarrierConfigManager.java:4020: lint: Unresolved link/see tag "ImsRegistrationImplBase.ImsRegistrationTech" in android.telephony.CarrierConfigManager.Ims [101]  android/telephony/CarrierConfigManager.java:4108: lint: Unresolved link/see tag "ImsRegistrationImplBase.ImsRegistrationTech" in android.telephony.CarrierConfigManager.Ims [101] +android/telephony/CarrierConfigManager.java:3920: lint: Unresolved link/see tag "android.telephony.ims.SipDelegateManager" in android.telephony.CarrierConfigManager.Ims [101] +android/telephony/CarrierConfigManager.java:4001: lint: Unresolved link/see tag "ImsRegistrationImplBase.ImsRegistrationTech" in android.telephony.CarrierConfigManager.Ims [101] +android/telephony/CarrierConfigManager.java:4089: lint: Unresolved link/see tag "ImsRegistrationImplBase.ImsRegistrationTech" in android.telephony.CarrierConfigManager.Ims [101]  android/telephony/NetworkRegistrationInfo.java:131: lint: Unresolved link/see tag "android.telephony.Annotation.NetworkType NetworkType" in android.telephony.NetworkRegistrationInfo [101] +android/telephony/PhoneStateListener.java:293: lint: Unresolved link/see tag "android.telephony.PreciseDisconnectCause PreciseDisconnectCause" in android.telephony.PhoneStateListener [101] +android/telephony/PhoneStateListener.java:544: lint: Unresolved link/see tag "android.telephony.PreciseDisconnectCause PreciseDisconnectCause" in android.telephony.PhoneStateListener [101]  android/telephony/SubscriptionManager.java:1385: lint: Unresolved link/see tag "Build.VERSION_CODES.P" in android.telephony.SubscriptionManager.OnSubscriptionsChangedListener [101]  android/telephony/SubscriptionManager.java:1385: lint: Unresolved link/see tag "Build.VERSION_CODES.V" in android.telephony.SubscriptionManager.OnSubscriptionsChangedListener [101]  android/telephony/SubscriptionPlan.java:134: lint: Unresolved link/see tag "android.telephony.Annotation.NetworkType NetworkType" in android.telephony.SubscriptionPlan [101]  android/telephony/SubscriptionPlan.java:288: lint: Unresolved link/see tag "android.telephony.Annotation.NetworkType NetworkType" in android.telephony.SubscriptionPlan.Builder [101] +android/telephony/TelephonyCallback.java:113: lint: Unresolved link/see tag "android.telephony.PreciseDisconnectCause PreciseDisconnectCause" in android.telephony.TelephonyCallback.CallDisconnectCauseListener [101]  android/telephony/TelephonyManager.java:2544: lint: Unresolved link/see tag "android.telephony.TelephonyManager.CarrierRestrictionStatus CarrierRestrictionStatus" in android.telephony.TelephonyManager [101]  android/telephony/TelephonyManager.java:2841: lint: Unresolved link/see tag "android.telephony.TelephonyManager.SetOpportunisticSubscriptionResult TelephonyManager.SetOpportunisticSubscriptionResult" in android.telephony.TelephonyManager [101]  android/telephony/TelephonyManager.java:3273: lint: Unresolved link/see tag "android.telephony.TelephonyManager.PurchasePremiumCapabilityResult PurchasePremiumCapabilityResult" in android.telephony.TelephonyManager [101]  android/telephony/TelephonyManager.java:3989: lint: Unresolved link/see tag "android.telephony.TelephonyManager.MobileDataPolicy MobileDataPolicy" in android.telephony.TelephonyManager [101] +android/telephony/data/ApnSetting.java:39: lint: Unresolved link/see tag "android.telephony.data.DataCallResponse#getMtuV4() DataCallResponse#getMtuV4()" in android.telephony.data.ApnSetting [101] +android/telephony/data/ApnSetting.java:50: lint: Unresolved link/see tag "android.telephony.data.DataCallResponse#getMtuV6() DataCallResponse#getMtuV6()" in android.telephony.data.ApnSetting [101] +android/telephony/data/ApnSetting.java:597: lint: Unresolved link/see tag "android.telephony.data.DataCallResponse#getMtuV4() DataCallResponse#getMtuV4()" in android.telephony.data.ApnSetting.Builder [101] +android/telephony/data/ApnSetting.java:611: lint: Unresolved link/see tag "android.telephony.data.DataCallResponse#getMtuV6() DataCallResponse#getMtuV6()" in android.telephony.data.ApnSetting.Builder [101] +android/telephony/euicc/EuiccManager.java:331: lint: Unresolved link/see tag "android.service.euicc.EuiccService#ACTION_BIND_CARRIER_PROVISIONING_SERVICE" in android.telephony.euicc.EuiccManager [101] +android/telephony/ims/ImsMmTelManager.java:117: lint: Unresolved link/see tag "android.telephony.ims.ImsService ImsService" in android.telephony.ims.ImsMmTelManager [101] +android/telephony/ims/ImsRcsManager.java:43: lint: Unresolved link/see tag "android.telephony.ims.ImsService ImsService" in android.telephony.ims.ImsRcsManager [101]  android/telephony/ims/ProvisioningManager.java:102: lint: Unresolved link/see tag "android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability MmTelFeature.MmTelCapabilities.MmTelCapability" in android.telephony.ims.ProvisioningManager [101]  android/telephony/ims/ProvisioningManager.java:102: lint: Unresolved link/see tag "android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech ImsRegistrationImplBase.ImsRegistrationTech" in android.telephony.ims.ProvisioningManager [101]  android/telephony/ims/ProvisioningManager.java:136: lint: Unresolved link/see tag "android.telephony.ims.ImsRcsManager.RcsImsCapabilityFlag ImsRcsManager.RcsImsCapabilityFlag" in android.telephony.ims.ProvisioningManager [101] +android/telephony/ims/RegistrationManager.java:21: lint: Unresolved link/see tag "android.telephony.ims.feature.ImsFeature ImsFeature" in android.telephony.ims.RegistrationManager [101] +android/telephony/ims/RegistrationManager.java:24: lint: Unresolved link/see tag "android.telephony.ims.ImsService ImsService" in android.telephony.ims.RegistrationManager [101]  android/text/DynamicLayout.java:141: lint: Unresolved link/see tag "LineBreakconfig" in android.text.DynamicLayout [101] +android/text/WordSegmentFinder.java:13: lint: Unresolved link/see tag "android.text.method.WordIterator WordIterator" in android.text.WordSegmentFinder [101]  android/view/InputDevice.java:71: lint: Unresolved link/see tag "InputManagerGlobal.InputDeviceListener" in android.view.InputDevice [101]  android/view/PixelCopy.java:468: lint: Unresolved link/see tag "android.view.PixelCopy.CopyResultStatus CopyResultStatus" in android.view.PixelCopy.Result [101]  android/view/ScrollFeedbackProvider.java:-25: lint: Unresolved link/see tag "InputManager" in android.view.ScrollFeedbackProvider [101] @@ -213,86 +272,34 @@ android/view/SurfaceControl.java:908: lint: Unresolved link/see tag "android.vie  android/view/View.java:1647: lint: Unresolved link/see tag "androidx.core.view.ViewCompat#setAccessibilityPaneTitle(View, CharSequence)" in android.view.View [101]  android/view/View.java:4669: lint: Unresolved link/see tag "androidx.core.view.ViewCompat#setScreenReaderFocusable(View, boolean)" in android.view.View [101]  android/view/View.java:4712: lint: Unresolved link/see tag "androidx.core.view.ViewCompat#setAccessibilityHeading(View, boolean)" in android.view.View [101] +android/view/WindowManager.java:230: lint: Unresolved link/see tag "android.annotation.UiContext" in android.view.WindowManager [101] +android/view/WindowManager.java:247: lint: Unresolved link/see tag "android.annotation.UiContext" in android.view.WindowManager [101]  android/view/WindowManager.java:822: lint: @attr must be a field: android.R.attr#Window_windowNoMoveAnimation [106]  android/view/WindowManager.java:832: lint: @attr must be a field: android.R.attr#Window_windowNoMoveAnimation [106] +android/view/WindowMetrics.java:22: lint: Unresolved link/see tag "android.annotation.UiContext" in android.view.WindowMetrics [101] +android/view/WindowMetrics.java:57: lint: Unresolved link/see tag "android.annotation.UiContext" in android.view.WindowMetrics [101] +android/view/WindowMetrics.java:114: lint: Unresolved link/see tag "android.annotation.UiContext" in android.view.WindowMetrics [101] +android/view/WindowMetrics.java:127: lint: Unresolved link/see tag "android.annotation.UiContext" in android.view.WindowMetrics [101]  android/view/accessibility/AccessibilityNodeInfo.java:368: lint: Unresolved link/see tag "androidx.core.view.ViewCompat#addAccessibilityAction(View, AccessibilityNodeInfoCompat.AccessibilityActionCompat)" in android.view.accessibility.AccessibilityNodeInfo [101]  android/view/accessibility/AccessibilityNodeInfo.java:3246: lint: Unresolved link/see tag "androidx.core.view.ViewCompat#addAccessibilityAction(View, AccessibilityNodeInfoCompat.AccessibilityActionCompat)" in android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction [101]  android/view/displayhash/DisplayHashResultCallback.java:38: lint: Unresolved link/see tag "android.view.displayhash.DisplayHashResultCallback.DisplayHashErrorCode DisplayHashErrorCode" in android.view.displayhash.DisplayHashResultCallback [101] - -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_30" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_35" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_40" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_45" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_50" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_55" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_60" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_65" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_70" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_75" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_80" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_85" in android [101] -com/android/server/wm/CompatModePackages.java:92: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_90" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_30" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_35" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_40" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_45" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_50" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_55" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_60" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_65" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_70" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_75" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_80" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_85" in android [101] -com/android/server/wm/CompatModePackages.java:122: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_90" in android [101] -com/android/server/wm/CompatModePackages.java:135: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:135: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:135: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_90" in android [101] -com/android/server/wm/CompatModePackages.java:148: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:148: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:148: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_85" in android [101] -com/android/server/wm/CompatModePackages.java:161: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:161: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:161: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_80" in android [101] -com/android/server/wm/CompatModePackages.java:174: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:174: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:174: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_75" in android [101] -com/android/server/wm/CompatModePackages.java:187: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:187: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:187: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_70" in android [101] -com/android/server/wm/CompatModePackages.java:200: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:200: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:200: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_65" in android [101] -com/android/server/wm/CompatModePackages.java:213: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:213: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:213: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_60" in android [101] -com/android/server/wm/CompatModePackages.java:226: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:226: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:226: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_55" in android [101] -com/android/server/wm/CompatModePackages.java:239: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:239: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:239: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_50" in android [101] -com/android/server/wm/CompatModePackages.java:252: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:252: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:252: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_45" in android [101] -com/android/server/wm/CompatModePackages.java:265: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:265: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:265: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_40" in android [101] -com/android/server/wm/CompatModePackages.java:278: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:278: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:278: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_35" in android [101] -com/android/server/wm/CompatModePackages.java:291: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED" in android [101] -com/android/server/wm/CompatModePackages.java:291: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALED_INVERSE" in android [101] -com/android/server/wm/CompatModePackages.java:291: lint: Unresolved link/see tag "CompatModePackages#DOWNSCALE_30" in android [101] +android/view/inputmethod/EditorInfo.java:107: lint: Unresolved link/see tag "android.widget.Editor Editor" in android.view.inputmethod.EditorInfo [101] +android/view/inputmethod/EditorInfo.java:122: lint: Unresolved link/see tag "android.widget.Editor Editor" in android.view.inputmethod.EditorInfo [101] +android/view/inputmethod/InputMethodManager.java:423: lint: Unresolved link/see tag "android.widget.Editor Editor" in android.view.inputmethod.InputMethodManager [101] +android/view/inputmethod/InputMethodManager.java:447: lint: Unresolved link/see tag "android.widget.Editor Editor" in android.view.inputmethod.InputMethodManager [101] +android/view/inputmethod/InputMethodManager.java:456: lint: Unresolved link/see tag "android.widget.Editor Editor" in android.view.inputmethod.InputMethodManager [101] +android/view/inspector/PropertyReader.java:141: lint: Unresolved link/see tag "android.annotation.ColorInt ColorInt" in android.view.inspector.PropertyReader [101] +android/window/BackEvent.java:24: lint: Unresolved link/see tag "android.window.BackMotionEvent BackMotionEvent" in android.window.BackEvent [101]  android/net/wifi/SoftApConfiguration.java:173: lint: Unresolved link/see tag "android.net.wifi.SoftApConfiguration.Builder#setShutdownTimeoutMillis(long)" in android.net.wifi.SoftApConfiguration [101] - +android/content/pm/ActivityInfo.java:1197: lint: Unresolved link/see tag "android.view.ViewRootImpl" in android.content.pm.ActivityInfo [101] +android/os/UserManager.java:2384: lint: Unresolved link/see tag "android.annotation.UserHandleAware @UserHandleAware" in android.os.UserManager [101] +android/os/UserManager.java:2384: lint: Unresolved link/see tag "android.annotation.UserHandleAware#enabledSinceTargetSdkVersion" in android.os.UserManager [101]  android/service/voice/AlwaysOnHotwordDetector.java:269: lint: Unresolved link/see tag "#initialize( PersistableBundle, SharedMemory, SoundTrigger.ModuleProperties)" in android.service.voice.AlwaysOnHotwordDetector [101]  android/service/voice/AlwaysOnHotwordDetector.java:269: lint: Unresolved link/see tag "STATE_HARDWARE_UNAVAILABLE" in android.service.voice.AlwaysOnHotwordDetector [101] +android/service/voice/AlwaysOnHotwordDetector.java:278: lint: Unresolved link/see tag "#STATE_ERROR" in android [101] +android/service/voice/AlwaysOnHotwordDetector.java:278: lint: Unresolved link/see tag "Callback#onFailure" in android [101] +android/service/voice/AlwaysOnHotwordDetector.java:278: lint: Unresolved link/see tag "Callback#onUnknownFailure" in android [101]  android/telephony/TelephonyRegistryManager.java:242: lint: Unresolved link/see tag "#listenFromListener" in android [101]  android/view/animation/AnimationUtils.java:64: lint: Unresolved link/see tag "Build.VERSION_CODES#VANILLA_ICE_CREAM" in android.view.animation.AnimationUtils [101]  android/view/contentcapture/ContentCaptureSession.java:188: lint: Unresolved link/see tag "UPSIDE_DOWN_CAKE" in android.view.contentcapture.ContentCaptureSession [101] @@ -315,6 +322,7 @@ com/android/server/pm/PackageInstallerSession.java:327: lint: Unresolved link/se  com/android/server/pm/PackageInstallerSession.java:327: lint: Unresolved link/see tag "Build.VERSION_CODES#UPSIDE_DOWN_CAKE API 34" in android [101]  com/android/server/pm/PackageInstallerSession.java:327: lint: Unresolved link/see tag "PackageInstaller.SessionParams#setRequestUpdateOwnership(boolean)" in android [101]  com/android/server/pm/PackageInstallerSession.java:358: lint: Unresolved link/see tag "IntentSender" in android [101] +com/android/server/devicepolicy/DevicePolicyManagerService.java:860: lint: Unresolved link/see tag "android.security.IKeyChainService#setGrant" in android [101]  android/telephony/SubscriptionManager.java:1370: lint: Unresolved link/see tag "Build.VERSION_CODES.Q" in android.telephony.SubscriptionManager.OnSubscriptionsChangedListener [101]  android/companion/virtual/sensor/VirtualSensorDirectChannelWriter.java:-4: lint: Invalid tag: @Override [131] diff --git a/core/api/current.txt b/core/api/current.txt index 96a959572949..d037c31e5af7 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -18539,8 +18539,10 @@ package android.hardware.biometrics {      ctor public BiometricPrompt.CryptoObject(@NonNull javax.crypto.Mac);      ctor @Deprecated public BiometricPrompt.CryptoObject(@NonNull android.security.identity.IdentityCredential);      ctor public BiometricPrompt.CryptoObject(@NonNull android.security.identity.PresentationSession); +    ctor @FlaggedApi("android.hardware.biometrics.add_key_agreement_crypto_object") public BiometricPrompt.CryptoObject(@NonNull javax.crypto.KeyAgreement);      method public javax.crypto.Cipher getCipher();      method @Deprecated @Nullable public android.security.identity.IdentityCredential getIdentityCredential(); +    method @FlaggedApi("android.hardware.biometrics.add_key_agreement_crypto_object") @Nullable public javax.crypto.KeyAgreement getKeyAgreement();      method public javax.crypto.Mac getMac();      method @Nullable public android.security.identity.PresentationSession getPresentationSession();      method public java.security.Signature getSignature(); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 358c8e72064b..a99eeb0c36d8 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -3946,7 +3946,7 @@ package android.content.pm {      field public static final int DELETE_FAILED_OWNER_BLOCKED = -4; // 0xfffffffc      field public static final int DELETE_KEEP_DATA = 1; // 0x1      field public static final int DELETE_SUCCEEDED = 1; // 0x1 -    field public static final String EXTRA_REQUEST_PERMISSIONS_DEVICE_ID = "android.content.pm.extra.REQUEST_PERMISSIONS_DEVICE_ID"; +    field @FlaggedApi("android.permission.flags.device_aware_permission_apis") public static final String EXTRA_REQUEST_PERMISSIONS_DEVICE_ID = "android.content.pm.extra.REQUEST_PERMISSIONS_DEVICE_ID";      field public static final String EXTRA_REQUEST_PERMISSIONS_LEGACY_ACCESS_PERMISSION_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_LEGACY_ACCESS_PERMISSION_NAMES";      field public static final String EXTRA_REQUEST_PERMISSIONS_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";      field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS"; diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java index 7b3d01712867..d15c79f41d3f 100644 --- a/core/java/android/app/ApplicationExitInfo.java +++ b/core/java/android/app/ApplicationExitInfo.java @@ -468,6 +468,15 @@ public final class ApplicationExitInfo implements Parcelable {       */      public static final int SUBREASON_EXCESSIVE_BINDER_OBJECTS = 29; +    /** +     * The process was killed by the [kernel] Out-of-memory (OOM) killer; this +     * would be set only when the reason is {@link #REASON_LOW_MEMORY}. +     * +     * For internal use only. +     * @hide +     */ +    public static final int SUBREASON_OOM_KILL = 30; +      // If there is any OEM code which involves additional app kill reasons, it should      // be categorized in {@link #REASON_OTHER}, with subreason code starting from 1000. @@ -644,6 +653,7 @@ public final class ApplicationExitInfo implements Parcelable {          SUBREASON_PACKAGE_UPDATE,          SUBREASON_UNDELIVERED_BROADCAST,          SUBREASON_EXCESSIVE_BINDER_OBJECTS, +        SUBREASON_OOM_KILL,      })      @Retention(RetentionPolicy.SOURCE)      public @interface SubReason {} @@ -1371,6 +1381,8 @@ public final class ApplicationExitInfo implements Parcelable {                  return "UNDELIVERED BROADCAST";              case SUBREASON_EXCESSIVE_BINDER_OBJECTS:                  return "EXCESSIVE BINDER OBJECTS"; +            case SUBREASON_OOM_KILL: +                return "OOM KILL";              default:                  return "UNKNOWN";          } diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java index 2fb428b3e0b4..a84845a15a79 100644 --- a/core/java/android/companion/CompanionDeviceManager.java +++ b/core/java/android/companion/CompanionDeviceManager.java @@ -240,6 +240,12 @@ public final class CompanionDeviceManager {      public static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 0x63826983; // ?RES      /** +     * The length limit of Association tag. +     * @hide +     */ +    private static final int ASSOCIATION_TAG_LENGTH_LIMIT = 100; + +    /**       * Callback for applications to receive updates about and the outcome of       * {@link AssociationRequest} issued via {@code associate()} call.       * @@ -1409,7 +1415,7 @@ public final class CompanionDeviceManager {      /**       * Sets the {@link AssociationInfo#getTag() tag} for this association.       * -     * <p>The length of the tag must be at most 20 characters. +     * <p>The length of the tag must be at most 100 characters to save disk space.       *       * <p>This allows to store useful information about the associated devices.       * @@ -1421,8 +1427,8 @@ public final class CompanionDeviceManager {      public void setAssociationTag(int associationId, @NonNull String tag) {          Objects.requireNonNull(tag, "tag cannot be null"); -        if (tag.length() > 20) { -            throw new IllegalArgumentException("Length of the tag must be at most 20 characters"); +        if (tag.length() > ASSOCIATION_TAG_LENGTH_LIMIT) { +            throw new IllegalArgumentException("Length of the tag must be at most 100 characters");          }          try { diff --git a/core/java/android/companion/virtualnative/OWNERS b/core/java/android/companion/virtualnative/OWNERS new file mode 100644 index 000000000000..29681045ac4a --- /dev/null +++ b/core/java/android/companion/virtualnative/OWNERS @@ -0,0 +1 @@ +include /services/companion/java/com/android/server/companion/virtual/OWNERS diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 3fc515d3d37d..8fbe50c32881 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -4802,6 +4802,7 @@ public abstract class PackageManager {       * @hide       */      @SystemApi +    @FlaggedApi(android.permission.flags.Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS)      public static final String EXTRA_REQUEST_PERMISSIONS_DEVICE_ID =              "android.content.pm.extra.REQUEST_PERMISSIONS_DEVICE_ID"; diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig index ea0f049cece3..3e12a1a66791 100644 --- a/core/java/android/content/pm/multiuser.aconfig +++ b/core/java/android/content/pm/multiuser.aconfig @@ -13,3 +13,10 @@ flag {      description: "Bind wallpaper service on its own thread instead of system_server's main handler during a user switch."      bug: "302100344"  } + +flag { +    name: "support_communal_profile" +    namespace: "multiuser" +    description: "Framework support for communal profile." +    bug: "285426179" +} diff --git a/core/java/android/credentials/GetCandidateCredentialsResponse.java b/core/java/android/credentials/GetCandidateCredentialsResponse.java index 231e4bc4ac75..1b130a9fb64d 100644 --- a/core/java/android/credentials/GetCandidateCredentialsResponse.java +++ b/core/java/android/credentials/GetCandidateCredentialsResponse.java @@ -53,6 +53,15 @@ public final class GetCandidateCredentialsResponse implements Parcelable {          mCandidateProviderDataList = new ArrayList<>(candidateProviderDataList);      } +    /** +     * Returns candidate provider data list. +     * +     * @hide +     */ +    public List<GetCredentialProviderData> getCandidateProviderDataList() { +        return mCandidateProviderDataList; +    } +      protected GetCandidateCredentialsResponse(Parcel in) {          List<GetCredentialProviderData> candidateProviderDataList = new ArrayList<>();          in.readTypedList(candidateProviderDataList, GetCredentialProviderData.CREATOR); diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index af448f0c4917..490ff640885e 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -20,8 +20,10 @@ import static android.Manifest.permission.TEST_BIOMETRIC;  import static android.Manifest.permission.USE_BIOMETRIC;  import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;  import static android.hardware.biometrics.BiometricManager.Authenticators; +import static android.hardware.biometrics.Flags.FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT;  import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi;  import android.annotation.IntDef;  import android.annotation.NonNull;  import android.annotation.Nullable; @@ -53,6 +55,7 @@ import java.util.List;  import java.util.concurrent.Executor;  import javax.crypto.Cipher; +import javax.crypto.KeyAgreement;  import javax.crypto.Mac;  /** @@ -748,7 +751,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan       * A wrapper class for the cryptographic operations supported by BiometricPrompt.       *       * <p>Currently the framework supports {@link Signature}, {@link Cipher}, {@link Mac}, -     * {@link IdentityCredential}, and {@link PresentationSession}. +     * {@link IdentityCredential}, {@link PresentationSession} and {@link KeyAgreement}.       *       * <p>Cryptographic operations in Android can be split into two categories: auth-per-use and       * time-based. This is specified during key creation via the timeout parameter of the @@ -793,6 +796,11 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan              super(session);          } +        @FlaggedApi(FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT) +        public CryptoObject(@NonNull KeyAgreement keyAgreement) { +            super(keyAgreement); +        } +          /**           * Get {@link Signature} object.           * @return {@link Signature} object or null if this doesn't contain one. @@ -834,6 +842,15 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan          public @Nullable PresentationSession getPresentationSession() {              return super.getPresentationSession();          } + +        /** +         * Get {@link KeyAgreement} object. +         * @return {@link KeyAgreement} object or null if this doesn't contain one. +         */ +        @FlaggedApi(FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT) +        public @Nullable KeyAgreement getKeyAgreement() { +            return super.getKeyAgreement(); +        }      }      /** diff --git a/core/java/android/hardware/biometrics/CryptoObject.java b/core/java/android/hardware/biometrics/CryptoObject.java index 267ef3637ce7..151f819329c9 100644 --- a/core/java/android/hardware/biometrics/CryptoObject.java +++ b/core/java/android/hardware/biometrics/CryptoObject.java @@ -16,6 +16,9 @@  package android.hardware.biometrics; +import static android.hardware.biometrics.Flags.FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT; + +import android.annotation.FlaggedApi;  import android.annotation.NonNull;  import android.security.identity.IdentityCredential;  import android.security.identity.PresentationSession; @@ -24,6 +27,7 @@ import android.security.keystore2.AndroidKeyStoreProvider;  import java.security.Signature;  import javax.crypto.Cipher; +import javax.crypto.KeyAgreement;  import javax.crypto.Mac;  /** @@ -62,6 +66,11 @@ public class CryptoObject {          mCrypto = session;      } +    @FlaggedApi(FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT) +    public CryptoObject(@NonNull KeyAgreement keyAgreement) { +        mCrypto = keyAgreement; +    } +      /**       * Get {@link Signature} object.       * @return {@link Signature} object or null if this doesn't contain one. @@ -105,6 +114,15 @@ public class CryptoObject {      }      /** +     * Get {@link PresentationSession} object. +     * @return {@link PresentationSession} object or null if this doesn't contain one. +     */ +    @FlaggedApi(FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT) +    public KeyAgreement getKeyAgreement() { +        return mCrypto instanceof KeyAgreement ? (KeyAgreement) mCrypto : null; +    } + +    /**       * @hide       * @return the opId associated with this object or 0 if none       */ diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index f59437795b9c..5bfda70f03de 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -24,12 +24,14 @@ import static android.Manifest.permission.USE_BIOMETRIC;  import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;  import static android.Manifest.permission.USE_FINGERPRINT;  import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_NONE; +import static android.hardware.biometrics.Flags.FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT;  import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON;  import static com.android.internal.util.FrameworkStatsLog.AUTH_DEPRECATED_APIUSED__DEPRECATED_API__API_FINGERPRINT_MANAGER_AUTHENTICATE;  import static com.android.internal.util.FrameworkStatsLog.AUTH_DEPRECATED_APIUSED__DEPRECATED_API__API_FINGERPRINT_MANAGER_HAS_ENROLLED_FINGERPRINTS;  import static com.android.internal.util.FrameworkStatsLog.AUTH_DEPRECATED_APIUSED__DEPRECATED_API__API_FINGERPRINT_MANAGER_IS_HARDWARE_DETECTED; +import android.annotation.FlaggedApi;  import android.annotation.IntDef;  import android.annotation.NonNull;  import android.annotation.Nullable; @@ -76,6 +78,7 @@ import java.util.List;  import java.util.concurrent.Executor;  import javax.crypto.Cipher; +import javax.crypto.KeyAgreement;  import javax.crypto.Mac;  /** @@ -312,6 +315,16 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing          public PresentationSession getPresentationSession() {              return super.getPresentationSession();          } + +        /** +         * Get {@link KeyAgreement} object. +         * @return {@link KeyAgreement} object or null if this doesn't contain one. +         * @hide +         */ +        @FlaggedApi(FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT) +        public KeyAgreement getKeyAgreement() { +            return super.getKeyAgreement(); +        }      }      /** diff --git a/core/java/android/hardware/input/KeyboardLayout.java b/core/java/android/hardware/input/KeyboardLayout.java index bbfed24f9dc1..883f157bbfe5 100644 --- a/core/java/android/hardware/input/KeyboardLayout.java +++ b/core/java/android/hardware/input/KeyboardLayout.java @@ -82,8 +82,8 @@ public final class KeyboardLayout implements Parcelable, Comparable<KeyboardLayo          DVORAK(4, LAYOUT_TYPE_DVORAK),          COLEMAK(5, LAYOUT_TYPE_COLEMAK),          WORKMAN(6, LAYOUT_TYPE_WORKMAN), -        TURKISH_F(7, LAYOUT_TYPE_TURKISH_F), -        TURKISH_Q(8, LAYOUT_TYPE_TURKISH_Q), +        TURKISH_Q(7, LAYOUT_TYPE_TURKISH_Q), +        TURKISH_F(8, LAYOUT_TYPE_TURKISH_F),          EXTENDED(9, LAYOUT_TYPE_EXTENDED);          private final int mValue; diff --git a/core/java/android/os/OomKillRecord.java b/core/java/android/os/OomKillRecord.java new file mode 100644 index 000000000000..151a65fdfaf5 --- /dev/null +++ b/core/java/android/os/OomKillRecord.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.os; + + +/** + * Expected data to get back from the OOM event's file. + * Note that this should be equivalent to the struct <b>OomKill</b> inside + * <pre> + * system/memory/libmeminfo/libmemevents/include/memevents.h + * </pre> + * + * @hide + */ +public final class OomKillRecord { +    private long mTimeStampInMillis; +    private int mPid; +    private int mUid; +    private String mProcessName; +    private short mOomScoreAdj; + +    public OomKillRecord(long timeStampInMillis, int pid, int uid, +                            String processName, short oomScoreAdj) { +        this.mTimeStampInMillis = timeStampInMillis; +        this.mPid = pid; +        this.mUid = uid; +        this.mProcessName = processName; +        this.mOomScoreAdj = oomScoreAdj; +    } + +    public long getTimestampMilli() { +        return mTimeStampInMillis; +    } + +    public int getPid() { +        return mPid; +    } + +    public int getUid() { +        return mUid; +    } + +    public String getProcessName() { +        return mProcessName; +    } + +    public short getOomScoreAdj() { +        return mOomScoreAdj; +    } +} diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index b414ed4faea2..36d318008560 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -11607,6 +11607,45 @@ public final class Settings {                  "accessibility_magnification_joystick_enabled";          /** +         * Controls magnification enable gesture. Accessibility magnification can have one or more +         * enable gestures. +         * +         * @see #ACCESSIBILITY_MAGNIFICATION_GESTURE_NONE +         * @see #ACCESSIBILITY_MAGNIFICATION_GESTURE_SINGLE_FINGER_TRIPLE_TAP +         * @see #ACCESSIBILITY_MAGNIFICATION_GESTURE_TWO_FINGER_TRIPLE_TAP +         * @hide +         */ +        public static final String ACCESSIBILITY_MAGNIFICATION_GESTURE = +                "accessibility_magnification_gesture"; + +        /** +         * Magnification enable gesture value that is a default value. +         * @hide +         */ +        public static final int ACCESSIBILITY_MAGNIFICATION_GESTURE_NONE = 0x0; + +        /** +         * Magnification enable gesture value is single finger triple tap. +         * @hide +         */ +        public static final int ACCESSIBILITY_MAGNIFICATION_GESTURE_SINGLE_FINGER_TRIPLE_TAP = 0x1; + +        /** +         * Magnification enable gesture value is two finger triple tap. +         * @hide +         */ +        public static final int ACCESSIBILITY_MAGNIFICATION_GESTURE_TWO_FINGER_TRIPLE_TAP = 0x2; + +        /** +         * Magnification enable gesture values include single finger triple tap and two finger +         * triple tap. +         * @hide +         */ +        public static final int ACCESSIBILITY_MAGNIFICATION_GESTURE_ALL = +                ACCESSIBILITY_MAGNIFICATION_GESTURE_SINGLE_FINGER_TRIPLE_TAP +                | ACCESSIBILITY_MAGNIFICATION_GESTURE_TWO_FINGER_TRIPLE_TAP; + +        /**           * Controls magnification capability. Accessibility magnification is capable of at least one           * of the magnification modes.           * diff --git a/core/java/android/service/credentials/CredentialProviderService.java b/core/java/android/service/credentials/CredentialProviderService.java index be7b72202b3f..a2b0a669c768 100644 --- a/core/java/android/service/credentials/CredentialProviderService.java +++ b/core/java/android/service/credentials/CredentialProviderService.java @@ -153,6 +153,18 @@ public abstract class CredentialProviderService extends Service {      public static final String EXTRA_BEGIN_GET_CREDENTIAL_REQUEST =              "android.service.credentials.extra.BEGIN_GET_CREDENTIAL_REQUEST"; +    /** +     * The key to autofillId associated with the requested credential option and the corresponding +     * credential entry. The associated autofillId will be contained inside the candidate query +     * bundle of {@link android.credentials.CredentialOption} if requested through the +     * {@link com.android.credentialmanager.autofill.CredentialAutofillService}. The resulting +     * credential entry will  contain the autofillId inside its framework extras intent. +     * +     * @hide +     */ +    public static final String EXTRA_AUTOFILL_ID = +            "android.service.credentials.extra.AUTOFILL_ID"; +      private static final String TAG = "CredProviderService";       /** diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl index c4d307073d12..a150187bbc6c 100644 --- a/core/java/android/view/IRecentsAnimationController.aidl +++ b/core/java/android/view/IRecentsAnimationController.aidl @@ -23,6 +23,8 @@ import android.graphics.GraphicBuffer;  import android.window.PictureInPictureSurfaceTransaction;  import android.window.TaskSnapshot; +import com.android.internal.os.IResultReceiver; +  /**   * Passed to the {@link IRecentsAnimationRunner} in order for the runner to control to let the   * runner control certain aspects of the recents animation, and to notify window manager when the @@ -58,7 +60,7 @@ interface IRecentsAnimationController {       *                          top resumed app, false otherwise.       */      @UnsupportedAppUsage -    void finish(boolean moveHomeToTop, boolean sendUserLeaveHint); +    void finish(boolean moveHomeToTop, boolean sendUserLeaveHint, in IResultReceiver finishCb);      /**       * Called by the handler to indicate that the recents animation input consumer should be diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java index 2761aaeb4a7d..45b3fdd7e5bc 100644 --- a/core/java/android/view/InputWindowHandle.java +++ b/core/java/android/view/InputWindowHandle.java @@ -16,6 +16,8 @@  package android.view; +import static com.android.window.flags.Flags.surfaceTrustedOverlay; +  import android.annotation.IntDef;  import android.annotation.Nullable;  import android.graphics.Matrix; @@ -35,7 +37,6 @@ import java.lang.ref.WeakReference;   * @hide   */  public final class InputWindowHandle { -      /**       * An internal annotation for all the {@link android.os.InputConfig} flags that can be       * specified to {@link #inputConfig} to control the behavior of an input window. Only the @@ -59,7 +60,6 @@ public final class InputWindowHandle {              InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER,              InputConfig.IS_WALLPAPER,              InputConfig.PAUSE_DISPATCHING, -            InputConfig.TRUSTED_OVERLAY,              InputConfig.WATCH_OUTSIDE_TOUCH,              InputConfig.SLIPPERY,              InputConfig.DISABLE_USER_ACTIVITY, @@ -272,4 +272,13 @@ public final class InputWindowHandle {          }          this.inputConfig &= ~inputConfig;      } + +    public void setTrustedOverlay(SurfaceControl.Transaction t, SurfaceControl sc, +            boolean isTrusted) { +        if (surfaceTrustedOverlay()) { +            t.setTrustedOverlay(sc, isTrusted); +        } else if (isTrusted) { +            inputConfig |= InputConfig.TRUSTED_OVERLAY; +        } +    }  } diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index effc127dabd2..57b19a8ce12f 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -407,7 +407,7 @@ public class SurfaceControlViewHost {      public @Nullable SurfacePackage getSurfacePackage() {          if (mSurfaceControl != null && mAccessibilityEmbeddedConnection != null) {              return new SurfacePackage(new SurfaceControl(mSurfaceControl, "getSurfacePackage"), -                mAccessibilityEmbeddedConnection, getFocusGrantToken(), mRemoteInterface); +                mAccessibilityEmbeddedConnection, getInputTransferToken(), mRemoteInterface);          } else {              return null;          } @@ -526,10 +526,12 @@ public class SurfaceControlViewHost {      }      /** +     * Returns an input token used which can be used to request focus on the embedded surface. +     *       * @hide       */ -    public IBinder getFocusGrantToken() { -        return mWm.getFocusGrantToken(getWindowToken().asBinder()); +    public IBinder getInputTransferToken() { +        return mWm.getInputTransferToken(getWindowToken().asBinder());      }      private void addWindowToken(WindowManager.LayoutParams attrs) { diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index e64274ec3892..2f4bea0270c1 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1850,6 +1850,8 @@ public interface WindowManager extends ViewManager {                          to = "PHONE"),                  @ViewDebug.IntToString(from = TYPE_SYSTEM_ALERT,                          to = "SYSTEM_ALERT"), +                @ViewDebug.IntToString(from = TYPE_KEYGUARD, +                        to = "KEYGUARD"),                  @ViewDebug.IntToString(from = TYPE_TOAST,                          to = "TOAST"),                  @ViewDebug.IntToString(from = TYPE_SYSTEM_OVERLAY, @@ -1898,6 +1900,8 @@ public interface WindowManager extends ViewManager {                          to = "PRIVATE_PRESENTATION"),                  @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION,                          to = "VOICE_INTERACTION"), +                @ViewDebug.IntToString(from = TYPE_ACCESSIBILITY_OVERLAY, +                        to = "ACCESSIBILITY_OVERLAY"),                  @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION_STARTING,                          to = "VOICE_INTERACTION_STARTING"),                  @ViewDebug.IntToString(from = TYPE_DOCK_DIVIDER, @@ -1907,7 +1911,13 @@ public interface WindowManager extends ViewManager {                  @ViewDebug.IntToString(from = TYPE_SCREENSHOT,                          to = "SCREENSHOT"),                  @ViewDebug.IntToString(from = TYPE_APPLICATION_OVERLAY, -                        to = "APPLICATION_OVERLAY") +                        to = "APPLICATION_OVERLAY"), +                @ViewDebug.IntToString(from = TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, +                        to = "ACCESSIBILITY_MAGNIFICATION_OVERLAY"), +                @ViewDebug.IntToString(from = TYPE_NOTIFICATION_SHADE, +                        to = "NOTIFICATION_SHADE"), +                @ViewDebug.IntToString(from = TYPE_STATUS_BAR_ADDITIONAL, +                        to = "STATUS_BAR_ADDITIONAL")          })          @WindowType          public int type; diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 7d3d283a45f2..8fe9b7bc0ca4 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -58,7 +58,7 @@ public class WindowlessWindowManager implements IWindowSession {          SurfaceControl mLeash;          Rect mFrame;          Rect mAttachedFrame; -        IBinder mFocusGrantToken; +        IBinder mInputTransferToken;          State(SurfaceControl sc, WindowManager.LayoutParams p, int displayId, IWindow client,                  SurfaceControl leash, Rect frame) { @@ -89,7 +89,7 @@ public class WindowlessWindowManager implements IWindowSession {      private final Configuration mConfiguration;      private final IWindowSession mRealWm;      private final IBinder mHostInputToken; -    private final IBinder mFocusGrantToken = new Binder(); +    private final IBinder mInputTransferToken = new Binder();      private InsetsState mInsetsState;      private final ClientWindowFrames mTmpFrames = new ClientWindowFrames();      private final MergedConfiguration mTmpConfig = new MergedConfiguration(); @@ -109,17 +109,17 @@ public class WindowlessWindowManager implements IWindowSession {          mConfiguration.setTo(configuration);      } -    IBinder getFocusGrantToken(IBinder window) { +    IBinder getInputTransferToken(IBinder window) {          synchronized (this) {              // This can only happen if someone requested the focusGrantToken before setView was              // called for the SCVH. In that case, use the root focusGrantToken since this will be              // the same token sent to WMS for the root window once setView is called.              if (mStateForWindow.isEmpty()) { -                return mFocusGrantToken; +                return mInputTransferToken;              }              State state = mStateForWindow.get(window);              if (state != null) { -                return state.mFocusGrantToken; +                return state.mInputTransferToken;              }          } @@ -207,9 +207,9 @@ public class WindowlessWindowManager implements IWindowSession {              // Give the first window the mFocusGrantToken since that's the token the host can use              // to give focus to the embedded.              if (mStateForWindow.isEmpty()) { -                state.mFocusGrantToken = mFocusGrantToken; +                state.mInputTransferToken = mInputTransferToken;              } else { -                state.mFocusGrantToken = new Binder(); +                state.mInputTransferToken = new Binder();              }              mStateForWindow.put(window.asBinder(), state); @@ -230,12 +230,13 @@ public class WindowlessWindowManager implements IWindowSession {                              new SurfaceControl(sc, "WindowlessWindowManager.addToDisplay"),                              window, mHostInputToken, attrs.flags, attrs.privateFlags,                              attrs.inputFeatures, attrs.type, -                            attrs.token, state.mFocusGrantToken, attrs.getTitle().toString(), +                            attrs.token, state.mInputTransferToken, attrs.getTitle().toString(),                              outInputChannel);                  } else {                      mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags,                              attrs.privateFlags, attrs.inputFeatures, attrs.type, attrs.token, -                            state.mFocusGrantToken, attrs.getTitle().toString(), outInputChannel); +                            state.mInputTransferToken, attrs.getTitle().toString(), +                            outInputChannel);                  }                  state.mInputChannelToken =                          outInputChannel != null ? outInputChannel.getToken() : null; diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig index a0d58001a30d..e31ad82d3f55 100644 --- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig +++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig @@ -4,5 +4,5 @@ flag {      namespace: "accessibility"      name: "force_invert_color"      description: "Enable force force-dark for smart inversion and dark theme everywhere" -    bug: "239594271" +    bug: "282821643"  }
\ No newline at end of file diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig new file mode 100644 index 000000000000..1b98806a0f01 --- /dev/null +++ b/core/java/android/window/flags/window_surfaces.aconfig @@ -0,0 +1,11 @@ +package: "com.android.window.flags" + +# Project link: https://gantry.corp.google.com/projects/android_platform_window_surfaces/changes + +flag { +    namespace: "window_surfaces" +    name: "surface_trusted_overlay" +    description: "Whether to add trusted overlay flag on the SurfaceControl or the InputWindow" +    is_fixed_read_only: true +    bug: "292032926" +} diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java index 1bfb51cc4b82..6e836e077e44 100644 --- a/core/java/com/android/internal/jank/InteractionJankMonitor.java +++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java @@ -837,25 +837,41 @@ public class InteractionJankMonitor {      @WorkerThread      private void updateProperties(DeviceConfig.Properties properties) { -        mSamplingInterval = properties.getInt(SETTINGS_SAMPLING_INTERVAL_KEY, -                DEFAULT_SAMPLING_INTERVAL); -        mTraceThresholdMissedFrames = properties.getInt(SETTINGS_THRESHOLD_MISSED_FRAMES_KEY, -                DEFAULT_TRACE_THRESHOLD_MISSED_FRAMES); -        mTraceThresholdFrameTimeMillis = properties.getInt( -                SETTINGS_THRESHOLD_FRAME_TIME_MILLIS_KEY, -                DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS); -        // Never allow the debug overlay to be used on user builds -        boolean debugOverlayEnabled = Build.IS_DEBUGGABLE && properties.getBoolean( -                SETTINGS_DEBUG_OVERLAY_ENABLED_KEY, -                DEFAULT_DEBUG_OVERLAY_ENABLED); -        if (debugOverlayEnabled && mDebugOverlay == null) { -            mDebugOverlay = new InteractionMonitorDebugOverlay(mLock, mDebugBgColor, mDebugYOffset); -        } else if (!debugOverlayEnabled && mDebugOverlay != null) { -            mDebugOverlay.dispose(); -            mDebugOverlay = null; +        for (String property : properties.getKeyset()) { +            switch (property) { +                case SETTINGS_SAMPLING_INTERVAL_KEY: +                    mSamplingInterval = properties.getInt(property, DEFAULT_SAMPLING_INTERVAL); +                    break; +                case SETTINGS_THRESHOLD_MISSED_FRAMES_KEY: +                    mTraceThresholdMissedFrames = +                            properties.getInt(property, DEFAULT_TRACE_THRESHOLD_MISSED_FRAMES); +                    break; +                case SETTINGS_THRESHOLD_FRAME_TIME_MILLIS_KEY: +                    mTraceThresholdFrameTimeMillis = +                            properties.getInt(property, DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS); +                    break; +                case SETTINGS_ENABLED_KEY: +                    mEnabled = properties.getBoolean(property, DEFAULT_ENABLED); +                    break; +                case SETTINGS_DEBUG_OVERLAY_ENABLED_KEY: +                    // Never allow the debug overlay to be used on user builds +                    boolean debugOverlayEnabled = Build.IS_DEBUGGABLE +                            && properties.getBoolean(property, DEFAULT_DEBUG_OVERLAY_ENABLED); +                    if (debugOverlayEnabled && mDebugOverlay == null) { +                        mDebugOverlay = new InteractionMonitorDebugOverlay( +                                mLock, mDebugBgColor, mDebugYOffset); +                    } else if (!debugOverlayEnabled && mDebugOverlay != null) { +                        mDebugOverlay.dispose(); +                        mDebugOverlay = null; +                    } +                    break; +                default: +                    if (DEBUG) { +                        Log.d(TAG, "Got a change event for an unknown property: " +                                + property + " => " + properties.getString(property, "")); +                    } +            }          } -        // The memory visibility is powered by the volatile field, mEnabled. -        mEnabled = properties.getBoolean(SETTINGS_ENABLED_KEY, DEFAULT_ENABLED);      }      @VisibleForTesting diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java index 06e69f2d9859..fd435d0595c2 100644 --- a/core/java/com/android/internal/view/FloatingActionMode.java +++ b/core/java/com/android/internal/view/FloatingActionMode.java @@ -222,6 +222,7 @@ public final class FloatingActionMode extends ActionMode {      private boolean isContentRectWithinBounds() {          mContext.getDisplayNoVerify().getRealSize(mDisplaySize);          mScreenRect.set(0, 0, mDisplaySize.x, mDisplaySize.y); +        mScreenRect.offset(mRootViewPositionOnScreen[0], mRootViewPositionOnScreen[1]);          return intersectsClosed(mContentRectOnScreen, mScreenRect)              && intersectsClosed(mContentRectOnScreen, mViewRectOnScreen); diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto index 6c936801de18..473270229bdb 100644 --- a/core/proto/android/providers/settings/secure.proto +++ b/core/proto/android/providers/settings/secure.proto @@ -98,6 +98,7 @@ message SecureSettingsProto {          // Settings for font scaling          optional SettingProto accessibility_font_scaling_has_been_changed = 51 [ (android.privacy).dest = DEST_AUTOMATIC ];          optional SettingProto accessibility_force_invert_color_enabled = 52 [ (android.privacy).dest = DEST_AUTOMATIC ]; +        optional SettingProto accessibility_magnification_gesture = 53 [ (android.privacy).dest = DEST_AUTOMATIC ];      }      optional Accessibility accessibility = 2; diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml index 8b6c90141bb7..27f8138ac5e3 100644 --- a/core/res/res/layout/autofill_save.xml +++ b/core/res/res/layout/autofill_save.xml @@ -60,10 +60,11 @@                      android:gravity="center"                      android:textAppearance="@style/AutofillSaveUiTitle">                  </TextView> -                <LinearLayout +                <FrameLayout                      android:id="@+id/autofill_save_custom_subtitle"                      android:layout_width="match_parent"                      android:layout_height="wrap_content" +                    android:minHeight="0dp"                      android:visibility="gone"/>              </LinearLayout> diff --git a/core/res/res/values-watch/dimens_material.xml b/core/res/res/values-watch/dimens_material.xml index 2ab2d91058e2..8becb0880f97 100644 --- a/core/res/res/values-watch/dimens_material.xml +++ b/core/res/res/values-watch/dimens_material.xml @@ -47,11 +47,12 @@      <dimen name="progress_bar_height">24dp</dimen>      <!-- Progress bar message dimens --> -    <dimen name="message_progress_dialog_text_size">18sp</dimen> +    <dimen name="message_progress_dialog_text_size">14sp</dimen>      <dimen name="message_progress_dialog_bottom_padding">80px</dimen>      <dimen name="message_progress_dialog_top_padding">0dp</dimen>      <dimen name="message_progress_dialog_start_padding">0dp</dimen>      <dimen name="message_progress_dialog_end_padding">0dp</dimen> +    <item name="message_progress_dialog_letter_spacing" format="float" type="dimen">0.021</item>      <!-- fallback for screen percentage widths -->      <dimen name="screen_percentage_05">0dp</dimen> diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml index 8698e86ba5f9..f3e412dc948e 100644 --- a/core/res/res/values-watch/styles_material.xml +++ b/core/res/res/values-watch/styles_material.xml @@ -100,7 +100,9 @@ please see styles_device_defaults.xml.      <style name="ProgressDialogMessage">          <item name="android:textAlignment">center</item> -        <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item> +        <item name="android:fontFamily">google-sans-text</item> +        <item name="android:letterSpacing">@dimen/message_progress_dialog_letter_spacing</item> +        <item name="textColor">?attr/textColorPrimary</item>          <item name="textSize">@dimen/message_progress_dialog_text_size</item>          <item name="paddingBottom">@dimen/message_progress_dialog_bottom_padding</item>          <item name="paddingEnd">@dimen/message_progress_dialog_end_padding</item> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 3c296de780a2..7ef81abb8f0d 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1151,6 +1151,14 @@      <!-- Allows activities to be launched on a long press on power during device setup. -->      <bool name="config_allowStartActivityForLongPressOnPowerInSetup">false</bool> +    <!-- Control the behavior when the user short presses the settings button. +            0 - Nothing +            1 - Launch notification panel +         This needs to match the constants in +         com/android/server/policy/PhoneWindowManager.java +    --> +    <integer name="config_shortPressOnSettingsBehavior">0</integer> +      <!-- Control the behavior when the user short presses the power button.              0 - Nothing              1 - Go to sleep (doze) @@ -5394,6 +5402,7 @@          <item>1,1,1.0,.4,1</item>          <item>1,1,1.0,.15,15</item>          <item>0,0,0.7,0,1</item> +        <item>0,0,0.83333,0,1</item>      </string-array>      <!-- The integer index of the selected option in config_udfps_touch_detection_options --> diff --git a/core/res/res/values/config_device_idle.xml b/core/res/res/values/config_device_idle.xml index 98a5ff9c4a79..bc9ca3decec3 100644 --- a/core/res/res/values/config_device_idle.xml +++ b/core/res/res/values/config_device_idle.xml @@ -42,6 +42,15 @@      <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_FACTOR -->      <item name="device_idle_light_idle_factor" format="float" type="integer">2.0</item> +    <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_INCREASE_LINEARLY --> +    <bool name="device_idle_light_idle_increase_linearly">false</bool> + +    <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS --> +    <integer name="device_idle_light_idle_linear_increase_factor_ms">300000</integer> + +    <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_FLEX_LINEAR_INCREASE_FACTOR_MS --> +    <integer name="device_idle_light_idle_flex_linear_increase_factor_ms">60000</integer> +      <!-- Default for DeviceIdleController.Constants.LIGHT_MAX_IDLE_TIMEOUT -->      <integer name="device_idle_light_max_idle_to_ms">900000</integer> diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml index 71d696ea4554..3ba150bcdd44 100644 --- a/core/res/res/values/config_telephony.xml +++ b/core/res/res/values/config_telephony.xml @@ -73,7 +73,7 @@           CarrierConfigManager#KEY_AUTO_DATA_SWITCH_RAT_SIGNAL_SCORE_STRING_ARRAY.           If 0, the device always switch to the higher score SIM.           If < 0, the network type and signal strength based auto switch is disabled. --> -    <integer name="auto_data_switch_score_tolerance">-1</integer> +    <integer name="auto_data_switch_score_tolerance">4000</integer>      <java-symbol type="integer" name="auto_data_switch_score_tolerance" />      <!-- Boolean indicating whether the Iwlan data service supports persistence of iwlan ipsec @@ -219,4 +219,8 @@      <bool name="telephony_analytics_switch">true</bool>      <java-symbol type="bool" name="telephony_analytics_switch" /> +    <!-- Whether to enable modem on boot if behavior is not defined --> +    <bool name="config_enable_cellular_on_boot_default">true</bool> +    <java-symbol type="bool" name="config_enable_cellular_on_boot_default" /> +  </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 193f3adeedea..643f4b148d74 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1816,6 +1816,7 @@    <java-symbol type="integer" name="config_lidNavigationAccessibility" />    <java-symbol type="integer" name="config_lidOpenRotation" />    <java-symbol type="integer" name="config_longPressOnHomeBehavior" /> +  <java-symbol type="integer" name="config_shortPressOnSettingsBehavior" />    <java-symbol type="layout" name="global_actions" />    <java-symbol type="layout" name="global_actions_item" />    <java-symbol type="layout" name="global_actions_silent_mode" /> @@ -4537,7 +4538,10 @@    <java-symbol type="integer" name="device_idle_light_idle_to_init_flex_ms" />    <java-symbol type="integer" name="device_idle_light_idle_to_max_flex_ms" />    <java-symbol type="integer" name="device_idle_light_idle_factor" /> +  <java-symbol type="bool" name="device_idle_light_idle_increase_linearly" />    <java-symbol type="integer" name="device_idle_light_max_idle_to_ms" /> +  <java-symbol type="integer" name="device_idle_light_idle_linear_increase_factor_ms" /> +  <java-symbol type="integer" name="device_idle_light_idle_flex_linear_increase_factor_ms" />    <java-symbol type="integer" name="device_idle_light_idle_maintenance_min_budget_ms" />    <java-symbol type="integer" name="device_idle_light_idle_maintenance_max_budget_ms" />    <java-symbol type="integer" name="device_idle_min_light_maintenance_time_ms" /> diff --git a/core/tests/BroadcastRadioTests/Android.bp b/core/tests/BroadcastRadioTests/Android.bp index 85d54e02d318..054d10c336e6 100644 --- a/core/tests/BroadcastRadioTests/Android.bp +++ b/core/tests/BroadcastRadioTests/Android.bp @@ -38,7 +38,7 @@ android_test {      static_libs: [          "services.core",          "androidx.test.rules", -        "truth-prebuilt", +        "truth",          "testng",          "mockito-target-extended",      ], diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java index a1952282dd0b..824f5910f96c 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java @@ -16,20 +16,20 @@  package com.android.server.broadcastradio.aidl; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.after; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;  import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.timeout; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;  import static org.junit.Assert.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when;  import android.app.compat.CompatChanges;  import android.graphics.Bitmap; @@ -81,8 +81,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {      private static final int USER_ID_1 = 11;      private static final int USER_ID_2 = 12; -    private static final VerificationWithTimeout CALLBACK_TIMEOUT = -            timeout(/* millis= */ 200); +    private static final int CALLBACK_TIMEOUT_MS = 200; +    private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(CALLBACK_TIMEOUT_MS);      private static final int SIGNAL_QUALITY = 90;      private static final long AM_FM_FREQUENCY_SPACING = 500;      private static final long[] AM_FM_FREQUENCY_LIST = {97_500, 98_100, 99_100}; @@ -166,12 +166,12 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {      @Before      public void setup() throws Exception { -        when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1);          doReturn(true).when(() -> CompatChanges.isChangeEnabled(                  eq(ConversionUtils.RADIO_U_VERSION_REQUIRED), anyInt())); +        doReturn(USER_ID_1).when(mUserHandleMock).getIdentifier(); +        doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());          doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());          doReturn(USER_ID_1).when(() -> RadioServiceUserController.getCurrentUser()); -        doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());          mRadioModule = new RadioModule(mBroadcastRadioMock,                  AidlTestUtils.makeDefaultModuleProperties()); @@ -222,7 +222,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {              return Result.OK;          }).when(mBroadcastRadioMock).seek(anyBoolean(), anyBoolean()); -        when(mBroadcastRadioMock.getImage(anyInt())).thenReturn(null); +        doReturn(null).when(mBroadcastRadioMock).getImage(anyInt());          doAnswer(invocation -> {              int configFlag = (int) invocation.getArguments()[0]; @@ -275,7 +275,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {          mTunerSessions[0].setConfiguration(FM_BAND_CONFIG); -        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) +        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))                  .onConfigurationChanged(FM_BAND_CONFIG);      } @@ -446,26 +446,11 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {          mTunerSessions[0].tune(initialSel); -        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) +        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))                  .onCurrentProgramInfoChanged(tuneInfo);      }      @Test -    public void tune_forSystemUser() throws Exception { -        when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM); -        doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle()); -        doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); -        ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); -        RadioManager.ProgramInfo tuneInfo = -                AidlTestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY); -        openAidlClients(/* numClients= */ 1); - -        mTunerSessions[0].tune(initialSel); - -        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo); -    } - -    @Test      public void tune_withUnknownErrorFromHal_fails() throws Exception {          openAidlClients(/* numClients= */ 1);          ProgramSelector sel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); @@ -525,7 +510,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {          mTunerSessions[0].step(/* directionDown= */ true, /* skipSubChannel= */ false); -        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) +        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))                  .onCurrentProgramInfoChanged(any());      } @@ -604,7 +589,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {          mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false); -        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) +        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))                  .onCurrentProgramInfoChanged(seekUpInfo);      } @@ -638,6 +623,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {          openAidlClients(/* numClients= */ 1);          ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);          mTunerSessions[0].tune(initialSel); +        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(any());          doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());          mTunerSessions[0].cancel(); @@ -686,8 +672,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {      public void getImage_whenHalThrowsException_fails() throws Exception {          openAidlClients(/* numClients= */ 1);          String exceptionMessage = "HAL service died."; -        when(mBroadcastRadioMock.getImage(anyInt())) -                .thenThrow(new RemoteException(exceptionMessage)); +        doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock) +                .getImage(anyInt());          RuntimeException thrown = assertThrows(RuntimeException.class, () -> {              mTunerSessions[0].getImage(/* id= */ 1); @@ -713,7 +699,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {          mTunerSessions[0].startBackgroundScan(); -        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onBackgroundScanComplete(); +        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0)) +                .onBackgroundScanComplete();      }      @Test @@ -905,7 +892,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {          mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,                  /* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>())); -        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onProgramListUpdated(any()); +        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0)) +                .onProgramListUpdated(any());      }      @Test @@ -1160,8 +1148,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {          Map<String, String> parametersSet = Map.of("mockParam1", "mockValue1",                  "mockParam2", "mockValue2");          String exceptionMessage = "HAL service died."; -        when(mBroadcastRadioMock.setParameters(any())) -                .thenThrow(new RemoteException(exceptionMessage)); +        doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock) +                .setParameters(any());          RuntimeException thrown = assertThrows(RuntimeException.class, () -> {              mTunerSessions[0].setParameters(parametersSet); @@ -1186,8 +1174,8 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {          openAidlClients(/* numClients= */ 1);          List<String> parameterKeys = List.of("mockKey1", "mockKey2");          String exceptionMessage = "HAL service died."; -        when(mBroadcastRadioMock.getParameters(any())) -                .thenThrow(new RemoteException(exceptionMessage)); +        doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock) +                .getParameters(any());          RuntimeException thrown = assertThrows(RuntimeException.class, () -> {              mTunerSessions[0].getParameters(parameterKeys); @@ -1198,7 +1186,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {      }      @Test -    public void onCurrentProgramInfoChanged_withNoncurrentUser_doesNotInvokeCallback() +    public void onCurrentProgramInfoChanged_withNonCurrentUser_doesNotInvokeCallback()              throws Exception {          openAidlClients(1);          doReturn(USER_ID_2).when(() -> RadioServiceUserController.getCurrentUser()); @@ -1206,7 +1194,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {          mHalTunerCallback.onCurrentProgramInfoChanged(AidlTestUtils.makeHalProgramInfo(                  AidlTestUtils.makeHalFmSelector(AM_FM_FREQUENCY_LIST[1]), SIGNAL_QUALITY)); -        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) +        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))                  .onCurrentProgramInfoChanged(any());      } diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java index fac9eaafe94c..3b9d7ba5de3e 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java @@ -16,22 +16,22 @@  package com.android.server.broadcastradio.hal2; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.after; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;  import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.timeout; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;  import static com.google.common.truth.Truth.assertWithMessage;  import static org.junit.Assert.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when;  import android.graphics.Bitmap;  import android.hardware.broadcastradio.V2_0.Constants; @@ -78,8 +78,8 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {      private static final int USER_ID_1 = 11;      private static final int USER_ID_2 = 12; -    private static final VerificationWithTimeout CALLBACK_TIMEOUT = -            timeout(/* millis= */ 200); +    private static final int CALLBACK_TIMEOUT_MS = 200; +    private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(CALLBACK_TIMEOUT_MS);      private static final int SIGNAL_QUALITY = 1;      private static final long AM_FM_FREQUENCY_SPACING = 500;      private static final long[] AM_FM_FREQUENCY_LIST = {97_500, 98_100, 99_100}; @@ -113,7 +113,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {      @Before      public void setup() throws Exception { -        when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1); +        doReturn(USER_ID_1).when(mUserHandleMock).getIdentifier();          doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());          doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());          doReturn(USER_ID_1).when(() -> RadioServiceUserController.getCurrentUser()); @@ -170,7 +170,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {              return Result.OK;          }).when(mHalTunerSessionMock).scan(anyBoolean(), anyBoolean()); -        when(mBroadcastRadioMock.getImage(anyInt())).thenReturn(new ArrayList<Byte>(0)); +        doReturn(new ArrayList<Byte>(0)).when(mBroadcastRadioMock).getImage(anyInt());          doAnswer(invocation -> {              int configFlag = (int) invocation.getArguments()[0]; @@ -227,7 +227,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {          mTunerSessions[0].setConfiguration(FM_BAND_CONFIG); -        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) +        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))                  .onConfigurationChanged(FM_BAND_CONFIG);      } @@ -379,7 +379,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {          mTunerSessions[0].tune(initialSel); -        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) +        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))                  .onCurrentProgramInfoChanged(tuneInfo);      } @@ -398,20 +398,6 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {      }      @Test -    public void tune_forSystemUser() throws Exception { -        when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM); -        doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle()); -        doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); -        ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); -        RadioManager.ProgramInfo tuneInfo = TestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY); -        openAidlClients(/* numClients= */ 1); - -        mTunerSessions[0].tune(initialSel); - -        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo); -    } - -    @Test      public void step_withDirectionUp() throws Exception {          long initFreq = AM_FM_FREQUENCY_LIST[1];          ProgramSelector initialSel = TestUtils.makeFmSelector(initFreq); @@ -455,7 +441,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {          mTunerSessions[0].step(/* directionDown= */ true, /* skipSubChannel= */ false); -        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) +        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))                  .onCurrentProgramInfoChanged(any());      } @@ -533,7 +519,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {          mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false); -        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) +        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))                  .onCurrentProgramInfoChanged(seekUpInfo);      } @@ -563,18 +549,6 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {      }      @Test -    public void cancel_forNonCurrentUser() throws Exception { -        openAidlClients(/* numClients= */ 1); -        ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); -        mTunerSessions[0].tune(initialSel); -        doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); - -        mTunerSessions[0].cancel(); - -        verify(mHalTunerSessionMock, never()).cancel(); -    } - -    @Test      public void cancel_forNonCurrentUser_doesNotCancel() throws Exception {          openAidlClients(/* numClients= */ 1);          ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); @@ -627,8 +601,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {      public void getImage_whenHalThrowsException_fails() throws Exception {          openAidlClients(/* numClients= */ 1);          String exceptionMessage = "HAL service died."; -        when(mBroadcastRadioMock.getImage(anyInt())) -                .thenThrow(new RemoteException(exceptionMessage)); +        doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock).getImage(anyInt());          RuntimeException thrown = assertThrows(RuntimeException.class, () -> {              mTunerSessions[0].getImage(/* id= */ 1); @@ -654,7 +627,8 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {          mTunerSessions[0].startBackgroundScan(); -        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onBackgroundScanComplete(); +        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0)) +                .onBackgroundScanComplete();      }      @Test @@ -845,8 +819,8 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {          Map<String, String> parametersSet = Map.of("mockParam1", "mockValue1",                  "mockParam2", "mockValue2");          String exceptionMessage = "HAL service died."; -        when(mHalTunerSessionMock.setParameters(any())) -                .thenThrow(new RemoteException(exceptionMessage)); +        doThrow(new RemoteException(exceptionMessage)).when(mHalTunerSessionMock) +                .setParameters(any());          RuntimeException thrown = assertThrows(RuntimeException.class, () -> {              mTunerSessions[0].setParameters(parametersSet); @@ -871,8 +845,8 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {          openAidlClients(/* numClients= */ 1);          List<String> parameterKeys = List.of("mockKey1", "mockKey2");          String exceptionMessage = "HAL service died."; -        when(mHalTunerSessionMock.getParameters(any())) -                .thenThrow(new RemoteException(exceptionMessage)); +        doThrow(new RemoteException(exceptionMessage)).when(mHalTunerSessionMock) +                .getParameters(any());          RuntimeException thrown = assertThrows(RuntimeException.class, () -> {              mTunerSessions[0].getParameters(parameterKeys); @@ -883,7 +857,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {      }      @Test -    public void onCurrentProgramInfoChanged_withNoncurrentUser_doesNotInvokeCallback() +    public void onCurrentProgramInfoChanged_withNonCurrentUser_doesNotInvokeCallback()              throws Exception {          openAidlClients(1);          doReturn(USER_ID_2).when(() -> RadioServiceUserController.getCurrentUser()); @@ -891,7 +865,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {          mHalTunerCallback.onCurrentProgramInfoChanged(TestUtils.makeHalProgramInfo(                  TestUtils.makeHalFmSelector(/* freq= */ 97300), SIGNAL_QUALITY)); -        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) +        verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).times(0))                  .onCurrentProgramInfoChanged(any());      } diff --git a/core/tests/GameManagerTests/Android.bp b/core/tests/GameManagerTests/Android.bp index 8c5d6d5a76a1..0e3bc6562edb 100644 --- a/core/tests/GameManagerTests/Android.bp +++ b/core/tests/GameManagerTests/Android.bp @@ -30,7 +30,7 @@ android_test {          "frameworks-base-testutils",          "junit",          "platform-test-annotations", -        "truth-prebuilt", +        "truth",      ],      libs: ["android.test.runner"],      platform_apis: true, diff --git a/core/tests/PackageInstallerSessions/Android.bp b/core/tests/PackageInstallerSessions/Android.bp index 6f2366e32574..b631df1fcf57 100644 --- a/core/tests/PackageInstallerSessions/Android.bp +++ b/core/tests/PackageInstallerSessions/Android.bp @@ -35,7 +35,7 @@ android_test {          "frameworks-base-testutils",          "platform-test-annotations",          "testng", -        "truth-prebuilt", +        "truth",      ],      libs: [ diff --git a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/Android.bp b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/Android.bp index 52608351775c..1fb5f2c0789b 100644 --- a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/Android.bp +++ b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/Android.bp @@ -18,7 +18,7 @@ android_test {          "platform-test-annotations",          "platformprotosnano",          "statsdprotolite", -        "truth-prebuilt", +        "truth",      ],      libs: ["android.test.runner"], diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp index 2b34ee2646f3..7c1ac487bfdb 100644 --- a/core/tests/bugreports/Android.bp +++ b/core/tests/bugreports/Android.bp @@ -32,7 +32,7 @@ android_test {      static_libs: [          "androidx.test.rules",          "androidx.test.uiautomator_uiautomator", -        "truth-prebuilt", +        "truth",      ],      test_suites: ["general-tests"],      sdk_version: "test_current", diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 04622fda75df..81dab0833af1 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -58,7 +58,7 @@ android_test {          "androidx.test.uiautomator_uiautomator",          "platform-test-annotations",          "platform-compat-test-rules", -        "truth-prebuilt", +        "truth",          "print-test-util-lib",          "testng",          "servicestests-utils", @@ -149,7 +149,7 @@ android_library {          "androidx.test.runner",          "androidx.test.rules",          "mockito-target-minus-junit4", -        "truth-prebuilt", +        "truth",      ],      libs: [ diff --git a/core/tests/hdmitests/Android.bp b/core/tests/hdmitests/Android.bp index 3d04937c9195..5f6eaf96a846 100644 --- a/core/tests/hdmitests/Android.bp +++ b/core/tests/hdmitests/Android.bp @@ -30,7 +30,7 @@ android_test {          "frameworks-base-testutils",          "guava-android-testlib",          "platform-test-annotations", -        "truth-prebuilt", +        "truth",      ],      libs: ["android.test.runner"],      platform_apis: true, diff --git a/core/tests/mockingcoretests/Android.bp b/core/tests/mockingcoretests/Android.bp index fde7c08715c7..2d778b1218d2 100644 --- a/core/tests/mockingcoretests/Android.bp +++ b/core/tests/mockingcoretests/Android.bp @@ -38,7 +38,7 @@ android_test {          "androidx.test.ext.junit",          "mockito-target-extended-minus-junit4",          "platform-test-annotations", -        "truth-prebuilt", +        "truth",          "testables",      ], diff --git a/core/tests/nfctests/Android.bp b/core/tests/nfctests/Android.bp index c74600bbab22..f81be494ad18 100644 --- a/core/tests/nfctests/Android.bp +++ b/core/tests/nfctests/Android.bp @@ -27,7 +27,7 @@ android_test {          "androidx.test.ext.junit",          "androidx.test.rules",          "mockito-target-minus-junit4", -        "truth-prebuilt", +        "truth",      ],      libs: [          "android.test.runner", diff --git a/core/tests/overlaytests/device_self_targeting/Android.bp b/core/tests/overlaytests/device_self_targeting/Android.bp index 063c5694ab5b..931eac515e31 100644 --- a/core/tests/overlaytests/device_self_targeting/Android.bp +++ b/core/tests/overlaytests/device_self_targeting/Android.bp @@ -30,7 +30,7 @@ android_test {          "androidx.test.runner",          "androidx.test.ext.junit",          "mockito-target-minus-junit4", -        "truth-prebuilt", +        "truth",      ],      optimize: { diff --git a/core/tests/packagemonitortests/Android.bp b/core/tests/packagemonitortests/Android.bp index 7b5d7dff0a85..b08850e90d28 100644 --- a/core/tests/packagemonitortests/Android.bp +++ b/core/tests/packagemonitortests/Android.bp @@ -32,7 +32,7 @@ android_test {          "compatibility-device-util-axt",          "frameworks-base-testutils",          "mockito-target-minus-junit4", -        "truth-prebuilt", +        "truth",      ],      libs: ["android.test.runner"],      platform_apis: true, diff --git a/core/tests/privacytests/Android.bp b/core/tests/privacytests/Android.bp index bc3dd810be8c..4e24cd5d91cb 100644 --- a/core/tests/privacytests/Android.bp +++ b/core/tests/privacytests/Android.bp @@ -14,7 +14,7 @@ android_test {          "junit",          "rappor-tests",          "androidx.test.rules", -        "truth-prebuilt", +        "truth",      ],      libs: ["android.test.runner"],      platform_apis: true, diff --git a/core/tests/utiltests/Android.bp b/core/tests/utiltests/Android.bp index 3798da592cd5..580e73c331a1 100644 --- a/core/tests/utiltests/Android.bp +++ b/core/tests/utiltests/Android.bp @@ -33,7 +33,7 @@ android_test {          "frameworks-base-testutils",          "mockito-target-minus-junit4",          "androidx.test.ext.junit", -        "truth-prebuilt", +        "truth",          "servicestests-utils",      ], diff --git a/core/tests/vibrator/Android.bp b/core/tests/vibrator/Android.bp index 829409a36986..09608e9bf507 100644 --- a/core/tests/vibrator/Android.bp +++ b/core/tests/vibrator/Android.bp @@ -18,7 +18,7 @@ android_test {          "androidx.test.runner",          "androidx.test.rules",          "mockito-target-minus-junit4", -        "truth-prebuilt", +        "truth",          "testng",      ], diff --git a/errorprone/Android.bp b/errorprone/Android.bp index ad08026622d1..c1d2235e3324 100644 --- a/errorprone/Android.bp +++ b/errorprone/Android.bp @@ -41,7 +41,7 @@ java_test_host {      java_resource_dirs: ["tests/res"],      java_resources: [":error_prone_android_framework_testdata"],      static_libs: [ -        "truth-prebuilt", +        "truth",          "kxml2-2.3.0",          "compile-testing-prebuilt",          "error_prone_android_framework_lib", diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java index c55a781ce2a4..11278e84ceaa 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java @@ -43,6 +43,7 @@ import java.security.interfaces.ECPublicKey;  import java.security.interfaces.RSAPublicKey;  import javax.crypto.Cipher; +import javax.crypto.KeyAgreement;  import javax.crypto.Mac;  import javax.crypto.SecretKey; @@ -181,6 +182,8 @@ public class AndroidKeyStoreProvider extends Provider {              spi = ((Mac) cryptoPrimitive).getCurrentSpi();          } else if (cryptoPrimitive instanceof Cipher) {              spi = ((Cipher) cryptoPrimitive).getCurrentSpi(); +        } else if (cryptoPrimitive instanceof KeyAgreement) { +            spi = ((KeyAgreement) cryptoPrimitive).getCurrentSpi();          } else {              throw new IllegalArgumentException("Unsupported crypto primitive: " + cryptoPrimitive                      + ". Supported: Signature, Mac, Cipher"); diff --git a/libs/WindowManager/Jetpack/tests/unittest/Android.bp b/libs/WindowManager/Jetpack/tests/unittest/Android.bp index b6e743a2b7e1..ed2ff2de245b 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/Android.bp +++ b/libs/WindowManager/Jetpack/tests/unittest/Android.bp @@ -37,7 +37,7 @@ android_test {          "androidx.test.rules",          "androidx.test.ext.junit",          "mockito-target-extended-minus-junit4", -        "truth-prebuilt", +        "truth",          "testables",          "platform-test-annotations",      ], diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java index f1ee8fa38485..a67821b7e819 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java @@ -318,7 +318,7 @@ public class BadgedImageView extends ConstraintLayout {      /**       * Animates the dot to the given scale, running the optional callback when the animation ends.       */ -    private void animateDotScale(float toScale, @Nullable Runnable after) { +    public void animateDotScale(float toScale, @Nullable Runnable after) {          mDotIsAnimating = true;          // Don't restart the animation if we're already animating to the given value. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt index df19757203eb..dc099d9abda4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt @@ -27,6 +27,7 @@ import android.graphics.drawable.ColorDrawable  import android.graphics.drawable.InsetDrawable  import android.util.PathParser  import android.view.LayoutInflater +import android.view.View.VISIBLE  import android.widget.FrameLayout  import com.android.launcher3.icons.BubbleIconFactory  import com.android.wm.shell.R @@ -156,7 +157,9 @@ class BubbleOverflow(private val context: Context, private val positioner: Bubbl      fun setShowDot(show: Boolean) {          showDot = show -        overflowBtn?.updateDotVisibility(true /* animate */) +        if (overflowBtn?.visibility == VISIBLE) { +            overflowBtn?.updateDotVisibility(true /* animate */) +        }      }      /** Creates the expanded view for bubbles showing in the stack view. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index c124b532b89d..2241c343a208 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -1864,6 +1864,14 @@ public class BubbleStackView extends FrameLayout                  : GONE);      } +    private void updateOverflowDotVisibility(boolean expanding) { +        if (mBubbleOverflow.showDot()) { +            mBubbleOverflow.getIconView().animateDotScale(expanding ? 1 : 0f, () -> { +                mBubbleOverflow.setVisible(expanding ? VISIBLE : GONE); +            }); +        } +    } +      // via BubbleData.Listener      void updateBubble(Bubble bubble) {          animateInFlyoutForBubble(bubble); @@ -2274,6 +2282,7 @@ public class BubbleStackView extends FrameLayout              if (mIsExpanded && mExpandedBubble.getExpandedView() != null) {                  maybeShowManageEdu();              } +            updateOverflowDotVisibility(true /* expanding */);          } /* after */);          int index;          if (mExpandedBubble != null && BubbleOverflow.KEY.equals(mExpandedBubble.getKey())) { @@ -2405,11 +2414,15 @@ public class BubbleStackView extends FrameLayout          // since we're about to animate collapsed.          mExpandedAnimationController.notifyPreparingToCollapse(); +        updateOverflowDotVisibility(false /* expanding */);          final Runnable collapseBackToStack = () -> mExpandedAnimationController.collapseBackToStack(                  mStackAnimationController                          .getStackPositionAlongNearestHorizontalEdge()                  /* collapseTo */, -                () -> mBubbleContainer.setActiveController(mStackAnimationController)); +                () -> { +                    mBubbleContainer.setActiveController(mStackAnimationController); +                    updateOverflowVisibility(); +                });          final Runnable after = () -> {              final BubbleViewProvider previouslySelected = mExpandedBubble; @@ -2424,7 +2437,6 @@ public class BubbleStackView extends FrameLayout                  Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(),                          mExpandedBubble));              } -            updateOverflowVisibility();              updateZOrder();              updateBadges(true /* setBadgeForCollapsedStack */);              afterExpandedViewAnimation(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java index 4d7042bbb3d2..738c94e82a95 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java @@ -34,6 +34,8 @@ import androidx.dynamicanimation.animation.SpringForce;  import com.android.wm.shell.R;  import com.android.wm.shell.animation.Interpolators;  import com.android.wm.shell.animation.PhysicsAnimator; +import com.android.wm.shell.bubbles.BadgedImageView; +import com.android.wm.shell.bubbles.BubbleOverflow;  import com.android.wm.shell.bubbles.BubblePositioner;  import com.android.wm.shell.bubbles.BubbleStackView;  import com.android.wm.shell.common.magnetictarget.MagnetizedObject; @@ -63,6 +65,12 @@ public class ExpandedAnimationController      /** Damping ratio for expand/collapse spring. */      private static final float DAMPING_RATIO_MEDIUM_LOW_BOUNCY = 0.65f; +    /** +     * Damping ratio for the overflow bubble spring; this is less bouncy so it doesn't bounce behind +     * the top bubble when it goes to disappear. +     */ +    private static final float DAMPING_RATIO_OVERFLOW_BOUNCY = 0.90f; +      /** Stiffness for the expand/collapse path-following animation. */      private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS = 400; @@ -274,9 +282,14 @@ public class ExpandedAnimationController                  // of the screen where the bubble will be stacked.                  path.lineTo(stackedX, p.y); +                // The overflow should animate to the collapse point, so 0 offset. +                final boolean isOverflow = bubble instanceof BadgedImageView +                        && BubbleOverflow.KEY.equals(((BadgedImageView) bubble).getKey()); +                final float offsetY = isOverflow +                        ? 0 +                        : Math.min(index, NUM_VISIBLE_WHEN_RESTING - 1) * mStackOffsetPx;                  // Then, draw a line down to the stack position. -                path.lineTo(stackedX, mCollapsePoint.y -                        + Math.min(index, NUM_VISIBLE_WHEN_RESTING - 1) * mStackOffsetPx); +                path.lineTo(stackedX, mCollapsePoint.y + offsetY);              }              // The lead bubble should be the bubble with the longest distance to travel when we're @@ -505,8 +518,12 @@ public class ExpandedAnimationController      @Override      SpringForce getSpringForce(DynamicAnimation.ViewProperty property, View view) { +        boolean isOverflow = (view instanceof BadgedImageView) +                && BubbleOverflow.KEY.equals(((BadgedImageView) view).getKey());          return new SpringForce() -                .setDampingRatio(DAMPING_RATIO_MEDIUM_LOW_BOUNCY) +                .setDampingRatio(isOverflow +                        ? DAMPING_RATIO_OVERFLOW_BOUNCY +                        : DAMPING_RATIO_MEDIUM_LOW_BOUNCY)                  .setStiffness(SpringForce.STIFFNESS_LOW);      } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java index 5e42782431fd..e9344ffcce0c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java @@ -203,7 +203,7 @@ public class SystemWindows {                      + "SystemWindow:" + view);              return null;          } -        return root.getFocusGrantToken(); +        return root.getInputTransferToken();      }      private class PerDisplay { 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 11aa054676cb..5dfba5e7ff1d 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 @@ -494,13 +494,14 @@ public abstract class WMShellModule {              ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler,              @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,              LaunchAdjacentController launchAdjacentController, +            RecentsTransitionHandler recentsTransitionHandler,              @ShellMainThread ShellExecutor mainExecutor      ) {          return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController,                  displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer,                  transitions, enterDesktopTransitionHandler, exitDesktopTransitionHandler,                  toggleResizeDesktopTaskTransitionHandler, desktopModeTaskRepository, -                launchAdjacentController, mainExecutor); +                launchAdjacentController, recentsTransitionHandler, mainExecutor);      }      @WMSingleton 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 09ba4f79326e..412a5b5a6997 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 @@ -60,6 +60,8 @@ import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP  import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener  import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.TO_DESKTOP_INDICATOR  import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE +import com.android.wm.shell.recents.RecentsTransitionHandler +import com.android.wm.shell.recents.RecentsTransitionStateListener  import com.android.wm.shell.splitscreen.SplitScreenController  import com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_ENTER_DESKTOP  import com.android.wm.shell.sysui.ShellCommandHandler @@ -68,7 +70,6 @@ import com.android.wm.shell.sysui.ShellInit  import com.android.wm.shell.sysui.ShellSharedConstants  import com.android.wm.shell.transition.OneShotRemoteHandler  import com.android.wm.shell.transition.Transitions -import com.android.wm.shell.transition.Transitions.TransitionHandler  import com.android.wm.shell.util.KtProtoLog  import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration  import com.android.wm.shell.windowdecor.MoveToDesktopAnimator @@ -93,6 +94,7 @@ class DesktopTasksController(          ToggleResizeDesktopTaskTransitionHandler,          private val desktopModeTaskRepository: DesktopModeTaskRepository,          private val launchAdjacentController: LaunchAdjacentController, +        private val recentsTransitionHandler: RecentsTransitionHandler,          @ShellMainThread private val mainExecutor: ShellExecutor  ) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler { @@ -119,6 +121,8 @@ class DesktopTasksController(              com.android.wm.shell.R.dimen.desktop_mode_transition_area_width          ) +    private var recentsAnimationRunning = false +      // This is public to avoid cyclic dependency; it is set by SplitScreenController      lateinit var splitScreenController: SplitScreenController @@ -139,6 +143,19 @@ class DesktopTasksController(          )          transitions.addHandler(this)          desktopModeTaskRepository.addVisibleTasksListener(taskVisibilityListener, mainExecutor) + +        recentsTransitionHandler.addTransitionStateListener( +            object : RecentsTransitionStateListener { +                override fun onAnimationStateChanged(running: Boolean) { +                    KtProtoLog.v( +                        WM_SHELL_DESKTOP_MODE, +                        "DesktopTasksController: recents animation state changed running=%b", +                        running +                    ) +                    recentsAnimationRunning = running +                } +            } +        )      }      /** Show all tasks, that are part of the desktop, on top of launcher */ @@ -644,6 +661,10 @@ class DesktopTasksController(          val triggerTask = request.triggerTask          val shouldHandleRequest =              when { +                recentsAnimationRunning -> { +                    reason = "recents animation is running" +                    false +                }                  // Only handle open or to front transitions                  request.type != TRANSIT_OPEN && request.type != TRANSIT_TO_FRONT -> {                      reason = "transition type not handled (${request.type})" diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java index ead2f9cbd1ad..d31476c63890 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java @@ -54,6 +54,7 @@ import android.window.WindowContainerToken;  import android.window.WindowContainerTransaction;  import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.IResultReceiver;  import com.android.internal.protolog.common.ProtoLog;  import com.android.wm.shell.common.ShellExecutor;  import com.android.wm.shell.protolog.ShellProtoLogGroup; @@ -279,7 +280,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {              mDeathHandler = () -> {                  ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,                          "[%d] RecentsController.DeathRecipient: binder died", mInstanceId); -                finish(mWillFinishToHome, false /* leaveHint */); +                finish(mWillFinishToHome, false /* leaveHint */, null /* finishCb */);              };              try {                  mListener.asBinder().linkToDeath(mDeathHandler, 0 /* flags */); @@ -313,7 +314,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {                  }              }              if (mFinishCB != null) { -                finishInner(toHome, false /* userLeave */); +                finishInner(toHome, false /* userLeave */, null /* finishCb */);              } else {                  cleanUp();              } @@ -670,7 +671,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {                  // now and let it do its animation (since recents is going to be occluded).                  sendCancelWithSnapshots();                  mExecutor.executeDelayed( -                        () -> finishInner(true /* toHome */, false /* userLeaveHint */), 0); +                        () -> finishInner(true /* toHome */, false /* userLeaveHint */, +                                null /* finishCb */), 0);                  return;              }              if (recentsOpening != null) { @@ -899,11 +901,12 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {          @Override          @SuppressLint("NewApi") -        public void finish(boolean toHome, boolean sendUserLeaveHint) { -            mExecutor.execute(() -> finishInner(toHome, sendUserLeaveHint)); +        public void finish(boolean toHome, boolean sendUserLeaveHint, IResultReceiver finishCb) { +            mExecutor.execute(() -> finishInner(toHome, sendUserLeaveHint, finishCb));          } -        private void finishInner(boolean toHome, boolean sendUserLeaveHint) { +        private void finishInner(boolean toHome, boolean sendUserLeaveHint, +                IResultReceiver runnerFinishCb) {              if (mFinishCB == null) {                  Slog.e(TAG, "Duplicate call to finish");                  return; @@ -993,6 +996,16 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {              }              cleanUp();              finishCB.onTransitionFinished(wct.isEmpty() ? null : wct); +            if (runnerFinishCb != null) { +                try { +                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, +                            "[%d] RecentsController.finishInner: calling finish callback", +                            mInstanceId); +                    runnerFinishCb.send(0, null); +                } catch (RemoteException e) { +                    Slog.e(TAG, "Failed to report transition finished", e); +                } +            }          }          @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java index 83dc7fa5e869..e828eedc275c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java @@ -23,6 +23,7 @@ import static android.view.Display.DEFAULT_DISPLAY;  import static android.view.WindowManager.TRANSIT_CHANGE;  import static android.view.WindowManager.TRANSIT_TO_BACK;  import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; +  import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;  import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;  import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA; @@ -693,9 +694,19 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,              @NonNull SurfaceControl.Transaction startTransaction,              @NonNull SurfaceControl.Transaction finishTransaction,              @NonNull Transitions.TransitionFinishCallback finishCallback) { +        Transitions.TransitionFinishCallback finishCB = wct -> { +            mixed.mInFlightSubAnimations--; +            if (mixed.mInFlightSubAnimations == 0) { +                mActiveTransitions.remove(mixed); +                finishCallback.onTransitionFinished(wct); +            } +        }; + +        mixed.mInFlightSubAnimations++;          boolean consumed = mRecentsHandler.startAnimation( -                mixed.mTransition, info, startTransaction, finishTransaction, finishCallback); +                mixed.mTransition, info, startTransaction, finishTransaction, finishCB);          if (!consumed) { +            mixed.mInFlightSubAnimations--;              return false;          }          if (mDesktopTasksController != null) { 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 e0635ac2e19a..de03f5826925 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 @@ -322,7 +322,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {          final Runnable onAnimFinish = () -> {              if (!animations.isEmpty()) return;              mAnimations.remove(transition); -            info.releaseAllSurfaces();              finishCallback.onTransitionFinished(null /* wct */);          }; diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp index 54f94986d90c..d09a90cd7dc7 100644 --- a/libs/WindowManager/Shell/tests/unittest/Android.bp +++ b/libs/WindowManager/Shell/tests/unittest/Android.bp @@ -45,7 +45,7 @@ android_test {          "kotlinx-coroutines-core",          "mockito-kotlin2",          "mockito-target-extended-minus-junit4", -        "truth-prebuilt", +        "truth",          "testables",          "platform-test-annotations",          "servicestests-utils", 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 dea161786da2..ebcb6407a6fd 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 @@ -54,6 +54,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.recents.RecentsTransitionHandler +import com.android.wm.shell.recents.RecentsTransitionStateListener  import com.android.wm.shell.splitscreen.SplitScreenController  import com.android.wm.shell.sysui.ShellCommandHandler  import com.android.wm.shell.sysui.ShellController @@ -101,11 +103,13 @@ class DesktopTasksControllerTest : ShellTestCase() {      @Mock lateinit var launchAdjacentController: LaunchAdjacentController      @Mock lateinit var desktopModeWindowDecoration: DesktopModeWindowDecoration      @Mock lateinit var splitScreenController: SplitScreenController +    @Mock lateinit var recentsTransitionHandler: RecentsTransitionHandler      private lateinit var mockitoSession: StaticMockitoSession      private lateinit var controller: DesktopTasksController      private lateinit var shellInit: ShellInit      private lateinit var desktopModeTaskRepository: DesktopModeTaskRepository +    private lateinit var recentsTransitionStateListener: RecentsTransitionStateListener      private val shellExecutor = TestShellExecutor()      // Mock running tasks are registered here so we can get the list from mock shell task organizer @@ -126,6 +130,10 @@ class DesktopTasksControllerTest : ShellTestCase() {          controller.splitScreenController = splitScreenController          shellInit.init() + +        val captor = ArgumentCaptor.forClass(RecentsTransitionStateListener::class.java) +        verify(recentsTransitionHandler).addTransitionStateListener(captor.capture()) +        recentsTransitionStateListener = captor.value      }      private fun createController(): DesktopTasksController { @@ -144,6 +152,7 @@ class DesktopTasksControllerTest : ShellTestCase() {              mToggleResizeDesktopTaskTransitionHandler,              desktopModeTaskRepository,              launchAdjacentController, +            recentsTransitionHandler,              shellExecutor          )      } @@ -355,7 +364,7 @@ class DesktopTasksControllerTest : ShellTestCase() {      @Test      fun moveToDesktop_splitTaskExitsSplit() { -        var task = setUpSplitScreenTask() +        val task = setUpSplitScreenTask()          controller.moveToDesktop(desktopModeWindowDecoration, task)          val wct = getLatestMoveToDesktopWct()          assertThat(wct.changes[task.token.asBinder()]?.windowingMode) @@ -367,7 +376,7 @@ class DesktopTasksControllerTest : ShellTestCase() {      @Test      fun moveToDesktop_fullscreenTaskDoesNotExitSplit() { -        var task = setUpFullscreenTask() +        val task = setUpFullscreenTask()          controller.moveToDesktop(desktopModeWindowDecoration, task)          val wct = getLatestMoveToDesktopWct()          assertThat(wct.changes[task.token.asBinder()]?.windowingMode) @@ -666,6 +675,20 @@ class DesktopTasksControllerTest : ShellTestCase() {      }      @Test +    fun handleRequest_recentsAnimationRunning_returnNull() { +        // Set up a visible freeform task so a fullscreen task should be converted to freeform +        val freeformTask = setUpFreeformTask() +        markTaskVisible(freeformTask) + +        // Mark recents animation running +        recentsTransitionStateListener.onAnimationStateChanged(true) + +        // Open a fullscreen task, check that it does not result in a WCT with changes to it +        val fullscreenTask = createFullscreenTask() +        assertThat(controller.handleRequest(Binder(), createTransition(fullscreenTask))).isNull() +    } + +    @Test      fun stashDesktopApps_stateUpdates() {          whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true) diff --git a/libs/dream/lowlight/tests/Android.bp b/libs/dream/lowlight/tests/Android.bp index 64b53cbb5c5a..4dafd0aa6df4 100644 --- a/libs/dream/lowlight/tests/Android.bp +++ b/libs/dream/lowlight/tests/Android.bp @@ -34,7 +34,7 @@ android_test {          "mockito-target-extended-minus-junit4",          "platform-test-annotations",          "testables", -        "truth-prebuilt", +        "truth",      ],      libs: [          "android.test.mock", diff --git a/libs/securebox/tests/Android.bp b/libs/securebox/tests/Android.bp index 7df546ae0ff6..80b501da1aa5 100644 --- a/libs/securebox/tests/Android.bp +++ b/libs/securebox/tests/Android.bp @@ -32,7 +32,7 @@ android_test {          "platform-test-annotations",          "testables",          "testng", -        "truth-prebuilt", +        "truth",      ],      libs: [          "android.test.mock", diff --git a/media/tests/MediaFrameworkTest/Android.bp b/media/tests/MediaFrameworkTest/Android.bp index ca20225e8885..bdd7afeb2f65 100644 --- a/media/tests/MediaFrameworkTest/Android.bp +++ b/media/tests/MediaFrameworkTest/Android.bp @@ -22,7 +22,7 @@ android_test {          "android-ex-camera2",          "testables",          "testng", -        "truth-prebuilt", +        "truth",      ],      jni_libs: [          "libdexmakerjvmtiagent", diff --git a/media/tests/MediaRouter/Android.bp b/media/tests/MediaRouter/Android.bp index 4cccf8972798..61b18c88e734 100644 --- a/media/tests/MediaRouter/Android.bp +++ b/media/tests/MediaRouter/Android.bp @@ -24,7 +24,7 @@ android_test {          "compatibility-device-util-axt",          "mockito-target-minus-junit4",          "testng", -        "truth-prebuilt", +        "truth",      ],      test_suites: ["general-tests"],      platform_apis: true, diff --git a/media/tests/projection/Android.bp b/media/tests/projection/Android.bp index e313c46d1973..48cd8b69ade8 100644 --- a/media/tests/projection/Android.bp +++ b/media/tests/projection/Android.bp @@ -30,7 +30,7 @@ android_test {          "platform-test-annotations",          "testng",          "testables", -        "truth-prebuilt", +        "truth",          "platform-compat-test-rules",      ], diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt index ba88484518aa..2318bb95dabb 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt @@ -18,21 +18,23 @@ package com.android.credentialmanager.autofill  import android.app.assist.AssistStructure  import android.content.Context -import android.credentials.GetCredentialRequest  import android.credentials.CredentialManager -import android.credentials.GetCandidateCredentialsResponse  import android.credentials.CredentialOption  import android.credentials.GetCandidateCredentialsException +import android.credentials.GetCandidateCredentialsResponse +import android.credentials.GetCredentialRequest  import android.os.Bundle  import android.os.CancellationSignal  import android.os.OutcomeReceiver -import android.service.autofill.FillRequest  import android.service.autofill.AutofillService -import android.service.autofill.FillResponse  import android.service.autofill.FillCallback -import android.service.autofill.SaveRequest +import android.service.autofill.FillRequest +import android.service.autofill.FillResponse  import android.service.autofill.SaveCallback +import android.service.autofill.SaveRequest +import android.service.credentials.CredentialProviderService  import android.util.Log +import android.view.autofill.AutofillId  import org.json.JSONObject  import java.util.concurrent.Executors @@ -129,27 +131,31 @@ class CredentialAutofillService : AutofillService() {      }      private fun traverseNode( -            viewNode: AssistStructure.ViewNode?, +            viewNode: AssistStructure.ViewNode,              cmRequests: MutableList<CredentialOption>      ) { -        val options = getCredentialOptionsFromViewNode(viewNode) -        cmRequests.addAll(options) +        viewNode.autofillId?.let { +            val options = getCredentialOptionsFromViewNode(viewNode, it) +            cmRequests.addAll(options) +        } -        val children: List<AssistStructure.ViewNode>? = -                viewNode?.run { +        val children: List<AssistStructure.ViewNode> = +                viewNode.run {                      (0 until childCount).map { getChildAt(it) }                  } -        children?.forEach { childNode: AssistStructure.ViewNode -> +        children.forEach { childNode: AssistStructure.ViewNode ->              traverseNode(childNode, cmRequests)          }      } -    private fun getCredentialOptionsFromViewNode(viewNode: AssistStructure.ViewNode?): -            List<CredentialOption> { +    private fun getCredentialOptionsFromViewNode( +            viewNode: AssistStructure.ViewNode, +            autofillId: AutofillId +    ): List<CredentialOption> {          // TODO(b/293945193) Replace with isCredential check from viewNode          val credentialHints: MutableList<String> = mutableListOf() -        if (viewNode != null && viewNode.autofillHints != null) { +        if (viewNode.autofillHints != null) {              for (hint in viewNode.autofillHints!!) {                  if (hint.startsWith(CRED_HINT_PREFIX)) {                      credentialHints.add(hint.substringAfter(CRED_HINT_PREFIX)) @@ -159,12 +165,14 @@ class CredentialAutofillService : AutofillService() {          val credentialOptions: MutableList<CredentialOption> = mutableListOf()          for (credentialHint in credentialHints) { -            convertJsonToCredentialOption(credentialHint).let { credentialOptions.addAll(it) } +            convertJsonToCredentialOption(credentialHint, autofillId) +                    .let { credentialOptions.addAll(it) }          }          return credentialOptions      } -    private fun convertJsonToCredentialOption(jsonString: String): List<CredentialOption> { +    private fun convertJsonToCredentialOption(jsonString: String, autofillId: AutofillId): +            List<CredentialOption> {          // TODO(b/302000646) Move this logic to jetpack so that is consistent          //  with building the json          val credentialOptions: MutableList<CredentialOption> = mutableListOf() @@ -173,11 +181,14 @@ class CredentialAutofillService : AutofillService() {          val options = json.getJSONArray(CRED_OPTIONS_KEY)          for (i in 0 until options.length()) {              val option = options.getJSONObject(i) - +            val candidateBundle = convertJsonToBundle(option.getJSONObject(CANDIDATE_DATA_KEY)) +            candidateBundle.putParcelable( +                    CredentialProviderService.EXTRA_AUTOFILL_ID, +                    autofillId)              credentialOptions.add(CredentialOption(                      option.getString(TYPE_KEY),                      convertJsonToBundle(option.getJSONObject(REQUEST_DATA_KEY)), -                    convertJsonToBundle(option.getJSONObject(CANDIDATE_DATA_KEY)), +                    candidateBundle,                      option.getBoolean(SYS_PROVIDER_REQ_KEY),              ))          } diff --git a/packages/ExternalStorageProvider/tests/Android.bp b/packages/ExternalStorageProvider/tests/Android.bp index 633f18610921..86c62ef299e4 100644 --- a/packages/ExternalStorageProvider/tests/Android.bp +++ b/packages/ExternalStorageProvider/tests/Android.bp @@ -25,7 +25,7 @@ android_test {      static_libs: [          "androidx.test.rules",          "mockito-target", -        "truth-prebuilt", +        "truth",      ],      certificate: "platform", diff --git a/packages/FusedLocation/Android.bp b/packages/FusedLocation/Android.bp index 64b4c54e74ad..61a82701d155 100644 --- a/packages/FusedLocation/Android.bp +++ b/packages/FusedLocation/Android.bp @@ -47,7 +47,7 @@ android_test {      test_config: "test/AndroidTest.xml",      srcs: [          "test/src/**/*.java", -        "src/**/*.java",  // include real sources because we're forced to test this directly +        "src/**/*.java", // include real sources because we're forced to test this directly      ],      libs: [          "android.test.base", @@ -60,9 +60,9 @@ android_test {          "androidx.test.ext.junit",          "androidx.test.ext.truth",          "mockito-target-minus-junit4", -        "truth-prebuilt", +        "truth",      ],      platform_apis: true,      certificate: "platform", -    test_suites: ["device-tests"] +    test_suites: ["device-tests"],  } diff --git a/packages/InputDevices/res/raw/keyboard_layout_persian.kcm b/packages/InputDevices/res/raw/keyboard_layout_persian.kcm index 67449220b189..fc53cbad91db 100644 --- a/packages/InputDevices/res/raw/keyboard_layout_persian.kcm +++ b/packages/InputDevices/res/raw/keyboard_layout_persian.kcm @@ -12,9 +12,7 @@  # See the License for the specific language governing permissions and  # limitations under the License. - - -type FULL +type OVERLAY  ### Basic QWERTY keys ### diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml index 88bb30b34ede..7f23f747090b 100644 --- a/packages/InputDevices/res/xml/keyboard_layouts.xml +++ b/packages/InputDevices/res/xml/keyboard_layouts.xml @@ -227,13 +227,6 @@          android:label="@string/keyboard_layout_turkish"          android:keyboardLayout="@raw/keyboard_layout_turkish"          android:keyboardLocale="tr-Latn" -        android:keyboardLayoutType="qwerty" /> - -    <keyboard-layout -        android:name="keyboard_layout_turkish" -        android:label="@string/keyboard_layout_turkish" -        android:keyboardLayout="@raw/keyboard_layout_turkish" -        android:keyboardLocale="tr-Latn"          android:keyboardLayoutType="turkish_q" />      <keyboard-layout diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsTextFieldPassword.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsTextFieldPassword.kt index d0a61882593c..0757df347d68 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsTextFieldPassword.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/SettingsTextFieldPassword.kt @@ -29,8 +29,8 @@ import androidx.compose.material3.OutlinedTextField  import androidx.compose.material3.Text  import androidx.compose.runtime.Composable  import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember  import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember  import androidx.compose.runtime.setValue  import androidx.compose.ui.Modifier  import androidx.compose.ui.platform.testTag @@ -46,6 +46,7 @@ import com.android.settingslib.spa.framework.theme.SettingsTheme  fun SettingsTextFieldPassword(      value: String,      label: String, +    enabled: Boolean = true,      onTextChange: (String) -> Unit,  ) {      var visibility by remember { mutableStateOf(false) } @@ -60,6 +61,7 @@ fun SettingsTextFieldPassword(              keyboardType = KeyboardType.Password,              imeAction = ImeAction.Send          ), +        enabled = enabled,          trailingIcon = {              Icon(                  imageVector = if (visibility) Icons.Outlined.VisibilityOff diff --git a/packages/SettingsLib/Spa/testutils/Android.bp b/packages/SettingsLib/Spa/testutils/Android.bp index 4031cd7f7a6f..639d1a7a7f55 100644 --- a/packages/SettingsLib/Spa/testutils/Android.bp +++ b/packages/SettingsLib/Spa/testutils/Android.bp @@ -31,7 +31,7 @@ android_library {          "androidx.compose.ui_ui-test-manifest",          "androidx.lifecycle_lifecycle-runtime-testing",          "mockito-kotlin2", -        "truth-prebuilt", +        "truth",      ],      kotlincflags: [          "-Xjvm-default=all", diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/SupervisedDeviceActionDisabledByAdminController.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/SupervisedDeviceActionDisabledByAdminController.java index 815293e9c2a8..09f34b3c5a5d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/enterprise/SupervisedDeviceActionDisabledByAdminController.java +++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/SupervisedDeviceActionDisabledByAdminController.java @@ -16,17 +16,20 @@  package com.android.settingslib.enterprise; +  import android.content.ComponentName;  import android.content.Context;  import android.content.DialogInterface;  import android.content.Intent;  import android.net.Uri;  import android.provider.Settings; -import android.util.Log; +import android.text.TextUtils; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable;  import com.android.settingslib.RestrictedLockUtils; -import org.jetbrains.annotations.Nullable;  final class SupervisedDeviceActionDisabledByAdminController          extends BaseActionDisabledByAdminController { @@ -57,8 +60,13 @@ final class SupervisedDeviceActionDisabledByAdminController      @Nullable      @Override -    public DialogInterface.OnClickListener getPositiveButtonListener(Context context, -            RestrictedLockUtils.EnforcedAdmin enforcedAdmin) { +    public DialogInterface.OnClickListener getPositiveButtonListener(@NonNull Context context, +            @NonNull RestrictedLockUtils.EnforcedAdmin enforcedAdmin) { +        if (enforcedAdmin.component == null +                || TextUtils.isEmpty(enforcedAdmin.component.getPackageName())) { +            return null; +        } +          final Intent intent = new Intent(Settings.ACTION_MANAGE_SUPERVISOR_RESTRICTED_SETTING)                  .setData(new Uri.Builder()                          .scheme("policy") @@ -72,7 +80,6 @@ final class SupervisedDeviceActionDisabledByAdminController              return null;          }          return (dialog, which) -> { -            Log.d(TAG, "Positive button clicked, component: " + enforcedAdmin.component);              context.startActivity(intent);          };      } diff --git a/packages/SettingsLib/tests/integ/Android.bp b/packages/SettingsLib/tests/integ/Android.bp index b03c43cbdee5..4b4caf5a620e 100644 --- a/packages/SettingsLib/tests/integ/Android.bp +++ b/packages/SettingsLib/tests/integ/Android.bp @@ -52,7 +52,7 @@ android_test {          "flag-junit",          "mockito-target-minus-junit4",          "platform-test-annotations", -        "truth-prebuilt", +        "truth",          "SettingsLibDeviceStateRotationLock",          "SettingsLibSettingsSpinner",          "SettingsLibUsageProgressBarPreference", diff --git a/packages/SettingsLib/tests/robotests/Android.bp b/packages/SettingsLib/tests/robotests/Android.bp index dd9cb9cf7abe..2d875cf7244d 100644 --- a/packages/SettingsLib/tests/robotests/Android.bp +++ b/packages/SettingsLib/tests/robotests/Android.bp @@ -96,6 +96,6 @@ java_library {      libs: [          "Robolectric_all-target_upstream",          "mockito-robolectric-prebuilt", -        "truth-prebuilt", +        "truth",      ],  } diff --git a/packages/SettingsLib/tests/unit/Android.bp b/packages/SettingsLib/tests/unit/Android.bp index 19ab1c69e98c..6d6e2ff8e59b 100644 --- a/packages/SettingsLib/tests/unit/Android.bp +++ b/packages/SettingsLib/tests/unit/Android.bp @@ -31,6 +31,6 @@ android_test {          "SettingsLib",          "androidx.test.ext.junit",          "androidx.test.runner", -        "truth-prebuilt", +        "truth",      ],  } diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp index 92ebe09fa441..f4ca260d4d89 100644 --- a/packages/SettingsProvider/Android.bp +++ b/packages/SettingsProvider/Android.bp @@ -64,7 +64,7 @@ android_test {          "SettingsLibDeviceStateRotationLock",          "SettingsLibDisplayUtils",          "platform-test-annotations", -        "truth-prebuilt", +        "truth",      ],      libs: [          "android.test.base", diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 91d2d1bb58e5..ba4ad365e1b3 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -218,6 +218,7 @@ public class SecureSettings {          Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,          Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED,          Settings.Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED, +        Settings.Secure.ACCESSIBILITY_MAGNIFICATION_GESTURE,          Settings.Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED,          Settings.Secure.NOTIFICATION_BUBBLES,          Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index bec144766438..19fde758da5d 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -308,6 +308,10 @@ public class SecureSettingsValidators {          VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED, BOOLEAN_VALIDATOR);          VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED, BOOLEAN_VALIDATOR);          VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED, BOOLEAN_VALIDATOR); +        VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_GESTURE, +                new InclusiveIntegerRangeValidator( +                        Secure.ACCESSIBILITY_MAGNIFICATION_GESTURE_NONE, +                        Secure.ACCESSIBILITY_MAGNIFICATION_GESTURE_ALL));          VALIDATORS.put(                  Secure.ACCESSIBILITY_BUTTON_TARGETS,                  ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 3c8d4bca2394..f06b31c4e965 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -1850,6 +1850,10 @@ class SettingsProtoDumpUtil {                  SecureSettingsProto.Accessibility                          .ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED);          dumpSetting(s, p, +                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_GESTURE, +                SecureSettingsProto.Accessibility +                        .ACCESSIBILITY_MAGNIFICATION_GESTURE); +        dumpSetting(s, p,                  Settings.Secure.HEARING_AID_RINGTONE_ROUTING,                  SecureSettingsProto.Accessibility.HEARING_AID_RINGTONE_ROUTING);          dumpSetting(s, p, diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 40f7ba667376..34d3d446530b 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -2054,12 +2054,14 @@ public class SettingsProvider extends ContentProvider {              final Uri ringtoneUri = Uri.parse(value);              // Stream selected ringtone into cache, so it's available for playback              // when CE storage is still locked -            try (InputStream in = openRingtone(getContext(), ringtoneUri); -                 OutputStream out = new FileOutputStream(cacheFile)) { -                FileUtils.copy(in, out); -            } catch (IOException e) { -                Slog.w(LOG_TAG, "Failed to cache ringtone: " + e); -            } +            Binder.withCleanCallingIdentity(() -> { +                try (InputStream in = openRingtone(getContext(), ringtoneUri); +                         OutputStream out = new FileOutputStream(cacheFile)) { +                    FileUtils.copy(in, out); +                } catch (IOException e) { +                    Slog.w(LOG_TAG, "Failed to cache ringtone: " + e); +                } +            });          }          return true;      } diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index ee05f2d9101b..e40fcb2a633b 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -319,6 +319,8 @@ filegroup {          "tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt",          "tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt",          "tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt", +        "tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt", +        "tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt",          /* Bouncer UI tests */          "tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt", @@ -365,6 +367,42 @@ filegroup {          "tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt",          "tests/src/com/android/systemui/qs/tiles/base/**/*.kt",          "tests/src/com/android/systemui/qs/tiles/viewmodel/**/*.kt", + +        /* Authentication */ +        "tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt", +        "tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt", + +        /* Device entry */ +        "tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt", +        "tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt", + +        /* Bouncer scene */ +        "tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt", +        "tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt", +        "tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt", +        "tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt", +        "tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt", +        "tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt", +        "tests/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModelTest.kt", + +        /* Lockscreen scene */ +        "tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt", + +        /* Shade scene */ +        "tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt", +        "tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt", + +        /* Quick Settings scene */ +        "tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt", + +        /* Flexiglass / Scene framework tests */ +        "tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt", +        "tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt", +        "tests/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepositoryTest.kt", +        "tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt", +        "tests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt", +        "tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt", +        "tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt",      ],      path: "tests/src",  } @@ -428,7 +466,7 @@ android_library {          "hamcrest-library",          "androidx.test.rules",          "testables", -        "truth-prebuilt", +        "truth",          "monet",          "libmonet",          "dagger2", @@ -545,7 +583,7 @@ android_robolectric_test {          "android.test.runner",          "android.test.base",          "android.test.mock", -        "truth-prebuilt", +        "truth",      ],      upstream: true, diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java index 008732e787f1..96e1e3fa68a7 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java +++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java @@ -63,6 +63,7 @@ public class AccessibilityMenuService extends AccessibilityService      private static final String TAG = "A11yMenuService";      private static final long BUFFER_MILLISECONDS_TO_PREVENT_UPDATE_FAILURE = 100L; +    private static final long TAKE_SCREENSHOT_DELAY_MS = 100L;      private static final int BRIGHTNESS_UP_INCREMENT_GAMMA =              (int) Math.ceil(BrightnessUtils.GAMMA_SPACE_MAX * 0.11f); @@ -301,7 +302,14 @@ public class AccessibilityMenuService extends AccessibilityService          } else if (viewTag == ShortcutId.ID_NOTIFICATION_VALUE.ordinal()) {              performGlobalActionInternal(GLOBAL_ACTION_NOTIFICATIONS);          } else if (viewTag == ShortcutId.ID_SCREENSHOT_VALUE.ordinal()) { -            performGlobalActionInternal(GLOBAL_ACTION_TAKE_SCREENSHOT); +            if (Flags.a11yMenuHideBeforeTakingAction()) { +                // Delay before taking a screenshot to give time for the UI to close. +                mHandler.postDelayed( +                        () -> performGlobalActionInternal(GLOBAL_ACTION_TAKE_SCREENSHOT), +                        TAKE_SCREENSHOT_DELAY_MS); +            } else { +                performGlobalActionInternal(GLOBAL_ACTION_TAKE_SCREENSHOT); +            }          }          if (!Flags.a11yMenuHideBeforeTakingAction()) { diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp b/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp index 538ecb3d438d..3fc351c32ec1 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp +++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/Android.bp @@ -32,7 +32,7 @@ android_test {          "androidx.test.ext.junit",          "compatibility-device-util-axt",          "platform-test-annotations", -        "truth-prebuilt", +        "truth",      ],      srcs: [          "src/**/*.java", diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index 437f8afa8d70..18117a890298 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -13,3 +13,11 @@ flag {      description: "Enables all the sysui classic flags that are marked as being in teamfood"      bug: "302578396"  } + +flag { +    name: "notifications_footer_view_refactor" +    namespace: "systemui" +    description: "Enables the refactored version of the footer view in the notification shade " +        "(containing the \"Clear all\" button). Should not bring any behavior changes" +    bug: "293167744" +} diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt index 0f2e4bace46d..4aac27932924 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt @@ -39,6 +39,7 @@ import android.view.ViewGroup  import android.view.WindowManager  import android.view.animation.Interpolator  import android.view.animation.PathInterpolator +import androidx.annotation.AnyThread  import androidx.annotation.BinderThread  import androidx.annotation.UiThread  import com.android.app.animation.Interpolators @@ -149,6 +150,10 @@ class ActivityLaunchAnimator(              override fun onLaunchAnimationProgress(linearProgress: Float) {                  listeners.forEach { it.onLaunchAnimationProgress(linearProgress) }              } + +            override fun onLaunchAnimationCancelled() { +                listeners.forEach { it.onLaunchAnimationCancelled() } +            }          }      /** @@ -191,6 +196,7 @@ class ActivityLaunchAnimator(                      "ActivityLaunchAnimator.callback must be set before using this animator"                  )          val runner = createRunner(controller) +        val runnerDelegate = runner.delegate!!          val hideKeyguardWithAnimation = callback.isOnKeyguard() && !showOverLockscreen          // Pass the RemoteAnimationAdapter to the intent starter only if we are not hiding the @@ -241,12 +247,15 @@ class ActivityLaunchAnimator(          // If we expect an animation, post a timeout to cancel it in case the remote animation is          // never started.          if (willAnimate) { -            runner.delegate.postTimeout() +            runnerDelegate.postTimeout()              // Hide the keyguard using the launch animation instead of the default unlock animation.              if (hideKeyguardWithAnimation) {                  callback.hideKeyguardWithAnimation(runner)              } +        } else { +            // We need to make sure delegate references are dropped to avoid memory leaks. +            runner.dispose()          }      } @@ -344,6 +353,13 @@ class ActivityLaunchAnimator(           */          fun onLaunchAnimationEnd() {} +        /** +         * The animation was cancelled. Note that [onLaunchAnimationEnd] will still be called after +         * this if the animation was already started, i.e. if [onLaunchAnimationStart] was called +         * before the cancellation. +         */ +        fun onLaunchAnimationCancelled() {} +          /** Called when an activity launch animation made progress. */          fun onLaunchAnimationProgress(linearProgress: Float) {}      } @@ -426,6 +442,39 @@ class ActivityLaunchAnimator(          fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean? = null) {}      } +    /** +     * Invokes [onAnimationComplete] when animation is either cancelled or completed. Delegates all +     * events to the passed [delegate]. +     */ +    @VisibleForTesting +    inner class DelegatingAnimationCompletionListener( +        private val delegate: Listener?, +        private val onAnimationComplete: () -> Unit +    ) : Listener { +        var cancelled = false + +        override fun onLaunchAnimationStart() { +            delegate?.onLaunchAnimationStart() +        } + +        override fun onLaunchAnimationProgress(linearProgress: Float) { +            delegate?.onLaunchAnimationProgress(linearProgress) +        } + +        override fun onLaunchAnimationEnd() { +            delegate?.onLaunchAnimationEnd() +            if (!cancelled) { +                onAnimationComplete.invoke() +            } +        } + +        override fun onLaunchAnimationCancelled() { +            cancelled = true +            delegate?.onLaunchAnimationCancelled() +            onAnimationComplete.invoke() +        } +    } +      @VisibleForTesting      inner class Runner(          controller: Controller, @@ -436,11 +485,21 @@ class ActivityLaunchAnimator(          listener: Listener? = null      ) : IRemoteAnimationRunner.Stub() {          private val context = controller.launchContainer.context -        internal val delegate: AnimationDelegate + +        // This is being passed across IPC boundaries and cycles (through PendingIntentRecords, +        // etc.) are possible. So we need to make sure we drop any references that might +        // transitively cause leaks when we're done with animation. +        @VisibleForTesting var delegate: AnimationDelegate?          init {              delegate = -                AnimationDelegate(controller, callback, listener, launchAnimator, disableWmTimeout) +                AnimationDelegate( +                    controller, +                    callback, +                    DelegatingAnimationCompletionListener(listener, this::dispose), +                    launchAnimator, +                    disableWmTimeout +                )          }          @BinderThread @@ -451,14 +510,33 @@ class ActivityLaunchAnimator(              nonApps: Array<out RemoteAnimationTarget>?,              finishedCallback: IRemoteAnimationFinishedCallback?          ) { +            val delegate = delegate              context.mainExecutor.execute { -                delegate.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback) +                if (delegate == null) { +                    Log.i(TAG, "onAnimationStart called after completion") +                    // Animation started too late and timed out already. We need to still +                    // signal back that we're done with it. +                    finishedCallback?.onAnimationFinished() +                } else { +                    delegate.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback) +                }              }          }          @BinderThread          override fun onAnimationCancelled() { -            context.mainExecutor.execute { delegate.onAnimationCancelled() } +            val delegate = delegate +            context.mainExecutor.execute { +                delegate ?: Log.wtf(TAG, "onAnimationCancelled called after completion") +                delegate?.onAnimationCancelled() +            } +        } + +        @AnyThread +        fun dispose() { +            // Drop references to animation controller once we're done with the animation +            // to avoid leaking. +            context.mainExecutor.execute { delegate = null }          }      } @@ -584,6 +662,7 @@ class ActivityLaunchAnimator(                      )                  }                  controller.onLaunchAnimationCancelled() +                listener?.onLaunchAnimationCancelled()                  return              } @@ -821,6 +900,7 @@ class ActivityLaunchAnimator(                  Log.d(TAG, "Calling controller.onLaunchAnimationCancelled() [animation timed out]")              }              controller.onLaunchAnimationCancelled() +            listener?.onLaunchAnimationCancelled()          }          @UiThread @@ -842,6 +922,7 @@ class ActivityLaunchAnimator(                  )              }              controller.onLaunchAnimationCancelled() +            listener?.onLaunchAnimationCancelled()          }          private fun IRemoteAnimationFinishedCallback.invoke() { diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt index 88944f10eab9..60c3fd3c4cdb 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt @@ -108,7 +108,7 @@ private fun CoroutineScope.animate(  ) {      val fromScene = layoutImpl.state.transitionState.currentScene      val isUserInput = -        (layoutImpl.state.transitionState as? TransitionState.Transition)?.isUserInputDriven +        (layoutImpl.state.transitionState as? TransitionState.Transition)?.isInitiatedByUserInput              ?: false      val animationSpec = layoutImpl.transitions.transitionSpec(fromScene, target).spec @@ -119,9 +119,23 @@ private fun CoroutineScope.animate(      val targetProgress = if (reversed) 0f else 1f      val transition =          if (reversed) { -            OneOffTransition(target, fromScene, currentScene = target, isUserInput, animatable) +            OneOffTransition( +                fromScene = target, +                toScene = fromScene, +                currentScene = target, +                isUserInput, +                isUserInputOngoing = false, +                animatable, +            )          } else { -            OneOffTransition(fromScene, target, currentScene = target, isUserInput, animatable) +            OneOffTransition( +                fromScene = fromScene, +                toScene = target, +                currentScene = target, +                isUserInput, +                isUserInputOngoing = false, +                animatable, +            )          }      // Change the current layout state to use this new transition. @@ -142,7 +156,8 @@ private class OneOffTransition(      override val fromScene: SceneKey,      override val toScene: SceneKey,      override val currentScene: SceneKey, -    override val isUserInputDriven: Boolean, +    override val isInitiatedByUserInput: Boolean, +    override val isUserInputOngoing: Boolean,      private val animatable: Animatable<Float, AnimationVector1D>,  ) : TransitionState.Transition {      override val progress: Float diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt index ccdec6ea8c5e..1b79dbdee510 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt @@ -52,7 +52,14 @@ sealed class ObservableTransitionState {           * scene, this value will remain true after the pointer is no longer touching the screen and           * will be true in any transition created to animate back to the original position.           */ -        val isUserInputDriven: Boolean, +        val isInitiatedByUserInput: Boolean, + +        /** +         * Whether user input is currently driving the transition. For example, if a user is +         * dragging a pointer, this emits true. Once they lift their finger, this emits false while +         * the transition completes/settles. +         */ +        val isUserInputOngoing: Flow<Boolean>,      ) : ObservableTransitionState()  } @@ -73,7 +80,8 @@ fun SceneTransitionLayoutState.observableTransitionState(): Flow<ObservableTrans                              fromScene = state.fromScene,                              toScene = state.toScene,                              progress = snapshotFlow { state.progress }, -                            isUserInputDriven = state.isUserInputDriven, +                            isInitiatedByUserInput = state.isInitiatedByUserInput, +                            isUserInputOngoing = snapshotFlow { state.isUserInputOngoing },                          )                      }                  } diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt index 39173d98538f..58c7bdbf3d71 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt @@ -130,10 +130,23 @@ interface SceneScope {  sealed interface UserAction  /** The user navigated back, either using a gesture or by triggering a KEYCODE_BACK event. */ -object Back : UserAction +data object Back : UserAction  /** The user swiped on the container. */ -enum class Swipe : UserAction { +data class Swipe( +    val direction: SwipeDirection, +    val pointerCount: Int = 1, +    val fromEdge: Edge? = null, +) : UserAction { +    companion object { +        val Left = Swipe(SwipeDirection.Left) +        val Up = Swipe(SwipeDirection.Up) +        val Right = Swipe(SwipeDirection.Right) +        val Down = Swipe(SwipeDirection.Down) +    } +} + +enum class SwipeDirection {      Up,      Down,      Left, diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt index 7a21211c3dde..b9f83c545122 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt @@ -70,6 +70,9 @@ sealed interface TransitionState {          val progress: Float          /** Whether the transition was triggered by user input rather than being programmatic. */ -        val isUserInputDriven: Boolean +        val isInitiatedByUserInput: Boolean + +        /** Whether user input is currently driving the transition. */ +        val isUserInputOngoing: Boolean      }  } diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt index 1cbfe3057ff0..e275fcaf4572 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt @@ -66,7 +66,7 @@ internal fun Modifier.swipeToScene(      // swipe in the other direction.      val startDragImmediately =          state == transition && -            transition.isAnimatingOffset && +            !transition.isUserInputOngoing &&              !currentScene.shouldEnableSwipes(orientation.opposite())      // The velocity threshold at which the intent of the user is to swipe up or down. It is the same @@ -126,7 +126,7 @@ private class SwipeTransition(initialScene: Scene) : TransitionState.Transition      override val progress: Float          get() { -            val offset = if (isAnimatingOffset) offsetAnimatable.value else dragOffset +            val offset = if (isUserInputOngoing) dragOffset else offsetAnimatable.value              if (distance == 0f) {                  // This can happen only if fromScene == toScene.                  error( @@ -137,16 +137,15 @@ private class SwipeTransition(initialScene: Scene) : TransitionState.Transition              return offset / distance          } -    override val isUserInputDriven = true +    override val isInitiatedByUserInput = true + +    var _isUserInputOngoing by mutableStateOf(false) +    override val isUserInputOngoing: Boolean +        get() = _isUserInputOngoing      /** The current offset caused by the drag gesture. */      var dragOffset by mutableFloatStateOf(0f) -    /** -     * Whether the offset is animated (the user lifted their finger) or if it is driven by gesture. -     */ -    var isAnimatingOffset by mutableStateOf(false) -      /** The animatable used to animate the offset once the user lifted its finger. */      val offsetAnimatable = Animatable(0f, visibilityThreshold = OffsetVisibilityThreshold) @@ -209,9 +208,11 @@ private fun onDragStarted(      transition: SwipeTransition,      orientation: Orientation,  ) { +    transition._isUserInputOngoing = true +      if (layoutImpl.state.transitionState == transition) {          // This [transition] was already driving the animation: simply take over it. -        if (transition.isAnimatingOffset) { +        if (!transition.isUserInputOngoing) {              // Stop animating and start from where the current offset. Setting the animation job to              // `null` will effectively cancel the animation.              transition.stopOffsetAnimation() @@ -456,30 +457,29 @@ private fun CoroutineScope.animateOffset(  ) {      transition.startOffsetAnimation {          launch { -                if (!transition.isAnimatingOffset) { -                    transition.offsetAnimatable.snapTo(transition.dragOffset) -                } -                transition.isAnimatingOffset = true - -                transition.offsetAnimatable.animateTo( -                    targetOffset, -                    // TODO(b/290184746): Make this spring spec configurable. -                    spring( -                        stiffness = Spring.StiffnessMediumLow, -                        visibilityThreshold = OffsetVisibilityThreshold -                    ), -                    initialVelocity = initialVelocity, -                ) +            if (transition.isUserInputOngoing) { +                transition.offsetAnimatable.snapTo(transition.dragOffset) +            } +            transition._isUserInputOngoing = false + +            transition.offsetAnimatable.animateTo( +                targetOffset, +                // TODO(b/290184746): Make this spring spec configurable. +                spring( +                    stiffness = Spring.StiffnessMediumLow, +                    visibilityThreshold = OffsetVisibilityThreshold +                ), +                initialVelocity = initialVelocity, +            ) -                // Now that the animation is done, the state should be idle. Note that if the state -                // was changed since this animation started, some external code changed it and we -                // shouldn't do anything here. Note also that this job will be cancelled in the case -                // where the user intercepts this swipe. -                if (layoutImpl.state.transitionState == transition) { -                    layoutImpl.state.transitionState = TransitionState.Idle(targetScene) -                } +            // Now that the animation is done, the state should be idle. Note that if the state +            // was changed since this animation started, some external code changed it and we +            // shouldn't do anything here. Note also that this job will be cancelled in the case +            // where the user intercepts this swipe. +            if (layoutImpl.state.transitionState == transition) { +                layoutImpl.state.transitionState = TransitionState.Idle(targetScene)              } -            .also { it.invokeOnCompletion { transition.isAnimatingOffset = false } } +        }      }  } diff --git a/packages/SystemUI/compose/core/tests/Android.bp b/packages/SystemUI/compose/core/tests/Android.bp index 52c63854f62f..8e9c5864ce70 100644 --- a/packages/SystemUI/compose/core/tests/Android.bp +++ b/packages/SystemUI/compose/core/tests/Android.bp @@ -43,7 +43,7 @@ android_test {          "androidx.compose.ui_ui-test-junit4",          "androidx.compose.ui_ui-test-manifest", -        "truth-prebuilt", +        "truth",      ],      kotlincflags: ["-Xjvm-default=all"], diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt index 2232370f3dc0..53ed2b5d3317 100644 --- a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt +++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt @@ -122,7 +122,8 @@ class SwipeToSceneTest {          assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)          assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)          assertThat(transition.progress).isEqualTo(55.dp / LayoutWidth) -        assertThat(transition.isUserInputDriven).isTrue() +        assertThat(transition.isInitiatedByUserInput).isTrue() +        assertThat(transition.isUserInputOngoing).isTrue()          // Release the finger. We should now be animating back to A (currentScene = SceneA) given          // that 55dp < positional threshold. @@ -134,7 +135,8 @@ class SwipeToSceneTest {          assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)          assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)          assertThat(transition.progress).isEqualTo(55.dp / LayoutWidth) -        assertThat(transition.isUserInputDriven).isTrue() +        assertThat(transition.isInitiatedByUserInput).isTrue() +        assertThat(transition.isUserInputOngoing).isFalse()          // Wait for the animation to finish. We should now be in scene A.          rule.waitForIdle() @@ -156,7 +158,8 @@ class SwipeToSceneTest {          assertThat(transition.toScene).isEqualTo(TestScenes.SceneC)          assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)          assertThat(transition.progress).isEqualTo(56.dp / LayoutHeight) -        assertThat(transition.isUserInputDriven).isTrue() +        assertThat(transition.isInitiatedByUserInput).isTrue() +        assertThat(transition.isUserInputOngoing).isTrue()          // Release the finger. We should now be animating to C (currentScene = SceneC) given          // that 56dp >= positional threshold. @@ -168,7 +171,8 @@ class SwipeToSceneTest {          assertThat(transition.toScene).isEqualTo(TestScenes.SceneC)          assertThat(transition.currentScene).isEqualTo(TestScenes.SceneC)          assertThat(transition.progress).isEqualTo(56.dp / LayoutHeight) -        assertThat(transition.isUserInputDriven).isTrue() +        assertThat(transition.isInitiatedByUserInput).isTrue() +        assertThat(transition.isUserInputOngoing).isFalse()          // Wait for the animation to finish. We should now be in scene C.          rule.waitForIdle() diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt index c3a3752db374..ee310ab41373 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt @@ -36,13 +36,14 @@ import androidx.compose.ui.input.pointer.pointerInput  import androidx.compose.ui.viewinterop.AndroidView  import androidx.core.view.isVisible  import com.android.compose.animation.scene.SceneScope -import com.android.systemui.res.R  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.keyguard.qualifiers.KeyguardRootView  import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel  import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel +import com.android.systemui.res.R  import com.android.systemui.scene.shared.model.Direction +import com.android.systemui.scene.shared.model.Edge  import com.android.systemui.scene.shared.model.SceneKey  import com.android.systemui.scene.shared.model.SceneModel  import com.android.systemui.scene.shared.model.UserAction @@ -99,7 +100,9 @@ constructor(          return buildMap {              up?.let { this[UserAction.Swipe(Direction.UP)] = SceneModel(up) }              left?.let { this[UserAction.Swipe(Direction.LEFT)] = SceneModel(left) } -            this[UserAction.Swipe(Direction.DOWN)] = SceneModel(SceneKey.Shade) +            this[UserAction.Swipe(fromEdge = Edge.TOP, direction = Direction.DOWN)] = +                SceneModel(SceneKey.QuickSettings) +            this[UserAction.Swipe(direction = Direction.DOWN)] = SceneModel(SceneKey.Shade)          }      }  } 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 1f9c3e6d1ea1..a33eac55ac3e 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 @@ -23,11 +23,13 @@ import androidx.compose.foundation.layout.Spacer  import androidx.compose.foundation.layout.fillMaxSize  import androidx.compose.foundation.layout.height  import androidx.compose.foundation.layout.padding +import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass  import androidx.compose.runtime.Composable  import androidx.compose.ui.Alignment  import androidx.compose.ui.Modifier  import androidx.compose.ui.unit.dp  import com.android.compose.animation.scene.SceneScope +import com.android.compose.windowsizeclass.LocalWindowSizeClass  import com.android.systemui.battery.BatteryMeterViewController  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.qs.footer.ui.compose.QuickSettings @@ -37,6 +39,7 @@ import com.android.systemui.scene.shared.model.SceneKey  import com.android.systemui.scene.shared.model.SceneModel  import com.android.systemui.scene.shared.model.UserAction  import com.android.systemui.scene.ui.composable.ComposableScene +import com.android.systemui.shade.ui.composable.CollapsedShadeHeader  import com.android.systemui.shade.ui.composable.ExpandedShadeHeader  import com.android.systemui.statusbar.phone.StatusBarIconController  import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager @@ -98,12 +101,22 @@ private fun SceneScope.QuickSettingsScene(                  .clickable(onClick = { viewModel.onContentClicked() })                  .padding(start = 16.dp, end = 16.dp, bottom = 48.dp)      ) { -        ExpandedShadeHeader( -            viewModel = viewModel.shadeHeaderViewModel, -            createTintedIconManager = createTintedIconManager, -            createBatteryMeterViewController = createBatteryMeterViewController, -            statusBarIconController = statusBarIconController, -        ) +        when (LocalWindowSizeClass.current.widthSizeClass) { +            WindowWidthSizeClass.Compact -> +                ExpandedShadeHeader( +                    viewModel = viewModel.shadeHeaderViewModel, +                    createTintedIconManager = createTintedIconManager, +                    createBatteryMeterViewController = createBatteryMeterViewController, +                    statusBarIconController = statusBarIconController, +                ) +            else -> +                CollapsedShadeHeader( +                    viewModel = viewModel.shadeHeaderViewModel, +                    createTintedIconManager = createTintedIconManager, +                    createBatteryMeterViewController = createBatteryMeterViewController, +                    statusBarIconController = statusBarIconController, +                ) +        }          Spacer(modifier = Modifier.height(16.dp))          QuickSettings()      } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt index 2ee461fca042..f35ea8373db7 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt @@ -22,6 +22,7 @@ import androidx.compose.ui.Modifier  import com.android.compose.animation.scene.SceneScope  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.scene.shared.model.Direction +import com.android.systemui.scene.shared.model.Edge  import com.android.systemui.scene.shared.model.SceneKey  import com.android.systemui.scene.shared.model.SceneModel  import com.android.systemui.scene.shared.model.UserAction @@ -41,7 +42,12 @@ class GoneScene @Inject constructor() : ComposableScene {      override val destinationScenes: StateFlow<Map<UserAction, SceneModel>> =          MutableStateFlow<Map<UserAction, SceneModel>>(                  mapOf( -                    UserAction.Swipe(Direction.DOWN) to SceneModel(SceneKey.Shade), +                    UserAction.Swipe( +                        pointerCount = 2, +                        fromEdge = Edge.TOP, +                        direction = Direction.DOWN, +                    ) to SceneModel(SceneKey.QuickSettings), +                    UserAction.Swipe(direction = Direction.DOWN) to SceneModel(SceneKey.Shade),                  )              )              .asStateFlow() diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt index ef012660ad71..0da562bcb3bb 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt @@ -35,15 +35,18 @@ import androidx.compose.ui.input.pointer.PointerEventPass  import androidx.compose.ui.input.pointer.motionEventSpy  import androidx.compose.ui.input.pointer.pointerInput  import com.android.compose.animation.scene.Back +import com.android.compose.animation.scene.Edge as SceneTransitionEdge  import com.android.compose.animation.scene.ObservableTransitionState as SceneTransitionObservableTransitionState  import com.android.compose.animation.scene.SceneKey as SceneTransitionSceneKey  import com.android.compose.animation.scene.SceneTransitionLayout  import com.android.compose.animation.scene.SceneTransitionLayoutState  import com.android.compose.animation.scene.Swipe +import com.android.compose.animation.scene.SwipeDirection  import com.android.compose.animation.scene.UserAction as SceneTransitionUserAction  import com.android.compose.animation.scene.observableTransitionState  import com.android.systemui.ribbon.ui.composable.BottomRightCornerRibbon  import com.android.systemui.scene.shared.model.Direction +import com.android.systemui.scene.shared.model.Edge  import com.android.systemui.scene.shared.model.ObservableTransitionState  import com.android.systemui.scene.shared.model.SceneKey  import com.android.systemui.scene.shared.model.SceneModel @@ -158,7 +161,8 @@ private fun SceneTransitionObservableTransitionState.toModel(): ObservableTransi                  fromScene = fromScene.toModel().key,                  toScene = toScene.toModel().key,                  progress = progress, -                isUserInputDriven = isUserInputDriven, +                isInitiatedByUserInput = isInitiatedByUserInput, +                isUserInputOngoing = isUserInputOngoing,              )      }  } @@ -180,12 +184,24 @@ private fun SceneTransitionSceneKey.toModel(): SceneModel {  private fun UserAction.toTransitionUserAction(): SceneTransitionUserAction {      return when (this) {          is UserAction.Swipe -> -            when (this.direction) { -                Direction.LEFT -> Swipe.Left -                Direction.UP -> Swipe.Up -                Direction.RIGHT -> Swipe.Right -                Direction.DOWN -> Swipe.Down -            } +            Swipe( +                pointerCount = pointerCount, +                fromEdge = +                    when (this.fromEdge) { +                        null -> null +                        Edge.LEFT -> SceneTransitionEdge.Left +                        Edge.TOP -> SceneTransitionEdge.Top +                        Edge.RIGHT -> SceneTransitionEdge.Right +                        Edge.BOTTOM -> SceneTransitionEdge.Bottom +                    }, +                direction = +                    when (this.direction) { +                        Direction.LEFT -> SwipeDirection.Left +                        Direction.UP -> SwipeDirection.Up +                        Direction.RIGHT -> SwipeDirection.Right +                        Direction.DOWN -> SwipeDirection.Down +                    } +            )          is UserAction.Back -> Back      }  } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt index 6629a2598587..591fa76f423f 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt @@ -30,6 +30,7 @@ import androidx.compose.foundation.layout.height  import androidx.compose.foundation.layout.padding  import androidx.compose.foundation.layout.width  import androidx.compose.foundation.layout.widthIn +import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass  import androidx.compose.runtime.Composable  import androidx.compose.runtime.collectAsState  import androidx.compose.runtime.derivedStateOf @@ -50,6 +51,7 @@ import com.android.compose.animation.scene.ElementKey  import com.android.compose.animation.scene.SceneScope  import com.android.compose.animation.scene.ValueKey  import com.android.compose.animation.scene.animateSharedFloatAsState +import com.android.compose.windowsizeclass.LocalWindowSizeClass  import com.android.settingslib.Utils  import com.android.systemui.battery.BatteryMeterView  import com.android.systemui.battery.BatteryMeterViewController @@ -98,12 +100,12 @@ fun SceneScope.CollapsedShadeHeader(              ShadeHeader.Keys.transitionProgress,              ShadeHeader.Elements.FormatPlaceholder          ) -    val useExpandedFormat by -        remember(formatProgress) { derivedStateOf { formatProgress.value > 0.5f } }      val cutoutWidth = LocalDisplayCutout.current.width()      val cutoutLocation = LocalDisplayCutout.current.location +    val useExpandedFormat = formatProgress.value > 0.5f || cutoutLocation != CutoutLocation.CENTER +      // This layout assumes it is globally positioned at (0, 0) and is the      // same size as the screen.      Layout( @@ -131,6 +133,14 @@ fun SceneScope.CollapsedShadeHeader(                  {                      Row(horizontalArrangement = Arrangement.End) {                          SystemIconContainer { +                            when (LocalWindowSizeClass.current.widthSizeClass) { +                                WindowWidthSizeClass.Medium, +                                WindowWidthSizeClass.Expanded -> +                                    ShadeCarrierGroup( +                                        viewModel = viewModel, +                                        modifier = Modifier.align(Alignment.CenterVertically), +                                    ) +                            }                              StatusIcons(                                  viewModel = viewModel,                                  createTintedIconManager = createTintedIconManager, diff --git a/packages/SystemUI/customization/res/values-af/strings.xml b/packages/SystemUI/customization/res/values-af/strings.xml new file mode 100644 index 000000000000..4c2c6275e6d8 --- /dev/null +++ b/packages/SystemUI/customization/res/values-af/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Verstek vir digitaal"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-am/strings.xml b/packages/SystemUI/customization/res/values-am/strings.xml new file mode 100644 index 000000000000..847d7a541c95 --- /dev/null +++ b/packages/SystemUI/customization/res/values-am/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"ዲጂታል ነባሪ"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ar/strings.xml b/packages/SystemUI/customization/res/values-ar/strings.xml new file mode 100644 index 000000000000..57d1612b337d --- /dev/null +++ b/packages/SystemUI/customization/res/values-ar/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"رقمية تلقائية"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-as/strings.xml b/packages/SystemUI/customization/res/values-as/strings.xml new file mode 100644 index 000000000000..2f3b64b9ceb6 --- /dev/null +++ b/packages/SystemUI/customization/res/values-as/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"ডিজিটেল ডিফ’ল্ট"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-az/strings.xml b/packages/SystemUI/customization/res/values-az/strings.xml new file mode 100644 index 000000000000..eb52f95a4525 --- /dev/null +++ b/packages/SystemUI/customization/res/values-az/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Rəqəmsal defolt"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/customization/res/values-b+sr+Latn/strings.xml new file mode 100644 index 000000000000..90e6678bdcd6 --- /dev/null +++ b/packages/SystemUI/customization/res/values-b+sr+Latn/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digitalni podrazumevani"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-be/strings.xml b/packages/SystemUI/customization/res/values-be/strings.xml new file mode 100644 index 000000000000..f327da2a40a4 --- /dev/null +++ b/packages/SystemUI/customization/res/values-be/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"электронны, стандартны шрыфт"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-bg/strings.xml b/packages/SystemUI/customization/res/values-bg/strings.xml new file mode 100644 index 000000000000..6e3754a62a29 --- /dev/null +++ b/packages/SystemUI/customization/res/values-bg/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Стандартно дигитално"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-bn/strings.xml b/packages/SystemUI/customization/res/values-bn/strings.xml new file mode 100644 index 000000000000..adf1256b6c82 --- /dev/null +++ b/packages/SystemUI/customization/res/values-bn/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"ডিজিটাল ডিফল্ট"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-bs/strings.xml b/packages/SystemUI/customization/res/values-bs/strings.xml new file mode 100644 index 000000000000..8de04ab06503 --- /dev/null +++ b/packages/SystemUI/customization/res/values-bs/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digitalno zadano"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ca/strings.xml b/packages/SystemUI/customization/res/values-ca/strings.xml new file mode 100644 index 000000000000..967bb3f6d2f5 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ca/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digital predeterminat"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-cs/strings.xml b/packages/SystemUI/customization/res/values-cs/strings.xml new file mode 100644 index 000000000000..45da4d759ad4 --- /dev/null +++ b/packages/SystemUI/customization/res/values-cs/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digitální výchozí"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-da/strings.xml b/packages/SystemUI/customization/res/values-da/strings.xml new file mode 100644 index 000000000000..3ffaa8b167c8 --- /dev/null +++ b/packages/SystemUI/customization/res/values-da/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Standard (digital)"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-de/strings.xml b/packages/SystemUI/customization/res/values-de/strings.xml new file mode 100644 index 000000000000..64f95e05b245 --- /dev/null +++ b/packages/SystemUI/customization/res/values-de/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digital (Standard)"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-el/strings.xml b/packages/SystemUI/customization/res/values-el/strings.xml new file mode 100644 index 000000000000..57134b566d08 --- /dev/null +++ b/packages/SystemUI/customization/res/values-el/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Ψηφιακή προεπιλογή"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-en-rAU/strings.xml b/packages/SystemUI/customization/res/values-en-rAU/strings.xml new file mode 100644 index 000000000000..a6110d5d5b09 --- /dev/null +++ b/packages/SystemUI/customization/res/values-en-rAU/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-en-rCA/strings.xml b/packages/SystemUI/customization/res/values-en-rCA/strings.xml new file mode 100644 index 000000000000..79919c07d189 --- /dev/null +++ b/packages/SystemUI/customization/res/values-en-rCA/strings.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +    <!-- no translation found for clock_default_description (5309401440896597541) --> +    <skip /> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-en-rGB/strings.xml b/packages/SystemUI/customization/res/values-en-rGB/strings.xml new file mode 100644 index 000000000000..a6110d5d5b09 --- /dev/null +++ b/packages/SystemUI/customization/res/values-en-rGB/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-en-rIN/strings.xml b/packages/SystemUI/customization/res/values-en-rIN/strings.xml new file mode 100644 index 000000000000..a6110d5d5b09 --- /dev/null +++ b/packages/SystemUI/customization/res/values-en-rIN/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-en-rXC/strings.xml b/packages/SystemUI/customization/res/values-en-rXC/strings.xml new file mode 100644 index 000000000000..7c540dab2cfe --- /dev/null +++ b/packages/SystemUI/customization/res/values-en-rXC/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-es-rUS/strings.xml b/packages/SystemUI/customization/res/values-es-rUS/strings.xml new file mode 100644 index 000000000000..59be786849e6 --- /dev/null +++ b/packages/SystemUI/customization/res/values-es-rUS/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Configuración predeterminada digital"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-es/strings.xml b/packages/SystemUI/customization/res/values-es/strings.xml new file mode 100644 index 000000000000..03ef0e5a8cea --- /dev/null +++ b/packages/SystemUI/customization/res/values-es/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digital predeterminada"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-et/strings.xml b/packages/SystemUI/customization/res/values-et/strings.xml new file mode 100644 index 000000000000..fec793e99619 --- /dev/null +++ b/packages/SystemUI/customization/res/values-et/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digitaalne vaikimisi"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-eu/strings.xml b/packages/SystemUI/customization/res/values-eu/strings.xml new file mode 100644 index 000000000000..a70c8085ccf0 --- /dev/null +++ b/packages/SystemUI/customization/res/values-eu/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digital lehenetsia"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-fa/strings.xml b/packages/SystemUI/customization/res/values-fa/strings.xml new file mode 100644 index 000000000000..6426d5112528 --- /dev/null +++ b/packages/SystemUI/customization/res/values-fa/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"دیجیتال پیشفرض"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-fi/strings.xml b/packages/SystemUI/customization/res/values-fi/strings.xml new file mode 100644 index 000000000000..9b19373a3765 --- /dev/null +++ b/packages/SystemUI/customization/res/values-fi/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digitaalinen (oletus)"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-fr-rCA/strings.xml b/packages/SystemUI/customization/res/values-fr-rCA/strings.xml new file mode 100644 index 000000000000..bbd1208b1922 --- /dev/null +++ b/packages/SystemUI/customization/res/values-fr-rCA/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Numérique, par défaut"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-fr/strings.xml b/packages/SystemUI/customization/res/values-fr/strings.xml new file mode 100644 index 000000000000..5579a427fe71 --- /dev/null +++ b/packages/SystemUI/customization/res/values-fr/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Numérique par défaut"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-gl/strings.xml b/packages/SystemUI/customization/res/values-gl/strings.xml new file mode 100644 index 000000000000..2da93c6f1e34 --- /dev/null +++ b/packages/SystemUI/customization/res/values-gl/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Predeterminada dixital"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-gu/strings.xml b/packages/SystemUI/customization/res/values-gu/strings.xml new file mode 100644 index 000000000000..c578a2e2d322 --- /dev/null +++ b/packages/SystemUI/customization/res/values-gu/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"ડિજિટલ ડિફૉલ્ટ"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-hi/strings.xml b/packages/SystemUI/customization/res/values-hi/strings.xml new file mode 100644 index 000000000000..6080f802af04 --- /dev/null +++ b/packages/SystemUI/customization/res/values-hi/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"डिजिटल डिफ़ॉल्ट"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-hr/strings.xml b/packages/SystemUI/customization/res/values-hr/strings.xml new file mode 100644 index 000000000000..0a1440fb683b --- /dev/null +++ b/packages/SystemUI/customization/res/values-hr/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digitalni zadani"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-hu/strings.xml b/packages/SystemUI/customization/res/values-hu/strings.xml new file mode 100644 index 000000000000..32618a869a1f --- /dev/null +++ b/packages/SystemUI/customization/res/values-hu/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digitális, alapértelmezett"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-hy/strings.xml b/packages/SystemUI/customization/res/values-hy/strings.xml new file mode 100644 index 000000000000..d45afbf256ab --- /dev/null +++ b/packages/SystemUI/customization/res/values-hy/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Թվային, կանխադրված"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-in/strings.xml b/packages/SystemUI/customization/res/values-in/strings.xml new file mode 100644 index 000000000000..a6110d5d5b09 --- /dev/null +++ b/packages/SystemUI/customization/res/values-in/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digital default"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-is/strings.xml b/packages/SystemUI/customization/res/values-is/strings.xml new file mode 100644 index 000000000000..5a370d614f0f --- /dev/null +++ b/packages/SystemUI/customization/res/values-is/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Stafræn, sjálfgefið"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-it/strings.xml b/packages/SystemUI/customization/res/values-it/strings.xml new file mode 100644 index 000000000000..2a5087d30669 --- /dev/null +++ b/packages/SystemUI/customization/res/values-it/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digitale - predefinito"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-iw/strings.xml b/packages/SystemUI/customization/res/values-iw/strings.xml new file mode 100644 index 000000000000..ddd28f21ad99 --- /dev/null +++ b/packages/SystemUI/customization/res/values-iw/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"דיגיטלי ברירת מחדל"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ja/strings.xml b/packages/SystemUI/customization/res/values-ja/strings.xml new file mode 100644 index 000000000000..744604a17efa --- /dev/null +++ b/packages/SystemUI/customization/res/values-ja/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"デジタル デフォルト"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ka/strings.xml b/packages/SystemUI/customization/res/values-ka/strings.xml new file mode 100644 index 000000000000..88ba1dfc0976 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ka/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"ციფრული ნაგულისხმევი"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-kk/strings.xml b/packages/SystemUI/customization/res/values-kk/strings.xml new file mode 100644 index 000000000000..9ee6522c49ce --- /dev/null +++ b/packages/SystemUI/customization/res/values-kk/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Цифрлық әдепкі"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-km/strings.xml b/packages/SystemUI/customization/res/values-km/strings.xml new file mode 100644 index 000000000000..bbc438a69bcd --- /dev/null +++ b/packages/SystemUI/customization/res/values-km/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"លំនាំដើមឌីជីថល"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-kn/strings.xml b/packages/SystemUI/customization/res/values-kn/strings.xml new file mode 100644 index 000000000000..e67319d4021b --- /dev/null +++ b/packages/SystemUI/customization/res/values-kn/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"ಡಿಜಿಟಲ್ ಡೀಫಾಲ್ಟ್"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ko/strings.xml b/packages/SystemUI/customization/res/values-ko/strings.xml new file mode 100644 index 000000000000..fa9103b01e66 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ko/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"디지털 기본"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ky/strings.xml b/packages/SystemUI/customization/res/values-ky/strings.xml new file mode 100644 index 000000000000..76cc5e211a40 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ky/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Демейки санариптик"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-lo/strings.xml b/packages/SystemUI/customization/res/values-lo/strings.xml new file mode 100644 index 000000000000..28f50008bd73 --- /dev/null +++ b/packages/SystemUI/customization/res/values-lo/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"ດິຈິຕອນຕາມຄ່າເລີ່ມຕົ້ນ"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-lt/strings.xml b/packages/SystemUI/customization/res/values-lt/strings.xml new file mode 100644 index 000000000000..2fe731547762 --- /dev/null +++ b/packages/SystemUI/customization/res/values-lt/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Skaitmeninis numatytasis"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-lv/strings.xml b/packages/SystemUI/customization/res/values-lv/strings.xml new file mode 100644 index 000000000000..e0b904a8a1c9 --- /dev/null +++ b/packages/SystemUI/customization/res/values-lv/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digitālais pulkstenis — noklusējums"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-mk/strings.xml b/packages/SystemUI/customization/res/values-mk/strings.xml new file mode 100644 index 000000000000..9b95a6e32b31 --- /dev/null +++ b/packages/SystemUI/customization/res/values-mk/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Дигитален стандарден приказ"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ml/strings.xml b/packages/SystemUI/customization/res/values-ml/strings.xml new file mode 100644 index 000000000000..7f6be8a59904 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ml/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"ഡിജിറ്റൽ ഡിഫോൾട്ട്"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-mn/strings.xml b/packages/SystemUI/customization/res/values-mn/strings.xml new file mode 100644 index 000000000000..38369b6f527d --- /dev/null +++ b/packages/SystemUI/customization/res/values-mn/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Дижитал өгөгдмөл"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-mr/strings.xml b/packages/SystemUI/customization/res/values-mr/strings.xml new file mode 100644 index 000000000000..821ff100ab13 --- /dev/null +++ b/packages/SystemUI/customization/res/values-mr/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"डिजिटल डीफॉल्टसह क्लॉक फेस"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ms/strings.xml b/packages/SystemUI/customization/res/values-ms/strings.xml new file mode 100644 index 000000000000..2f61b47a2324 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ms/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digital lalai"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-my/strings.xml b/packages/SystemUI/customization/res/values-my/strings.xml new file mode 100644 index 000000000000..3d137ebc3abb --- /dev/null +++ b/packages/SystemUI/customization/res/values-my/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"ဒစ်ဂျစ်တယ်နာရီ မူရင်း"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-nb/strings.xml b/packages/SystemUI/customization/res/values-nb/strings.xml new file mode 100644 index 000000000000..6eb4373c448c --- /dev/null +++ b/packages/SystemUI/customization/res/values-nb/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digital – standard"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ne/strings.xml b/packages/SystemUI/customization/res/values-ne/strings.xml new file mode 100644 index 000000000000..c5b087744a18 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ne/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"डिजिटल डिफल्ट"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-nl/strings.xml b/packages/SystemUI/customization/res/values-nl/strings.xml new file mode 100644 index 000000000000..4f46ab8b2ba5 --- /dev/null +++ b/packages/SystemUI/customization/res/values-nl/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Standaard digitaal"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-or/strings.xml b/packages/SystemUI/customization/res/values-or/strings.xml new file mode 100644 index 000000000000..a74017f6b689 --- /dev/null +++ b/packages/SystemUI/customization/res/values-or/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"ଡିଜିଟାଲ ଡିଫଲ୍ଟ"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-pa/strings.xml b/packages/SystemUI/customization/res/values-pa/strings.xml new file mode 100644 index 000000000000..a77661a8f56b --- /dev/null +++ b/packages/SystemUI/customization/res/values-pa/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"ਡਿਜੀਟਲ ਡਿਫਾਲਟ"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-pl/strings.xml b/packages/SystemUI/customization/res/values-pl/strings.xml new file mode 100644 index 000000000000..6f5b6f280dd1 --- /dev/null +++ b/packages/SystemUI/customization/res/values-pl/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Cyfrowa domyślna"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-pt-rPT/strings.xml b/packages/SystemUI/customization/res/values-pt-rPT/strings.xml new file mode 100644 index 000000000000..c6c3cc046965 --- /dev/null +++ b/packages/SystemUI/customization/res/values-pt-rPT/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Predefinição digital"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-pt/strings.xml b/packages/SystemUI/customization/res/values-pt/strings.xml new file mode 100644 index 000000000000..bbe435543211 --- /dev/null +++ b/packages/SystemUI/customization/res/values-pt/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digital padrão"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ro/strings.xml b/packages/SystemUI/customization/res/values-ro/strings.xml new file mode 100644 index 000000000000..ef163e96f79f --- /dev/null +++ b/packages/SystemUI/customization/res/values-ro/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Implicit digital"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ru/strings.xml b/packages/SystemUI/customization/res/values-ru/strings.xml new file mode 100644 index 000000000000..5ee928e0fa37 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ru/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Цифровые часы, стандартный"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-si/strings.xml b/packages/SystemUI/customization/res/values-si/strings.xml new file mode 100644 index 000000000000..caf9610e921e --- /dev/null +++ b/packages/SystemUI/customization/res/values-si/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"ඩිජිටල් පෙරනිමිය"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-sk/strings.xml b/packages/SystemUI/customization/res/values-sk/strings.xml new file mode 100644 index 000000000000..1843f971d251 --- /dev/null +++ b/packages/SystemUI/customization/res/values-sk/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digitálne predvolené"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-sl/strings.xml b/packages/SystemUI/customization/res/values-sl/strings.xml new file mode 100644 index 000000000000..12df66f571d3 --- /dev/null +++ b/packages/SystemUI/customization/res/values-sl/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digitalna (privzeta)"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-sq/strings.xml b/packages/SystemUI/customization/res/values-sq/strings.xml new file mode 100644 index 000000000000..1fc9f252175f --- /dev/null +++ b/packages/SystemUI/customization/res/values-sq/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Dixhitale e parazgjedhur"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-sr/strings.xml b/packages/SystemUI/customization/res/values-sr/strings.xml new file mode 100644 index 000000000000..6b127c9f79e5 --- /dev/null +++ b/packages/SystemUI/customization/res/values-sr/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Дигитални подразумевани"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-sv/strings.xml b/packages/SystemUI/customization/res/values-sv/strings.xml new file mode 100644 index 000000000000..84ad25c96655 --- /dev/null +++ b/packages/SystemUI/customization/res/values-sv/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digital standard"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-sw/strings.xml b/packages/SystemUI/customization/res/values-sw/strings.xml new file mode 100644 index 000000000000..e2ec3de573a8 --- /dev/null +++ b/packages/SystemUI/customization/res/values-sw/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Dijitali chaguomsingi"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-sw400dp/dimens.xml b/packages/SystemUI/customization/res/values-sw400dp/dimens.xml new file mode 100644 index 000000000000..3c9e0789b5f2 --- /dev/null +++ b/packages/SystemUI/customization/res/values-sw400dp/dimens.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ +--> +<resources> +    <dimen name="presentation_clock_text_size">170dp</dimen> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ta/strings.xml b/packages/SystemUI/customization/res/values-ta/strings.xml new file mode 100644 index 000000000000..f4eea07b0aa5 --- /dev/null +++ b/packages/SystemUI/customization/res/values-ta/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"டிஜிட்டல் இயல்பு"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-te/strings.xml b/packages/SystemUI/customization/res/values-te/strings.xml new file mode 100644 index 000000000000..c7c77d527e7f --- /dev/null +++ b/packages/SystemUI/customization/res/values-te/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"డిజిటల్ ఆటోమేటిక్ సెట్టింగ్"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-th/strings.xml b/packages/SystemUI/customization/res/values-th/strings.xml new file mode 100644 index 000000000000..61d880eb1ad9 --- /dev/null +++ b/packages/SystemUI/customization/res/values-th/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"ดิจิทัลแบบเริ่มต้น"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-tl/strings.xml b/packages/SystemUI/customization/res/values-tl/strings.xml new file mode 100644 index 000000000000..a3484a7b6d2a --- /dev/null +++ b/packages/SystemUI/customization/res/values-tl/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Digital na default"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-tr/strings.xml b/packages/SystemUI/customization/res/values-tr/strings.xml new file mode 100644 index 000000000000..a90e9852ef2f --- /dev/null +++ b/packages/SystemUI/customization/res/values-tr/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Dijital varsayılan"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-uk/strings.xml b/packages/SystemUI/customization/res/values-uk/strings.xml new file mode 100644 index 000000000000..ee9b77b905a2 --- /dev/null +++ b/packages/SystemUI/customization/res/values-uk/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Цифровий, стандартний"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-ur/strings.xml b/packages/SystemUI/customization/res/values-ur/strings.xml new file mode 100644 index 000000000000..06a6a7cd01fd --- /dev/null +++ b/packages/SystemUI/customization/res/values-ur/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"ڈیجیٹل ڈیفالٹ"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-uz/strings.xml b/packages/SystemUI/customization/res/values-uz/strings.xml new file mode 100644 index 000000000000..6b31b048b4a1 --- /dev/null +++ b/packages/SystemUI/customization/res/values-uz/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Raqamli soat, standart"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-vi/strings.xml b/packages/SystemUI/customization/res/values-vi/strings.xml new file mode 100644 index 000000000000..830b6e2b16a1 --- /dev/null +++ b/packages/SystemUI/customization/res/values-vi/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Mặt số mặc định"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-zh-rCN/strings.xml b/packages/SystemUI/customization/res/values-zh-rCN/strings.xml new file mode 100644 index 000000000000..747567e9fb65 --- /dev/null +++ b/packages/SystemUI/customization/res/values-zh-rCN/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"默认数字"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-zh-rHK/strings.xml b/packages/SystemUI/customization/res/values-zh-rHK/strings.xml new file mode 100644 index 000000000000..c19cc68ff150 --- /dev/null +++ b/packages/SystemUI/customization/res/values-zh-rHK/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"數碼時鐘 (預設)"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-zh-rTW/strings.xml b/packages/SystemUI/customization/res/values-zh-rTW/strings.xml new file mode 100644 index 000000000000..6fcd313a291d --- /dev/null +++ b/packages/SystemUI/customization/res/values-zh-rTW/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"數位預設"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-zu/strings.xml b/packages/SystemUI/customization/res/values-zu/strings.xml new file mode 100644 index 000000000000..c87c250ae1b9 --- /dev/null +++ b/packages/SystemUI/customization/res/values-zu/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android" +        xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +        <string name="clock_default_description" msgid="5309401440896597541">"Okuzenzakalelayo kwedijithali"</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values/dimens.xml b/packages/SystemUI/customization/res/values/dimens.xml index 8eb8132b07b9..c574d1fc674b 100644 --- a/packages/SystemUI/customization/res/values/dimens.xml +++ b/packages/SystemUI/customization/res/values/dimens.xml @@ -17,6 +17,7 @@  -->  <resources>      <!-- Clock maximum font size (dp is intentional, to prevent any further scaling) --> +    <dimen name="presentation_clock_text_size">50dp</dimen>      <dimen name="large_clock_text_size">150dp</dimen>      <dimen name="small_clock_text_size">86dp</dimen> diff --git a/packages/SystemUI/customization/res/values/strings.xml b/packages/SystemUI/customization/res/values/strings.xml new file mode 100644 index 000000000000..897c842b6d4b --- /dev/null +++ b/packages/SystemUI/customization/res/values/strings.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2023, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +    <!-- default clock face name [CHAR LIMIT=NONE]--> +    <string name="clock_default_name">Default</string> + +    <!-- default clock face description [CHAR LIMIT=NONE]--> +    <string name="clock_default_description">Digital default</string> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt index b28920c590c5..b076b2cacf08 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt @@ -65,7 +65,13 @@ class DefaultClockController(      protected var onSecondaryDisplay: Boolean = false      override val events: DefaultClockEvents -    override val config = ClockConfig(DEFAULT_CLOCK_ID) +    override val config: ClockConfig by lazy { +        ClockConfig( +            DEFAULT_CLOCK_ID, +            resources.getString(R.string.clock_default_name), +            resources.getString(R.string.clock_default_description) +        ) +    }      init {          val parent = FrameLayout(ctx) diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt index 949641a7f75e..dd52e39488ac 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt @@ -25,7 +25,6 @@ import com.android.systemui.plugins.ClockProvider  import com.android.systemui.plugins.ClockSettings  private val TAG = DefaultClockProvider::class.simpleName -const val DEFAULT_CLOCK_NAME = "Default Clock"  const val DEFAULT_CLOCK_ID = "DEFAULT"  /** Provides the default system clock */ @@ -35,8 +34,7 @@ class DefaultClockProvider(      val resources: Resources,      val hasStepClockAnimation: Boolean = false  ) : ClockProvider { -    override fun getClocks(): List<ClockMetadata> = -        listOf(ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME)) +    override fun getClocks(): List<ClockMetadata> = listOf(ClockMetadata(DEFAULT_CLOCK_ID))      override fun createClock(settings: ClockSettings): ClockController {          if (settings.clockId != DEFAULT_CLOCK_ID) { diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt index e2f4793b8f91..485c27e16150 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt @@ -192,15 +192,18 @@ enum class ClockTickRate(val value: Int) {  /** Some data about a clock design */  data class ClockMetadata(      val clockId: ClockId, -    val name: String, -) { -    constructor(clockId: ClockId) : this(clockId, clockId) {} -} +)  /** Render configuration for the full clock. Modifies the way systemUI behaves with this clock. */  data class ClockConfig(      val id: String, +    /** Localized name of the clock */ +    val name: String, + +    /** Localized accessibility description for the clock */ +    val description: String, +      /** Transition to AOD should move smartspace like large clock instead of small clock */      val useAlternateSmartspaceAODTransition: Boolean = false, diff --git a/packages/SystemUI/res-keyguard/layout/alternate_bouncer.xml b/packages/SystemUI/res-keyguard/layout/alternate_bouncer.xml new file mode 100644 index 000000000000..218735229a5d --- /dev/null +++ b/packages/SystemUI/res-keyguard/layout/alternate_bouncer.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?><!-- +  ~ Copyright (C) 2023 The Android Open Source Project +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~      http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  ~ See the License for the specific language governing permissions and +  ~ limitations under the License. +  ~ +  --> + +<FrameLayout +    xmlns:android="http://schemas.android.com/apk/res/android" +    xmlns:sysui="http://schemas.android.com/apk/res-auto" +    android:id="@+id/alternate_bouncer" +    android:focusable="true" +    android:clickable="true" +    android:layout_width="match_parent" +    android:layout_height="match_parent"> + +    <com.android.systemui.scrim.ScrimView +        android:id="@+id/alternate_bouncer_scrim" +        android:layout_width="match_parent" +        android:layout_height="match_parent" +        android:importantForAccessibility="no" +        sysui:ignoreRightInset="true" +    /> +</FrameLayout> diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_presentation.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_presentation.xml index 593f507f3c88..f68ab8110b6d 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_presentation.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_presentation.xml @@ -16,22 +16,30 @@  */  --> -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" +<androidx.constraintlayout.widget.ConstraintLayout +    xmlns:android="http://schemas.android.com/apk/res/android" +    xmlns:app="http://schemas.android.com/apk/res-auto"      android:id="@+id/presentation"      android:layout_width="match_parent"      android:layout_height="match_parent">      <com.android.keyguard.KeyguardStatusView          android:id="@+id/clock" -        android:layout_width="410dp" -        android:layout_height="wrap_content" +        android:layout_width="0dp" +        android:layout_height="0dp"          android:layout_gravity="center" -        android:orientation="vertical"> +        android:orientation="vertical" +        app:layout_constraintBottom_toBottomOf="parent" +        app:layout_constraintDimensionRatio="1:1" +        app:layout_constraintEnd_toEndOf="parent" +        app:layout_constraintStart_toStartOf="parent" +        app:layout_constraintTop_toTopOf="parent"> +          <include              android:id="@+id/keyguard_clock_container"              layout="@layout/keyguard_clock_switch"              android:layout_width="match_parent" -            android:layout_height="wrap_content" /> +            android:layout_height="wrap_content"/>      </com.android.keyguard.KeyguardStatusView> -</FrameLayout> +</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml index d4b73a4e3de0..acee4258b64d 100644 --- a/packages/SystemUI/res/layout/super_notification_shade.xml +++ b/packages/SystemUI/res/layout/super_notification_shade.xml @@ -130,6 +130,11 @@          android:inflatedId="@+id/multi_shade"          android:layout="@layout/multi_shade" /> +    <include layout="@layout/alternate_bouncer" +        android:layout_width="match_parent" +        android:layout_height="match_parent" +        android:visibility="invisible" /> +      <com.android.systemui.biometrics.AuthRippleView          android:id="@+id/auth_ripple"          android:layout_width="match_parent" diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt b/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt new file mode 100644 index 000000000000..57a49c83ae17 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.dagger.qualifiers + +import java.lang.annotation.Documented +import java.lang.annotation.Retention +import java.lang.annotation.RetentionPolicy.RUNTIME +import javax.inject.Qualifier + +/** Annotates a class that is display specific. */ +@Qualifier @Documented @Retention(RUNTIME) annotation class DisplaySpecific diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java index 0094820f0dad..a6e04cec5f86 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java @@ -23,6 +23,7 @@ import android.view.SurfaceControl;  import android.window.PictureInPictureSurfaceTransaction;  import android.window.TaskSnapshot; +import com.android.internal.os.IResultReceiver;  import com.android.systemui.shared.recents.model.ThumbnailData;  public class RecentsAnimationControllerCompat { @@ -89,11 +90,16 @@ public class RecentsAnimationControllerCompat {       * @param sendUserLeaveHint determines whether userLeaveHint will be set true to the previous       *                          app.       */ -    public void finish(boolean toHome, boolean sendUserLeaveHint) { +    public void finish(boolean toHome, boolean sendUserLeaveHint, IResultReceiver finishCb) {          try { -            mAnimationController.finish(toHome, sendUserLeaveHint); +            mAnimationController.finish(toHome, sendUserLeaveHint, finishCb);          } catch (RemoteException e) {              Log.e(TAG, "Failed to finish recents animation", e); +            try { +                finishCb.send(0, null); +            } catch (Exception ex) { +                // Local call, can ignore +            }          }      } diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index 2f3c1f263782..eb7a7358cbf1 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -205,19 +205,19 @@ constructor(      private var isRegistered = false      private var disposableHandle: DisposableHandle? = null      private val regionSamplingEnabled = featureFlags.isEnabled(REGION_SAMPLING) - +    private var largeClockOnSecondaryDisplay = false      private fun updateColors() {          if (regionSamplingEnabled) {              clock?.let { clock ->                  smallRegionSampler?.let { -                    smallClockIsDark = it.currentRegionDarkness().isDark -                    clock.smallClock.events.onRegionDarknessChanged(smallClockIsDark) +                    val isRegionDark = it.currentRegionDarkness().isDark +                    clock.smallClock.events.onRegionDarknessChanged(isRegionDark)                  }                  largeRegionSampler?.let { -                    largeClockIsDark = it.currentRegionDarkness().isDark -                    clock.largeClock.events.onRegionDarknessChanged(largeClockIsDark) +                    val isRegionDark = it.currentRegionDarkness().isDark +                    clock.largeClock.events.onRegionDarknessChanged(isRegionDark)                  }              }              return @@ -225,12 +225,12 @@ constructor(          val isLightTheme = TypedValue()          context.theme.resolveAttribute(android.R.attr.isLightTheme, isLightTheme, true) -        smallClockIsDark = isLightTheme.data == 0 -        largeClockIsDark = isLightTheme.data == 0 +        val isRegionDark = isLightTheme.data == 0          clock?.run { -            smallClock.events.onRegionDarknessChanged(smallClockIsDark) -            largeClock.events.onRegionDarknessChanged(largeClockIsDark) +            Log.i(TAG, "Region isDark: $isRegionDark") +            smallClock.events.onRegionDarknessChanged(isRegionDark) +            largeClock.events.onRegionDarknessChanged(isRegionDark)          }      }      protected open fun createRegionSampler( @@ -260,9 +260,6 @@ constructor(          get() = isKeyguardVisible && dozeAmount < DOZE_TICKRATE_THRESHOLD      private var cachedWeatherData: WeatherData? = null -    private var smallClockIsDark = true -    private var largeClockIsDark = true -      private val configListener =          object : ConfigurationController.ConfigurationListener {              override fun onThemeChanged() { @@ -381,6 +378,19 @@ constructor(                  ?.removeOnAttachStateChangeListener(largeClockOnAttachStateChangeListener)      } +    /** +     * Sets this clock as showing in a secondary display. +     * +     * Not that this is not necessarily needed, as we could get the displayId from [Context] +     * directly and infere [largeClockOnSecondaryDisplay] from the id being different than the +     * default display one. However, if we do so, current screenshot tests would not work, as they +     * pass an activity context always from the default display. +     */ +    fun setLargeClockOnSecondaryDisplay(onSecondaryDisplay: Boolean) { +        largeClockOnSecondaryDisplay = onSecondaryDisplay +        updateFontSizes() +    } +      private fun updateTimeListeners() {          smallTimeListener?.stop()          largeTimeListener?.stop() @@ -403,9 +413,15 @@ constructor(              smallClock.events.onFontSettingChanged(                  resources.getDimensionPixelSize(R.dimen.small_clock_text_size).toFloat()              ) -            largeClock.events.onFontSettingChanged( -                resources.getDimensionPixelSize(R.dimen.large_clock_text_size).toFloat() -            ) +            largeClock.events.onFontSettingChanged(getLargeClockSizePx()) +        } +    } + +    private fun getLargeClockSizePx(): Float { +        return if (largeClockOnSecondaryDisplay) { +            resources.getDimensionPixelSize(R.dimen.presentation_clock_text_size).toFloat() +        } else { +            resources.getDimensionPixelSize(R.dimen.large_clock_text_size).toFloat()          }      } diff --git a/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt b/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt index d677a15862de..dec7d7992596 100644 --- a/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt +++ b/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt @@ -68,10 +68,13 @@ constructor(          clock = requireViewById(R.id.clock)          keyguardStatusViewController = -            keyguardStatusViewComponentFactory.build(clock).keyguardStatusViewController.apply { -                setDisplayedOnSecondaryDisplay() -                init() -            } +            keyguardStatusViewComponentFactory +                .build(clock, display) +                .keyguardStatusViewController +                .apply { +                    setDisplayedOnSecondaryDisplay() +                    init() +                }      }      /** [ConnectedDisplayKeyguardPresentation] factory. */ diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index ff8e489528b7..3c8301fe1b26 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -84,7 +84,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS      private final DumpManager mDumpManager;      private final ClockEventController mClockEventController;      private final LogBuffer mLogBuffer; -      private FrameLayout mSmallClockFrame; // top aligned clock      private FrameLayout mLargeClockFrame; // centered clock @@ -265,6 +264,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS          if (mShownOnSecondaryDisplay) {              mView.setLargeClockOnSecondaryDisplay(true); +            mClockEventController.setLargeClockOnSecondaryDisplay(true);              displayClock(LARGE, /* animate= */ false);              hideSliceViewAndNotificationIconContainer();              return; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java index 9c015fea5cf7..8a6f101b6c6c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java @@ -419,7 +419,7 @@ public class KeyguardDisplayManager {              mClock.post(mMoveTextRunnable);              mKeyguardClockSwitchController = mKeyguardStatusViewComponentFactory -                    .build(findViewById(R.id.clock)) +                    .build(findViewById(R.id.clock), getDisplay())                      .getKeyguardClockSwitchController();              mKeyguardClockSwitchController.setOnlyClock(true); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java index 51c0676876b9..50be97ec1af9 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java @@ -139,7 +139,7 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {              case PROMPT_REASON_USER_REQUEST:                  return R.string.kg_prompt_after_user_lockdown_password;              case PROMPT_REASON_PREPARE_FOR_UPDATE: -                return R.string.kg_prompt_unattended_update_password; +                return R.string.kg_prompt_reason_timeout_password;              case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:                  return R.string.kg_prompt_reason_timeout_password;              case PROMPT_REASON_TRUSTAGENT_EXPIRED: diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java index 714ba81fc664..57151ae32db0 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java @@ -321,7 +321,7 @@ public class KeyguardPatternViewController                  resId = R.string.kg_prompt_after_user_lockdown_pattern;                  break;              case PROMPT_REASON_PREPARE_FOR_UPDATE: -                resId = R.string.kg_prompt_unattended_update_pattern; +                resId = R.string.kg_prompt_reason_timeout_pattern;                  break;              case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:                  resId = R.string.kg_prompt_reason_timeout_pattern; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java index 9d6d0332b96b..681aa70402bd 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java @@ -123,7 +123,7 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView              case PROMPT_REASON_USER_REQUEST:                  return R.string.kg_prompt_after_user_lockdown_pin;              case PROMPT_REASON_PREPARE_FOR_UPDATE: -                return R.string.kg_prompt_unattended_update_pin; +                return R.string.kg_prompt_reason_timeout_pin;              case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:                  return R.string.kg_prompt_reason_timeout_pin;              case PROMPT_REASON_TRUSTAGENT_EXPIRED: diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java index 1d2d77f16b75..40d0be1173fa 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java @@ -18,6 +18,7 @@ package com.android.keyguard;  import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import android.annotation.SuppressLint;  import android.content.Context;  import android.content.res.ColorStateList;  import android.graphics.Color; @@ -68,6 +69,7 @@ public class LockIconView extends FrameLayout implements Dumpable {      private boolean mUseBackground = false;      private float mDozeAmount = 0f; +    @SuppressLint("ClickableViewAccessibility")      public LockIconView(Context context, AttributeSet attrs) {          super(context, attrs);          mSensorRect = new RectF(); diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 9b00b5f2aaf2..0d3f726b011b 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -29,6 +29,7 @@ import static com.android.systemui.flags.Flags.NEW_AOD_TRANSITION;  import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;  import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; +import android.annotation.SuppressLint;  import android.content.Context;  import android.content.res.Configuration;  import android.content.res.Resources; @@ -57,11 +58,11 @@ import androidx.annotation.VisibleForTesting;  import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;  import com.android.systemui.Dumpable; -import com.android.systemui.res.R;  import com.android.systemui.biometrics.AuthController;  import com.android.systemui.biometrics.AuthRippleController;  import com.android.systemui.biometrics.UdfpsController;  import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams; +import com.android.systemui.bouncer.domain.interactor.BouncerInteractor;  import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;  import com.android.systemui.dagger.SysUISingleton;  import com.android.systemui.dagger.qualifiers.Main; @@ -73,12 +74,16 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac  import com.android.systemui.keyguard.shared.model.TransitionStep;  import com.android.systemui.plugins.FalsingManager;  import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.res.R; +import com.android.systemui.scene.shared.flag.SceneContainerFlags;  import com.android.systemui.statusbar.StatusBarState;  import com.android.systemui.statusbar.VibratorHelper;  import com.android.systemui.statusbar.policy.ConfigurationController;  import com.android.systemui.statusbar.policy.KeyguardStateController;  import com.android.systemui.util.concurrency.DelayableExecutor; +import dagger.Lazy; +  import java.io.PrintWriter;  import java.util.Objects;  import java.util.function.Consumer; @@ -127,6 +132,8 @@ public class LockIconViewController implements Dumpable {      @NonNull private final KeyguardTransitionInteractor mTransitionInteractor;      @NonNull private final KeyguardInteractor mKeyguardInteractor;      @NonNull private final View.AccessibilityDelegate mAccessibilityDelegate; +    @NonNull private final Lazy<BouncerInteractor> mBouncerInteractor; +    @NonNull private final SceneContainerFlags mSceneContainerFlags;      // Tracks the velocity of a touch to help filter out the touches that move too fast.      private VelocityTracker mVelocityTracker; @@ -203,7 +210,9 @@ public class LockIconViewController implements Dumpable {              @NonNull KeyguardInteractor keyguardInteractor,              @NonNull FeatureFlags featureFlags,              PrimaryBouncerInteractor primaryBouncerInteractor, -            Context context +            Context context, +            Lazy<BouncerInteractor> bouncerInteractor, +            SceneContainerFlags sceneContainerFlags      ) {          mStatusBarStateController = statusBarStateController;          mKeyguardUpdateMonitor = keyguardUpdateMonitor; @@ -232,6 +241,8 @@ public class LockIconViewController implements Dumpable {          dumpManager.registerDumpable(TAG, this);          mResources = resources;          mContext = context; +        mBouncerInteractor = bouncerInteractor; +        mSceneContainerFlags = sceneContainerFlags;          mAccessibilityDelegate = new View.AccessibilityDelegate() {              private final AccessibilityNodeInfo.AccessibilityAction mAccessibilityAuthenticateHint = @@ -256,6 +267,7 @@ public class LockIconViewController implements Dumpable {      }      /** Sets the LockIconView to the controller and rebinds any that depend on it. */ +    @SuppressLint("ClickableViewAccessibility")      public void setLockIconView(LockIconView lockIconView) {          mView = lockIconView;          mView.setImageDrawable(mIcon); @@ -305,6 +317,8 @@ public class LockIconViewController implements Dumpable {          if (lockIconView.isAttachedToWindow()) {              registerCallbacks();          } + +        lockIconView.setOnTouchListener((view, motionEvent) -> onTouchEvent(motionEvent));      }      private void registerCallbacks() { @@ -635,19 +649,18 @@ public class LockIconViewController implements Dumpable {      };      /** -     * Handles the touch if it is within the lock icon view and {@link #isActionable()} is true. +     * Handles the touch if {@link #isActionable()} is true.       * Subsequently, will trigger {@link #onLongPress()} if a touch is continuously in the lock icon       * area for {@link #mLongPressTimeout} ms.       *       * Touch speed debouncing mimics logic from the velocity tracker in {@link UdfpsController}.       */ -    public boolean onTouchEvent(MotionEvent event, Runnable onGestureDetectedRunnable) { -        if (!onInterceptTouchEvent(event)) { +    private boolean onTouchEvent(MotionEvent event) { +        if (!actionableDownEventStartedOnView(event)) {              cancelTouches();              return false;          } -        mOnGestureDetectedRunnable = onGestureDetectedRunnable;          switch(event.getActionMasked()) {              case MotionEvent.ACTION_DOWN:              case MotionEvent.ACTION_HOVER_ENTER: @@ -700,12 +713,8 @@ public class LockIconViewController implements Dumpable {          return true;      } -    /** -     * Intercepts the touch if the onDown event and current event are within this lock icon view's -     * bounds. -     */ -    public boolean onInterceptTouchEvent(MotionEvent event) { -        if (!inLockIconArea(event) || !isActionable()) { +    private boolean actionableDownEventStartedOnView(MotionEvent event) { +        if (!isActionable()) {              return false;          } @@ -716,7 +725,8 @@ public class LockIconViewController implements Dumpable {          return mDownDetected;      } -    private void onLongPress() { +    @VisibleForTesting +    protected void onLongPress() {          cancelTouches();          if (mFalsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)) {              Log.v(TAG, "lock icon long-press rejected by the falsing manager."); @@ -729,14 +739,15 @@ public class LockIconViewController implements Dumpable {              mAuthRippleController.showUnlockRipple(FINGERPRINT);          }          updateVisibility(); -        if (mOnGestureDetectedRunnable != null) { -            mOnGestureDetectedRunnable.run(); -        }          // play device entry haptic (consistent with UDFPS controller longpress)          vibrateOnLongPress(); -        mKeyguardViewController.showPrimaryBouncer(/* scrim */ true); +        if (mSceneContainerFlags.isEnabled()) { +            mBouncerInteractor.get().showOrUnlockDevice(null); +        } else { +            mKeyguardViewController.showPrimaryBouncer(/* scrim */ true); +        }      } @@ -751,12 +762,6 @@ public class LockIconViewController implements Dumpable {          }      } -    private boolean inLockIconArea(MotionEvent event) { -        mView.getHitRect(mSensorTouchLocation); -        return mSensorTouchLocation.contains((int) event.getX(), (int) event.getY()) -                && mView.getVisibility() == View.VISIBLE; -    } -      private boolean isActionable() {          if (mIsBouncerShowing) {              Log.v(TAG, "lock icon long-press ignored, bouncer already showing."); @@ -834,6 +839,19 @@ public class LockIconViewController implements Dumpable {          }      }; +    /** +     * Whether the lock icon will handle a touch while dozing. +     */ +    public boolean willHandleTouchWhileDozing(MotionEvent event) { +        // is in lock icon area +        mView.getHitRect(mSensorTouchLocation); +        final boolean inLockIconArea = +                mSensorTouchLocation.contains((int) event.getX(), (int) event.getY()) +                        && mView.getVisibility() == View.VISIBLE; + +        return inLockIconArea && actionableDownEventStartedOnView(event); +    } +      private final View.OnClickListener mA11yClickListener = v -> onLongPress();      private final AccessibilityManager.AccessibilityStateChangeListener diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardDisplayModule.kt b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardDisplayModule.kt new file mode 100644 index 000000000000..c5817881718b --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardDisplayModule.kt @@ -0,0 +1,40 @@ +package com.android.keyguard.dagger + +import android.content.Context +import android.content.res.Resources +import android.view.Display +import com.android.systemui.dagger.qualifiers.DisplaySpecific +import dagger.BindsOptionalOf +import dagger.Module +import dagger.Provides +import java.util.Optional + +/** + * Binds display specific context and resources. + * + * When a [Display] is available in the scope, binds a [DisplaySpecific] [Context] and [Resources]. + * When not available, the default display context and resources are used. + */ +@Module +abstract class KeyguardDisplayModule { + +    @BindsOptionalOf abstract fun optionalDisplay(): Display + +    companion object { +        @Provides +        @DisplaySpecific +        fun getDisplayContext(context: Context, display: Optional<Display>): Context { +            return if (display.isPresent) { +                context.createDisplayContext(display.get()) +            } else { +                context +            } +        } + +        @Provides +        @DisplaySpecific +        fun getDisplayResources(@DisplaySpecific context: Context): Resources { +            return context.resources +        } +    } +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java index d342377da49b..f3014f1ecc58 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java @@ -16,6 +16,8 @@  package com.android.keyguard.dagger; +import android.view.Display; +  import com.android.keyguard.KeyguardClockSwitchController;  import com.android.keyguard.KeyguardStatusView;  import com.android.keyguard.KeyguardStatusViewController; @@ -28,13 +30,17 @@ import dagger.Subcomponent;   *   * TODO: unify this with {@link KeyguardStatusBarViewComponent}   */ -@Subcomponent(modules = {KeyguardStatusViewModule.class}) +@Subcomponent(modules = {KeyguardStatusViewModule.class, KeyguardDisplayModule.class})  @KeyguardStatusViewScope  public interface KeyguardStatusViewComponent {      /** Simple factory for {@link KeyguardStatusViewComponent}. */      @Subcomponent.Factory      interface Factory { -        KeyguardStatusViewComponent build(@BindsInstance KeyguardStatusView presentation); +        /** Creates {@link KeyguardStatusViewComponent} for a given display. */ +        KeyguardStatusViewComponent build( +                @BindsInstance KeyguardStatusView presentation, +                @BindsInstance Display display +        );      }      /** Builds a {@link com.android.keyguard.KeyguardClockSwitchController}. */ diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 018038423d4e..7739021bad33 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -87,7 +87,6 @@ import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;  import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;  import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;  import com.android.systemui.statusbar.notification.logging.NotificationLogger; -import com.android.systemui.statusbar.notification.row.NotificationGutsManager;  import com.android.systemui.statusbar.notification.stack.AmbientState;  import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager;  import com.android.systemui.statusbar.phone.AutoHideController; @@ -130,14 +129,14 @@ import com.android.systemui.util.leak.LeakDetector;  import com.android.systemui.util.leak.LeakReporter;  import com.android.systemui.util.sensors.AsyncSensorManager; +import dagger.Lazy; +  import java.util.concurrent.Executor;  import java.util.function.Consumer;  import javax.inject.Inject;  import javax.inject.Named; -import dagger.Lazy; -  /**   * Class to handle ugly dependencies throughout sysui until we determine the   * long-term dependency injection solution. @@ -298,7 +297,6 @@ public class Dependency {      @Inject Lazy<AccessibilityFloatingMenuController> mAccessibilityFloatingMenuController;      @Inject Lazy<StatusBarStateController> mStatusBarStateController;      @Inject Lazy<NotificationLockscreenUserManager> mNotificationLockscreenUserManager; -    @Inject Lazy<NotificationGutsManager> mNotificationGutsManager;      @Inject Lazy<NotificationMediaManager> mNotificationMediaManager;      @Inject Lazy<NotificationRemoteInputManager> mNotificationRemoteInputManager;      @Inject Lazy<SmartReplyConstants> mSmartReplyConstants; @@ -498,7 +496,6 @@ public class Dependency {          mProviders.put(NotificationLockscreenUserManager.class,                  mNotificationLockscreenUserManager::get);          mProviders.put(NotificationMediaManager.class, mNotificationMediaManager::get); -        mProviders.put(NotificationGutsManager.class, mNotificationGutsManager::get);          mProviders.put(NotificationRemoteInputManager.class,                  mNotificationRemoteInputManager::get);          mProviders.put(SmartReplyConstants.class, mSmartReplyConstants::get); diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModel.kt index 4efc21b41e6a..4b78e9eeb265 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModel.kt @@ -35,10 +35,8 @@ import com.android.systemui.bouncer.ui.viewmodel.EntryToken.Digit   * The input is guaranteed to always contain a initial [ClearAll] token as a sentinel, thus clients   * can always assume there is a 'ClearAll' watermark available.   */ -data class PinInputViewModel -internal constructor( -    @get:VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) -    internal val input: List<EntryToken> +data class PinInputViewModel( +    @get:VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) val input: List<EntryToken>  ) {      init {          require(input.firstOrNull() is ClearAll) { "input does not begin with a ClearAll token" } @@ -132,8 +130,7 @@ sealed interface EntryToken : Comparable<EntryToken> {      val sequenceNumber: Int      /** The pin bouncer [input] as digits 0-9. */ -    data class Digit -    internal constructor(val input: Int, override val sequenceNumber: Int = nextSequenceNumber++) : +    data class Digit(val input: Int, override val sequenceNumber: Int = nextSequenceNumber++) :          EntryToken {          init {              check(input in 0..9) @@ -144,8 +141,7 @@ sealed interface EntryToken : Comparable<EntryToken> {       * Marker to indicate the input is completely cleared, and subsequent [EntryToken]s mark a new       * pin entry.       */ -    data class ClearAll -    internal constructor(override val sequenceNumber: Int = nextSequenceNumber++) : EntryToken +    data class ClearAll(override val sequenceNumber: Int = nextSequenceNumber++) : EntryToken      override fun compareTo(other: EntryToken): Int =          compareValuesBy(this, other, EntryToken::sequenceNumber) diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java index c0ee71cf0dc8..0dfaf0f4318d 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java @@ -18,8 +18,15 @@ package com.android.systemui.classifier;  import android.view.MotionEvent; +import javax.inject.Inject; +  /** */  public class FalsingCollectorFake implements FalsingCollector { + +    @Inject +    public FalsingCollectorFake() { +    } +      @Override      public void onSuccessfulUnlock() {      } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java index 046ccf165d07..a90980fddfb0 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java @@ -18,7 +18,6 @@ package com.android.systemui.dagger;  import com.android.systemui.globalactions.ShutdownUiModule;  import com.android.systemui.keyguard.CustomizationProvider; -import com.android.systemui.shade.ShadeModule;  import com.android.systemui.statusbar.NotificationInsetsModule;  import com.android.systemui.statusbar.QsFrameTranslateModule; @@ -33,7 +32,6 @@ import dagger.Subcomponent;          DependencyProvider.class,          NotificationInsetsModule.class,          QsFrameTranslateModule.class, -        ShadeModule.class,          ShutdownUiModule.class,          SystemUIBinder.class,          SystemUIModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java index 9e5fd5572dbc..1dd4abfa0767 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java @@ -21,12 +21,9 @@ import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME;  import android.content.Context;  import android.hardware.SensorPrivacyManager; -import android.os.Handler; -import com.android.internal.logging.UiEventLogger;  import com.android.keyguard.KeyguardViewController;  import com.android.systemui.battery.BatterySaverModule; -import com.android.systemui.dagger.qualifiers.Main;  import com.android.systemui.dock.DockManager;  import com.android.systemui.dock.DockManagerImpl;  import com.android.systemui.doze.DozeHost; @@ -34,7 +31,6 @@ import com.android.systemui.media.dagger.MediaModule;  import com.android.systemui.navigationbar.NavigationBarControllerModule;  import com.android.systemui.navigationbar.gestural.GestureModule;  import com.android.systemui.plugins.qs.QSFactory; -import com.android.systemui.plugins.statusbar.StatusBarStateController;  import com.android.systemui.power.dagger.PowerModule;  import com.android.systemui.qs.dagger.QSModule;  import com.android.systemui.qs.tileimpl.QSFactoryImpl; @@ -45,7 +41,7 @@ import com.android.systemui.scene.SceneContainerFrameworkModule;  import com.android.systemui.screenshot.ReferenceScreenshotModule;  import com.android.systemui.settings.dagger.MultiUserUtilsModule;  import com.android.systemui.shade.NotificationShadeWindowControllerImpl; -import com.android.systemui.shade.ShadeExpansionStateManager; +import com.android.systemui.shade.ShadeModule;  import com.android.systemui.statusbar.CommandQueue;  import com.android.systemui.statusbar.KeyboardShortcutsModule;  import com.android.systemui.statusbar.NotificationLockscreenUserManager; @@ -53,20 +49,13 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;  import com.android.systemui.statusbar.NotificationShadeWindowController;  import com.android.systemui.statusbar.dagger.StartCentralSurfacesModule;  import com.android.systemui.statusbar.events.StatusBarEventsModule; -import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider; -import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;  import com.android.systemui.statusbar.phone.DozeServiceHost; -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; -import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.phone.HeadsUpModule;  import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;  import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentStartableModule; -import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;  import com.android.systemui.statusbar.policy.AospPolicyModule; -import com.android.systemui.statusbar.policy.ConfigurationController;  import com.android.systemui.statusbar.policy.DeviceProvisionedController;  import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl; -import com.android.systemui.statusbar.policy.HeadsUpManager; -import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;  import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;  import com.android.systemui.statusbar.policy.IndividualSensorPrivacyControllerImpl;  import com.android.systemui.statusbar.policy.SensorPrivacyController; @@ -100,11 +89,13 @@ import javax.inject.Named;          BatterySaverModule.class,          CollapsedStatusBarFragmentStartableModule.class,          GestureModule.class, +        HeadsUpModule.class,          MediaModule.class,          MultiUserUtilsModule.class,          NavigationBarControllerModule.class,          PowerModule.class,          QSModule.class, +        ShadeModule.class,          ReferenceScreenshotModule.class,          RotationLockModule.class,          SceneContainerFrameworkModule.class, @@ -161,38 +152,6 @@ public abstract class ReferenceSystemUIModule {          return true;      } -    @SysUISingleton -    @Provides -    static HeadsUpManagerPhone provideHeadsUpManagerPhone( -            Context context, -            HeadsUpManagerLogger headsUpManagerLogger, -            StatusBarStateController statusBarStateController, -            KeyguardBypassController bypassController, -            GroupMembershipManager groupManager, -            VisualStabilityProvider visualStabilityProvider, -            ConfigurationController configurationController, -            @Main Handler handler, -            AccessibilityManagerWrapper accessibilityManagerWrapper, -            UiEventLogger uiEventLogger, -            ShadeExpansionStateManager shadeExpansionStateManager) { -        return new HeadsUpManagerPhone( -                context, -                headsUpManagerLogger, -                statusBarStateController, -                bypassController, -                groupManager, -                visualStabilityProvider, -                configurationController, -                handler, -                accessibilityManagerWrapper, -                uiEventLogger, -                shadeExpansionStateManager -        ); -    } - -    @Binds -    abstract HeadsUpManager bindHeadsUpManagerPhone(HeadsUpManagerPhone headsUpManagerPhone); -      @Provides      @SysUISingleton      static Recents provideRecents(Context context, RecentsImplementation recentsImplementation, diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt index d89332d6d686..5d6949b3e87f 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt @@ -37,6 +37,7 @@ import com.android.systemui.keyboard.PhysicalKeyboardCoreStartable  import com.android.systemui.keyguard.KeyguardViewConfigurator  import com.android.systemui.keyguard.KeyguardViewMediator  import com.android.systemui.keyguard.data.quickaffordance.MuteQuickAffordanceCoreStartable +import com.android.systemui.keyguard.ui.binder.AlternateBouncerBinder  import com.android.systemui.keyguard.ui.binder.KeyguardDismissActionBinder  import com.android.systemui.keyguard.ui.binder.KeyguardDismissBinder  import com.android.systemui.log.SessionTracker @@ -92,6 +93,11 @@ abstract class SystemUICoreStartableModule {      @ClassKey(AuthController::class)      abstract fun bindAuthController(service: AuthController): CoreStartable +    @Binds +    @IntoMap +    @ClassKey(AlternateBouncerBinder::class) +    abstract fun bindAlternateBouncerBinder(impl: AlternateBouncerBinder): CoreStartable +      /** Inject into BiometricNotificationService */      @Binds      @IntoMap diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt index 5b85ad01301b..1e29e1fa3197 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepository.kt @@ -2,7 +2,7 @@ package com.android.systemui.deviceentry.data.repository  import com.android.internal.widget.LockPatternUtils  import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow +import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.dagger.qualifiers.Background @@ -51,7 +51,7 @@ interface DeviceEntryRepository {       * When this is `false`, an automatically-triggered face unlock shouldn't automatically dismiss       * the lockscreen.       */ -    fun isBypassEnabled(): Boolean +    val isBypassEnabled: StateFlow<Boolean>  }  /** Encapsulates application state for device entry. */ @@ -68,7 +68,7 @@ constructor(  ) : DeviceEntryRepository {      override val isUnlocked = -        ConflatedCallbackFlow.conflatedCallbackFlow { +        conflatedCallbackFlow {                  val callback =                      object : KeyguardStateController.Callback {                          override fun onUnlockedChanged() { @@ -112,7 +112,24 @@ constructor(          }      } -    override fun isBypassEnabled() = keyguardBypassController.bypassEnabled +    override val isBypassEnabled: StateFlow<Boolean> = +        conflatedCallbackFlow { +                val listener = +                    object : KeyguardBypassController.OnBypassStateChangedListener { +                        override fun onBypassStateChanged(isEnabled: Boolean) { +                            trySend(isEnabled) +                        } +                    } +                keyguardBypassController.registerOnBypassStateChangedListener(listener) +                awaitClose { +                    keyguardBypassController.unregisterOnBypassStateChangedListener(listener) +                } +            } +            .stateIn( +                applicationScope, +                SharingStarted.Eagerly, +                initialValue = keyguardBypassController.bypassEnabled, +            )      companion object {          private const val TAG = "DeviceEntryRepositoryImpl" diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt index 5612c9a488ff..e96e318fd59d 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt @@ -106,5 +106,5 @@ constructor(       * authentication challenge via face unlock or fingerprint sensor can automatically bypass the       * lock screen.       */ -    fun isBypassEnabled() = repository.isBypassEnabled() +    val isBypassEnabled: StateFlow<Boolean> = repository.isBypassEnabled  } diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index bdd245ed7b7f..f6f24e0aecc0 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -144,11 +144,6 @@ object Flags {              "lockscreen_custom_clocks"          ) -    // TODO(b/275694445): Tracking Bug -    @JvmField -    val LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING = -        releasedFlag("lockscreen_without_secure_lock_when_dreaming") -      // TODO(b/286092087): Tracking Bug      @JvmField      val ENABLE_SYSTEM_UI_DREAM_CONTROLLER = unreleasedFlag("enable_system_ui_dream_controller") @@ -234,8 +229,7 @@ object Flags {      /** Whether page transition animations in the wallpaper picker are enabled */      // TODO(b/291710220): Tracking bug.      @JvmField -    val WALLPAPER_PICKER_PAGE_TRANSITIONS = -        unreleasedFlag("wallpaper_picker_page_transitions", teamfood = true) +    val WALLPAPER_PICKER_PAGE_TRANSITIONS = releasedFlag("wallpaper_picker_page_transitions")      /** Add "Apply" button to wall paper picker's grid preview page. */      // TODO(b/294866904): Tracking bug. @@ -310,6 +304,11 @@ object Flags {      @JvmField      val WALLPAPER_PICKER_PREVIEW_ANIMATION = releasedFlag("wallpaper_picker_preview_animation") +    /** Flag to enable rest to unlock feature. */ +    // TODO(b/303672286): Tracking bug +    @JvmField +    val REST_TO_UNLOCK: UnreleasedFlag = unreleasedFlag("rest_to_unlock") +      /**       * TODO(b/278086361): Tracking bug       * Complete rewrite of the interactions between System UI and Window Manager involving keyguard @@ -332,7 +331,7 @@ object Flags {      /** Flag to use a separate view for the alternate bouncer. */      // TODO(b/300440924): Tracking bug      @JvmField -    val ALTERNATE_BOUNCER_REFACTOR: UnreleasedFlag = unreleasedFlag("alternate_bouncer_view") +    val ALTERNATE_BOUNCER_VIEW: UnreleasedFlag = unreleasedFlag("alternate_bouncer_view")      // 300 - power menu      // TODO(b/254512600): Tracking Bug diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt index f500017e3a33..86bf368791bc 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt @@ -82,7 +82,8 @@ constructor(                  val statusViewComponent =                      keyguardStatusViewComponentFactory.build(                          LayoutInflater.from(context).inflate(R.layout.keyguard_status_view, null) -                            as KeyguardStatusView +                            as KeyguardStatusView, +                        context.display                      )                  val controller = statusViewComponent.keyguardStatusViewController                  controller.init() diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 7678f4d643ca..39742a02000b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -171,6 +171,8 @@ import com.android.systemui.util.time.SystemClock;  import com.android.systemui.wallpapers.data.repository.WallpaperRepository;  import com.android.wm.shell.keyguard.KeyguardTransitions; +import dagger.Lazy; +  import java.io.PrintWriter;  import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy; @@ -180,7 +182,8 @@ import java.util.Objects;  import java.util.concurrent.Executor;  import java.util.function.Consumer; -import dagger.Lazy; + +  import kotlinx.coroutines.CoroutineDispatcher;  /** @@ -1933,11 +1936,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,      public void onDreamingStarted() {          mUpdateMonitor.dispatchDreamingStarted();          synchronized (this) { -            final boolean alwaysShowKeyguard = -                mFeatureFlags.isEnabled(Flags.LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING); -            if (mDeviceInteractive -                && (alwaysShowKeyguard || -                mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser()))) { +            if (mDeviceInteractive) {                  doKeyguardLaterLocked();              }          } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index 03c166c05a62..41bde91d9a01 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -28,6 +28,7 @@ import com.android.keyguard.KeyguardDisplayManager;  import com.android.keyguard.KeyguardUpdateMonitor;  import com.android.keyguard.KeyguardViewController;  import com.android.keyguard.ViewMediatorCallback; +import com.android.keyguard.dagger.KeyguardDisplayModule;  import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent;  import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;  import com.android.keyguard.dagger.KeyguardStatusViewComponent; @@ -100,6 +101,7 @@ import kotlinx.coroutines.CoroutineDispatcher;              KeyguardDataQuickAffordanceModule.class,              KeyguardRepositoryModule.class,              KeyguardFaceAuthModule.class, +            KeyguardDisplayModule.class,              StartKeyguardTransitionModule.class,              ResourceTrimmerModule.class,          }) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt index 3ccf446fef59..d06f31fed8db 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt @@ -32,6 +32,7 @@ import kotlinx.coroutines.flow.combine  import kotlinx.coroutines.flow.onEach  import kotlinx.coroutines.launch  import javax.inject.Inject +import kotlin.time.Duration.Companion.milliseconds  @SysUISingleton  class FromAlternateBouncerTransitionInteractor @@ -129,11 +130,11 @@ constructor(      override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {          return ValueAnimator().apply {              interpolator = Interpolators.LINEAR -            duration = TRANSITION_DURATION_MS +            duration = TRANSITION_DURATION_MS.inWholeMilliseconds          }      }      companion object { -        private const val TRANSITION_DURATION_MS = 300L +        val TRANSITION_DURATION_MS = 300.milliseconds      }  } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt index e57c919a5b3e..89aca7631934 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt @@ -61,6 +61,7 @@ interface KeyguardFaceAuthInteractor {      fun onSwipeUpOnBouncer()      fun onPrimaryBouncerUserInput()      fun onAccessibilityAction() +    fun onWalletLaunched()  }  /** diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt index d69876292024..ac012f840d1f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt @@ -29,8 +29,10 @@ import com.android.systemui.shade.ShadeController  import com.android.systemui.statusbar.StatusBarState  import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager  import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi  /** Handles key events arriving when the keyguard is showing or device is dozing. */ +@ExperimentalCoroutinesApi  @SysUISingleton  class KeyguardKeyEventInteractor  @Inject @@ -56,7 +58,11 @@ constructor(          if (event.handleAction()) {              when (event.keyCode) {                  KeyEvent.KEYCODE_MENU -> return dispatchMenuKeyEvent() -                KeyEvent.KEYCODE_SPACE -> return dispatchSpaceEvent() +                KeyEvent.KEYCODE_SPACE, +                KeyEvent.KEYCODE_ENTER -> +                    if (isDeviceAwake()) { +                        return collapseShadeLockedOrShowPrimaryBouncer() +                    }              }          }          return false @@ -92,16 +98,24 @@ constructor(                  (statusBarStateController.state != StatusBarState.SHADE) &&                  statusBarKeyguardViewManager.shouldDismissOnMenuPressed()          if (shouldUnlockOnMenuPressed) { -            shadeController.animateCollapseShadeForced() -            return true +            return collapseShadeLockedOrShowPrimaryBouncer()          }          return false      } -    private fun dispatchSpaceEvent(): Boolean { -        if (isDeviceAwake() && statusBarStateController.state != StatusBarState.SHADE) { -            shadeController.animateCollapseShadeForced() -            return true +    private fun collapseShadeLockedOrShowPrimaryBouncer(): Boolean { +        when (statusBarStateController.state) { +            StatusBarState.SHADE -> return false +            StatusBarState.SHADE_LOCKED -> { +                shadeController.animateCollapseShadeForced() +                return true +            } +            StatusBarState.KEYGUARD -> { +                if (!statusBarKeyguardViewManager.primaryBouncerIsShowing()) { +                    statusBarKeyguardViewManager.showPrimaryBouncer(true) +                    return true +                } +            }          }          return false      } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt index 596a1c01ca42..f38bb2b519e7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt @@ -61,4 +61,5 @@ class NoopKeyguardFaceAuthInteractor @Inject constructor() : KeyguardFaceAuthInt      override fun onSwipeUpOnBouncer() {}      override fun onPrimaryBouncerUserInput() {}      override fun onAccessibilityAction() {} +    override fun onWalletLaunched() = Unit  } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt index ef1d5ac2a6d4..797dec2c9625 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt @@ -24,6 +24,7 @@ import com.android.keyguard.KeyguardUpdateMonitor  import com.android.systemui.CoreStartable  import com.android.systemui.biometrics.data.repository.FacePropertyRepository  import com.android.systemui.biometrics.shared.model.LockoutMode +import com.android.systemui.biometrics.shared.model.SensorStrength  import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor  import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor  import com.android.systemui.dagger.SysUISingleton @@ -33,7 +34,6 @@ import com.android.systemui.flags.FeatureFlags  import com.android.systemui.flags.Flags  import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository  import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository -import com.android.systemui.keyguard.data.repository.KeyguardRepository  import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus  import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus  import com.android.systemui.keyguard.shared.model.TransitionState @@ -44,6 +44,7 @@ import com.android.systemui.user.data.model.SelectionStatus  import com.android.systemui.user.data.repository.UserRepository  import com.android.systemui.util.kotlin.pairwise  import com.android.systemui.util.kotlin.sample +import javax.inject.Inject  import kotlinx.coroutines.CoroutineDispatcher  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.flow.Flow @@ -56,7 +57,6 @@ import kotlinx.coroutines.flow.map  import kotlinx.coroutines.flow.merge  import kotlinx.coroutines.flow.onEach  import kotlinx.coroutines.yield -import javax.inject.Inject  /**   * Encapsulates business logic related face authentication being triggered for device entry from @@ -79,7 +79,6 @@ constructor(      private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,      private val userRepository: UserRepository,      private val facePropertyRepository: FacePropertyRepository, -    private val keyguardRepository: KeyguardRepository,      private val faceWakeUpTriggersConfig: FaceWakeUpTriggersConfig,      private val powerInteractor: PowerInteractor,  ) : CoreStartable, KeyguardFaceAuthInteractor { @@ -207,6 +206,12 @@ constructor(          runFaceAuth(FaceAuthUiEvent.FACE_AUTH_ACCESSIBILITY_ACTION, false)      } +    override fun onWalletLaunched() { +        if (facePropertyRepository.sensorInfo.value?.strength == SensorStrength.STRONG) { +            runFaceAuth(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_OCCLUDING_APP_REQUESTED, true) +        } +    } +      override fun registerListener(listener: FaceAuthenticationListener) {          listeners.add(listener)      } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt new file mode 100644 index 000000000000..41af9e810fbf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.binder + +import android.view.View +import android.view.ViewGroup +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.flags.FeatureFlagsClassic +import com.android.systemui.flags.Flags +import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerViewModel +import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.res.R +import com.android.systemui.scrim.ScrimView +import com.android.systemui.shade.NotificationShadeWindowView +import com.android.systemui.statusbar.NotificationShadeWindowController +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.launch +import javax.inject.Inject + +@ExperimentalCoroutinesApi +@SysUISingleton +class AlternateBouncerBinder +@Inject +constructor( +    private val notificationShadeWindowView: NotificationShadeWindowView, +    private val featureFlags: FeatureFlagsClassic, +    private val alternateBouncerViewModel: AlternateBouncerViewModel, +    @Application private val scope: CoroutineScope, +    private val notificationShadeWindowController: NotificationShadeWindowController, +) : CoreStartable { +    override fun start() { +        if (!featureFlags.isEnabled(Flags.ALTERNATE_BOUNCER_VIEW)) { +            return +        } + +        AlternateBouncerViewBinder.bind( +            notificationShadeWindowView.requireViewById(R.id.alternate_bouncer), +            alternateBouncerViewModel, +            scope, +            notificationShadeWindowController, +        ) +    } +} + +/** + * Binds the alternate bouncer view to its view-model. + * + * To use this properly, users should maintain a one-to-one relationship between the [View] and the + * view-binding, binding each view only once. It is okay and expected for the same instance of the + * view-model to be reused for multiple view/view-binder bindings. + */ +@ExperimentalCoroutinesApi +object AlternateBouncerViewBinder { + +    /** Binds the view to the view-model, continuing to update the former based on the latter. */ +    @JvmStatic +    fun bind( +        view: ViewGroup, +        viewModel: AlternateBouncerViewModel, +        scope: CoroutineScope, +        notificationShadeWindowController: NotificationShadeWindowController, +    ) { +        scope.launch { +            // forcePluginOpen is necessary to show over occluded apps. +            // This cannot be tied to the view's lifecycle because setting this allows the view +            // to be started in the first place. +            viewModel.forcePluginOpen.collect { +                notificationShadeWindowController.setForcePluginOpen(it, this) +            } +        } + +        val scrim = view.requireViewById(R.id.alternate_bouncer_scrim) as ScrimView +        view.repeatWhenAttached { alternateBouncerViewContainer -> +            repeatOnLifecycle(Lifecycle.State.STARTED) { +                scrim.viewAlpha = 0f + +                launch { +                    viewModel.onClickListener.collect { +                        // TODO (b/287599719): Support swiping to dismiss altBouncer +                        alternateBouncerViewContainer.setOnClickListener(it) +                    } +                } + +                launch { +                    viewModel.scrimAlpha.collect { +                        alternateBouncerViewContainer.visibility = +                            if (it < .1f) View.INVISIBLE else View.VISIBLE +                        scrim.viewAlpha = it +                    } +                } + +                launch { viewModel.scrimColor.collect { scrim.tint = it } } +            } +        } +    } +} 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 5ae2abaea788..c6d8ec7789f2 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 @@ -27,11 +27,14 @@ import android.hardware.display.DisplayManager  import android.os.Bundle  import android.os.Handler  import android.os.IBinder +import android.view.Display +import android.view.Display.DEFAULT_DISPLAY  import android.view.LayoutInflater  import android.view.SurfaceControlViewHost  import android.view.View  import android.view.ViewGroup  import android.view.WindowManager +import android.view.WindowManager.LayoutParams.TYPE_KEYGUARD  import android.widget.FrameLayout  import androidx.constraintlayout.widget.ConstraintLayout  import androidx.core.view.isInvisible @@ -125,6 +128,8 @@ constructor(      private val shouldHideClock: Boolean =          bundle.getBoolean(ClockPreviewConstants.KEY_HIDE_CLOCK, false)      private val wallpaperColors: WallpaperColors? = bundle.getParcelable(KEY_COLORS) +    private val displayId = bundle.getInt(KEY_DISPLAY_ID, DEFAULT_DISPLAY) +    private val display: Display = displayManager.getDisplay(displayId)      private var host: SurfaceControlViewHost @@ -164,7 +169,7 @@ constructor(              host =                  SurfaceControlViewHost(                      context, -                    displayManager.getDisplay(bundle.getInt(KEY_DISPLAY_ID)), +                    displayManager.getDisplay(DEFAULT_DISPLAY),                      hostToken,                      "KeyguardPreviewRenderer"                  ) @@ -174,21 +179,27 @@ constructor(      fun render() {          mainHandler.post { -            val rootView = FrameLayout(context) +            val previewContext = context.createDisplayContext(display) -            setupKeyguardRootView(rootView) +            val rootView = FrameLayout(previewContext) + +            setupKeyguardRootView(previewContext, rootView)              if (!featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {                  setUpBottomArea(rootView)              } +            val windowContext = context.createWindowContext(display, TYPE_KEYGUARD, null) +            val windowManagerOfDisplay = windowContext.getSystemService(WindowManager::class.java)              rootView.measure(                  View.MeasureSpec.makeMeasureSpec( -                    windowManager.currentWindowMetrics.bounds.width(), +                    windowManagerOfDisplay?.currentWindowMetrics?.bounds?.width() +                        ?: windowManager.currentWindowMetrics.bounds.width(),                      View.MeasureSpec.EXACTLY                  ),                  View.MeasureSpec.makeMeasureSpec( -                    windowManager.currentWindowMetrics.bounds.height(), +                    windowManagerOfDisplay?.currentWindowMetrics?.bounds?.height() +                        ?: windowManager.currentWindowMetrics.bounds.height(),                      View.MeasureSpec.EXACTLY                  ),              ) @@ -251,7 +262,7 @@ constructor(       *       * The end padding is as follows: Below clock padding end       */ -    private fun setUpSmartspace(parentView: ViewGroup) { +    private fun setUpSmartspace(previewContext: Context, parentView: ViewGroup) {          if (              !lockscreenSmartspaceController.isEnabled() ||                  !lockscreenSmartspaceController.isDateWeatherDecoupled() @@ -263,12 +274,12 @@ constructor(          val topPadding: Int =              KeyguardPreviewSmartspaceViewModel.getLargeClockSmartspaceTopPadding( -                context.resources, +                previewContext.resources,              )          val startPadding: Int = -            context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_start) +            previewContext.resources.getDimensionPixelSize(R.dimen.below_clock_padding_start)          val endPadding: Int = -            context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_end) +            previewContext.resources.getDimensionPixelSize(R.dimen.below_clock_padding_end)          smartSpaceView?.let {              it.setPaddingRelative(startPadding, topPadding, endPadding, 0) @@ -308,8 +319,8 @@ constructor(      }      @OptIn(ExperimentalCoroutinesApi::class) -    private fun setupKeyguardRootView(rootView: FrameLayout) { -        val keyguardRootView = KeyguardRootView(context, null).apply { removeAllViews() } +    private fun setupKeyguardRootView(previewContext: Context, rootView: FrameLayout) { +        val keyguardRootView = KeyguardRootView(previewContext, null).apply { removeAllViews() }          disposables.add(              KeyguardRootViewBinder.bind(                  keyguardRootView, @@ -333,10 +344,10 @@ constructor(              if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {                  setupShortcuts(keyguardRootView)              } -            setUpUdfps(rootView) +            setUpUdfps(previewContext, rootView)              if (!shouldHideClock) { -                setUpClock(rootView) +                setUpClock(previewContext, rootView)                  KeyguardPreviewClockViewBinder.bind(                      largeClockHostView,                      smallClockHostView, @@ -344,7 +355,7 @@ constructor(                  )              } -            setUpSmartspace(rootView) +            setUpSmartspace(previewContext, rootView)              smartSpaceView?.let {                  KeyguardPreviewSmartspaceViewBinder.bind(it, smartspaceViewModel)              } @@ -381,7 +392,7 @@ constructor(          }      } -    private fun setUpUdfps(parentView: ViewGroup) { +    private fun setUpUdfps(previewContext: Context, parentView: ViewGroup) {          val sensorBounds = udfpsOverlayInteractor.udfpsOverlayParams.value.sensorBounds          // If sensorBounds are default rect, then there is no UDFPS @@ -399,7 +410,7 @@ constructor(              sensorBounds.bottom          )          val finger = -            LayoutInflater.from(context) +            LayoutInflater.from(previewContext)                  .inflate(                      R.layout.udfps_keyguard_preview,                      parentView, @@ -408,12 +419,12 @@ constructor(          parentView.addView(finger, fingerprintLayoutParams)      } -    private fun setUpClock(parentView: ViewGroup) { +    private fun setUpClock(previewContext: Context, parentView: ViewGroup) {          largeClockHostView =              if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {                  parentView.requireViewById<FrameLayout>(R.id.lockscreen_clock_view_large)              } else { -                val hostView = FrameLayout(context) +                val hostView = FrameLayout(previewContext)                  hostView.layoutParams =                      FrameLayout.LayoutParams(                          FrameLayout.LayoutParams.MATCH_PARENT, @@ -429,7 +440,7 @@ constructor(                  parentView.requireViewById<FrameLayout>(R.id.lockscreen_clock_view)              } else {                  val resources = parentView.resources -                val hostView = FrameLayout(context) +                val hostView = FrameLayout(previewContext)                  val layoutParams =                      FrameLayout.LayoutParams(                          FrameLayout.LayoutParams.WRAP_CONTENT, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt index 1a9f021a7622..0b0f21d7a281 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt @@ -31,12 +31,12 @@ import androidx.constraintlayout.widget.ConstraintSet.START  import androidx.constraintlayout.widget.ConstraintSet.TOP  import com.android.keyguard.KeyguardStatusView  import com.android.keyguard.dagger.KeyguardStatusViewComponent -import com.android.systemui.res.R  import com.android.systemui.flags.FeatureFlags  import com.android.systemui.flags.Flags  import com.android.systemui.keyguard.KeyguardViewConfigurator  import com.android.systemui.keyguard.shared.model.KeyguardSection  import com.android.systemui.media.controls.ui.KeyguardMediaController +import com.android.systemui.res.R  import com.android.systemui.shade.NotificationPanelView  import com.android.systemui.shade.NotificationPanelViewController  import com.android.systemui.statusbar.policy.SplitShadeStateController @@ -84,7 +84,8 @@ constructor(      override fun bindData(constraintLayout: ConstraintLayout) {          if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {              constraintLayout.findViewById<KeyguardStatusView?>(R.id.keyguard_status_view)?.let { -                val statusViewComponent = keyguardStatusViewComponentFactory.build(it) +                val statusViewComponent = +                    keyguardStatusViewComponentFactory.build(it, context.display)                  val controller = statusViewComponent.keyguardStatusViewController                  controller.init()                  keyguardMediaController.attachSplitShadeContainer( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt new file mode 100644 index 000000000000..235a28d4ebc5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import android.graphics.Color +import android.view.View +import com.android.systemui.keyguard.domain.interactor.FromAlternateBouncerTransitionInteractor.Companion.TRANSITION_DURATION_MS +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.plugins.FalsingManager +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager +import com.android.wm.shell.animation.Interpolators +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge + +@ExperimentalCoroutinesApi +class AlternateBouncerViewModel +@Inject +constructor( +    statusBarKeyguardViewManager: StatusBarKeyguardViewManager, +    transitionInteractor: KeyguardTransitionInteractor, +    falsingManager: FalsingManager, +) { +    // When we're fully transitioned to the AlternateBouncer, the alpha of the scrim should be: +    private val alternateBouncerScrimAlpha = .66f +    private val toAlternateBouncerTransition = +        KeyguardTransitionAnimationFlow( +                transitionDuration = TRANSITION_DURATION_MS, +                transitionFlow = transitionInteractor.anyStateToAlternateBouncerTransition, +            ) +            .createFlow( +                duration = TRANSITION_DURATION_MS, +                onStep = { it }, +                onFinish = { 1f }, +                // Reset on cancel +                onCancel = { 0f }, +                interpolator = Interpolators.FAST_OUT_SLOW_IN, +            ) +    private val fromAlternateBouncerTransition = +        KeyguardTransitionAnimationFlow( +                transitionDuration = TRANSITION_DURATION_MS, +                transitionFlow = transitionInteractor.transitionStepsFromState(ALTERNATE_BOUNCER), +            ) +            .createFlow( +                duration = TRANSITION_DURATION_MS, +                onStep = { 1f - it }, +                // Reset on cancel +                onCancel = { 0f }, +                interpolator = Interpolators.FAST_OUT_SLOW_IN, +            ) + +    /** Progress to a fully transitioned alternate bouncer. 1f represents fully transitioned. */ +    private val transitionToAlternateBouncerProgress = +        merge(fromAlternateBouncerTransition, toAlternateBouncerTransition) + +    val forcePluginOpen: Flow<Boolean> = +        transitionToAlternateBouncerProgress.map { it > 0f }.distinctUntilChanged() + +    /** An observable for the scrim alpha. */ +    val scrimAlpha = transitionToAlternateBouncerProgress.map { it * alternateBouncerScrimAlpha } + +    /** An observable for the scrim color. Change color for easier debugging. */ +    val scrimColor: Flow<Int> = flowOf(Color.BLACK) + +    private val clickListener = +        View.OnClickListener { +            if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { +                statusBarKeyguardViewManager.showPrimaryBouncer(/* scrimmed */ true) +            } +        } + +    val onClickListener: Flow<View.OnClickListener?> = +        transitionToAlternateBouncerProgress +            .map { +                if (it == 1f) { +                    clickListener +                } else { +                    null +                } +            } +            .distinctUntilChanged() +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt index 54abc5bc695f..0b1079f69d6e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt @@ -19,13 +19,13 @@ package com.android.systemui.keyguard.ui.viewmodel  import android.content.Context  import androidx.annotation.ColorInt  import com.android.settingslib.Utils.getColorAttrDefaultColor -import com.android.systemui.res.R  import com.android.systemui.keyguard.domain.interactor.BurnInOffsets  import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor  import com.android.systemui.keyguard.domain.interactor.UdfpsKeyguardInteractor  import com.android.systemui.keyguard.shared.model.KeyguardState  import com.android.systemui.keyguard.shared.model.StatusBarState +import com.android.systemui.res.R  import com.android.wm.shell.animation.Interpolators  import javax.inject.Inject  import kotlin.math.roundToInt @@ -62,7 +62,7 @@ open class UdfpsLockscreenViewModel(      private val toAlternateBouncer: Flow<TransitionViewModel> =          keyguardInteractor.statusBarState.flatMapLatest { statusBarState -> -            transitionInteractor.anyStateToAlternateBouncerTransition.map { +            transitionInteractor.transitionStepsToState(KeyguardState.ALTERNATE_BOUNCER).map {                  TransitionViewModel(                      alpha = 1f,                      scale = diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java index 2b56d0cf9f83..d08d0400f354 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java @@ -239,6 +239,8 @@ public class MediaProjectionPermissionActivity extends Activity      protected void onDestroy() {          super.onDestroy();          if (mDialog != null) { +            mDialog.setOnDismissListener(null); +            mDialog.setOnCancelListener(null);              mDialog.dismiss();          }      } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java index 8589ae9305fd..68bf88b16ae2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java @@ -72,7 +72,7 @@ public class QSFragmentLegacy extends LifecycleFragment implements QS {      @Override      public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { -        QSFragmentComponent qsFragmentComponent = mQsComponentFactory.create(this); +        QSFragmentComponent qsFragmentComponent = mQsComponentFactory.create(getView());          mQsImpl = mQsImplProvider.get();          mQsImpl.onComponentCreated(qsFragmentComponent, savedInstanceState);      } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt index 2a36fdb21e18..65a2c8ca692b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt @@ -105,7 +105,7 @@ constructor(      override fun removeCallback(callback: QSHost.Callback) {          if (useNewHost) { -            synchronized(callbacksMap) { callbacksMap.get(callback)?.cancel() } +            synchronized(callbacksMap) { callbacksMap.remove(callback)?.cancel() }          } else {              qsTileHost.removeCallback(callback)          } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java index a32a024dbb44..202254bb323f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java @@ -199,11 +199,13 @@ public class QSImpl implements QS, CommandQueue.Callbacks, StatusBarStateControl          mListeningAndVisibilityLifecycleOwner = new ListeningAndVisibilityLifecycleOwner();      } +    /** +     * This method will set up all the necessary fields. Methods from the implemented interfaces +     * should not be called before this method returns. +     */      public void onComponentCreated(QSComponent qsComponent, @Nullable Bundle savedInstanceState) {          mRootView = qsComponent.getRootView(); -        mCommandQueue.addCallback(this); -          mQSPanelController = qsComponent.getQSPanelController();          mQuickQSPanelController = qsComponent.getQuickQSPanelController(); @@ -270,6 +272,9 @@ public class QSImpl implements QS, CommandQueue.Callbacks, StatusBarStateControl                      mQSPanelController.getMediaHost().getHostView().setAlpha(1.0f);                      mQSAnimator.requestAnimatorUpdate();                  }); + +        // This will immediately call disable, so it needs to be added after setting up the fields. +        mCommandQueue.addCallback(this);      }      private void bindFooterActionsView(View root) { @@ -323,6 +328,8 @@ public class QSImpl implements QS, CommandQueue.Callbacks, StatusBarStateControl      public void onDestroy() {          mCommandQueue.removeCallback(this);          mStatusBarStateController.removeCallback(this); +        mQSPanelController.destroy(); +        mQuickQSPanelController.destroy();          if (mListening) {              setListening(false);          } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java index 60c92c000760..fc2f5f9c7226 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java @@ -158,6 +158,7 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr      protected void onInit() {          mView.initialize(mQSLogger);          mQSLogger.logAllTilesChangeListening(mView.isListening(), mView.getDumpableTag(), ""); +        mHost.addCallback(mQSHostCallback);      }      /** @@ -172,6 +173,18 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr      }      @Override +    public void destroy() { +        super.destroy(); +        mHost.removeCallback(mQSHostCallback); + +        for (TileRecord record : mRecords) { +            record.tile.removeCallback(record.callback); +            mView.removeTile(record); +        } +        mRecords.clear(); +    } + +    @Override      protected void onViewAttached() {          mQsTileRevealController = createTileRevealController();          if (mQsTileRevealController != null) { @@ -180,7 +193,6 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr          mMediaHost.addVisibilityChangeListener(mMediaHostVisibilityListener);          mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener); -        mHost.addCallback(mQSHostCallback);          setTiles();          mLastOrientation = getResources().getConfiguration().orientation;          mQSLogger.logOnViewAttached(mLastOrientation, mView.getDumpableTag()); @@ -193,16 +205,11 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr      protected void onViewDetached() {          mQSLogger.logOnViewDetached(mLastOrientation, mView.getDumpableTag());          mView.removeOnConfigurationChangedListener(mOnConfigurationChangedListener); -        mHost.removeCallback(mQSHostCallback);          mView.getTileLayout().setListening(false, mUiEventLogger);          mMediaHost.removeVisibilityChangeListener(mMediaHostVisibilityListener); -        for (TileRecord record : mRecords) { -            record.tile.removeCallback(record.callback); -        } -        mRecords.clear();          mDumpManager.unregisterDumpable(mView.getDumpableTag());      } @@ -222,15 +229,30 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr          if (!collapsedView && mQsTileRevealController != null) {              mQsTileRevealController.updateRevealedTiles(tiles);          } - -        for (QSPanelControllerBase.TileRecord record : mRecords) { -            mView.removeTile(record); -            record.tile.removeCallback(record.callback); +        boolean shouldChange = false; +        if (tiles.size() == mRecords.size()) { +            int i = 0; +            for (QSTile tile : tiles) { +                if (tile != mRecords.get(i).tile) { +                    shouldChange = true; +                    break; +                } +                i++; +            } +        } else { +            shouldChange = true;          } -        mRecords.clear(); -        mCachedSpecs = ""; -        for (QSTile tile : tiles) { -            addTile(tile, collapsedView); + +        if (shouldChange) { +            for (QSPanelControllerBase.TileRecord record : mRecords) { +                mView.removeTile(record); +                record.tile.removeCallback(record.callback); +            } +            mRecords.clear(); +            mCachedSpecs = ""; +            for (QSTile tile : tiles) { +                addTile(tile, collapsedView); +            }          }      } diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java index 327e858059f3..ce8db789842a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java +++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java @@ -16,6 +16,9 @@  package com.android.systemui.qs.dagger; +import android.view.View; + +import com.android.systemui.dagger.qualifiers.RootView;  import com.android.systemui.qs.QSFragmentLegacy;  import dagger.BindsInstance; @@ -31,6 +34,7 @@ public interface QSFragmentComponent extends QSComponent {      /** Factory for building a {@link QSFragmentComponent}. */      @Subcomponent.Factory      interface Factory { -        QSFragmentComponent create(@BindsInstance QSFragmentLegacy qsFragment); +        /** */ +        QSFragmentComponent create(@BindsInstance @RootView View view);      }  } diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java index 0c9c24df5e36..0e75b2157a7d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java +++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java @@ -20,34 +20,17 @@ import static com.android.systemui.util.Utils.useCollapsedMediaInLandscape;  import static com.android.systemui.util.Utils.useQsMediaPlayer;  import android.content.Context; -import android.view.View; -import com.android.systemui.dagger.qualifiers.RootView; -import com.android.systemui.plugins.qs.QS; -import com.android.systemui.qs.QSFragmentLegacy; - -import javax.inject.Named; - -import dagger.Binds;  import dagger.Module;  import dagger.Provides; +import javax.inject.Named; +  /**   * Dagger Module for {@link QSFragmentComponent}.   */  @Module(includes = {QSScopeModule.class})  public  interface QSFragmentModule { - -    @Provides -    @RootView -    static View provideRootView(QSFragmentLegacy qsFragment) { -        return qsFragment.getView(); -    } - -    /** */ -    @Binds -    QS bindQS(QSFragmentLegacy qsFragment); -      /** */      @Provides      @Named(QSScopeModule.QS_USING_MEDIA_PLAYER) diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt index c5512c15ccc2..4bb8c6e4bb2d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt @@ -272,7 +272,6 @@ constructor(                              // repository                              launch { tileSpecRepository.setTiles(currentUser.value, resolvedSpecs) }                          } -                        Log.d("Fabian", "Finished resolving tiles")                      }              }          } 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 584456d79890..91b4d1778e1c 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 @@ -42,6 +42,7 @@ import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICA  import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE  import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED  import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING +import javax.inject.Inject  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.flow.distinctUntilChanged @@ -51,7 +52,6 @@ import kotlinx.coroutines.flow.flatMapLatest  import kotlinx.coroutines.flow.map  import kotlinx.coroutines.flow.mapNotNull  import kotlinx.coroutines.launch -import javax.inject.Inject  /**   * Hooks up business logic that manipulates the state of the [SceneInteractor] for the system UI @@ -142,7 +142,7 @@ constructor(                                  // When the device becomes unlocked in Lockscreen, go to Gone if                                  // bypass is enabled.                                  renderedScenes.contains(SceneKey.Lockscreen) -> -                                    if (deviceEntryInteractor.isBypassEnabled()) { +                                    if (deviceEntryInteractor.isBypassEnabled.value) {                                          SceneKey.Gone to                                              "device unlocked in Lockscreen scene with bypass"                                      } else { @@ -179,36 +179,34 @@ constructor(          }          applicationScope.launch { -            powerInteractor.isAsleep -                .collect { isAsleep -> -                    if (isAsleep) { -                        switchToScene( -                                targetSceneKey = SceneKey.Lockscreen, -                                loggingReason = "device is starting to sleep", -                        ) -                    } else { -                        val authMethod = authenticationInteractor.getAuthenticationMethod() -                        val isUnlocked = deviceEntryInteractor.isUnlocked.value -                        when { -                            authMethod == AuthenticationMethodModel.None -> { -                                switchToScene( -                                        targetSceneKey = SceneKey.Gone, -                                        loggingReason = -                                        "device is starting to wake up while auth method is" + -                                                " none", -                                ) -                            } -                            authMethod.isSecure && isUnlocked -> { -                                switchToScene( -                                        targetSceneKey = SceneKey.Gone, -                                        loggingReason = -                                        "device is starting to wake up while unlocked with a" + -                                                " secure auth method", -                                ) -                            } +            powerInteractor.isAsleep.collect { isAsleep -> +                if (isAsleep) { +                    switchToScene( +                        targetSceneKey = SceneKey.Lockscreen, +                        loggingReason = "device is starting to sleep", +                    ) +                } else { +                    val authMethod = authenticationInteractor.getAuthenticationMethod() +                    val isUnlocked = deviceEntryInteractor.isUnlocked.value +                    when { +                        authMethod == AuthenticationMethodModel.None -> { +                            switchToScene( +                                targetSceneKey = SceneKey.Gone, +                                loggingReason = +                                    "device is starting to wake up while auth method is" + " none", +                            ) +                        } +                        authMethod.isSecure && isUnlocked -> { +                            switchToScene( +                                targetSceneKey = SceneKey.Gone, +                                loggingReason = +                                    "device is starting to wake up while unlocked with a" + +                                        " secure auth method", +                            )                          }                      }                  } +            }          }      } diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt index 3927873f8ba8..f704894e56e2 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt @@ -42,6 +42,13 @@ sealed class ObservableTransitionState {           * scene, this value will remain true after the pointer is no longer touching the screen and           * will be true in any transition created to animate back to the original position.           */ -        val isUserInputDriven: Boolean, +        val isInitiatedByUserInput: Boolean, + +        /** +         * Whether user input is currently driving the transition. For example, if a user is +         * dragging a pointer, this emits true. Once they lift their finger, this emits false while +         * the transition completes/settles. +         */ +        val isUserInputOngoing: Flow<Boolean>,      ) : ObservableTransitionState()  } diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt index 4bc93a8f1ca5..2e45353634fe 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt @@ -61,12 +61,17 @@ sealed interface UserAction {      data class Swipe(          /** The direction of the swipe. */          val direction: Direction, +        /** +         * The edge from which the swipe originated or `null`, if the swipe didn't start close to an +         * edge. +         */ +        val fromEdge: Edge? = null,          /** The number of pointers that were used (for example, one or two fingers). */          val pointerCount: Int = 1,      ) : UserAction      /** The user has hit the back button or performed the back navigation gesture. */ -    object Back : UserAction +    data object Back : UserAction  }  /** Enumerates all known "cardinal" directions for user actions. */ @@ -76,3 +81,11 @@ enum class Direction {      RIGHT,      DOWN,  } + +/** Enumerates all known edges from which a swipe can start. */ +enum class Edge { +    LEFT, +    TOP, +    RIGHT, +    BOTTOM, +} diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt index 2f873019349c..393a698bcdb7 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt @@ -132,6 +132,7 @@ open class UserTrackerImpl internal constructor(          setUserIdInternal(startingUser)          val filter = IntentFilter().apply { +            addAction(Intent.ACTION_LOCALE_CHANGED)              addAction(Intent.ACTION_USER_INFO_CHANGED)              // These get called when a managed profile goes in or out of quiet mode.              addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) @@ -149,6 +150,7 @@ open class UserTrackerImpl internal constructor(      override fun onReceive(context: Context, intent: Intent) {          when (intent.action) { +            Intent.ACTION_LOCALE_CHANGED,              Intent.ACTION_USER_INFO_CHANGED,              Intent.ACTION_MANAGED_PROFILE_AVAILABLE,              Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE, diff --git a/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java b/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java index 9235fcc8202f..c42fdf8e7b93 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java @@ -67,8 +67,6 @@ public class DebugDrawable extends Drawable {          mDebugPaint.setStrokeWidth(2);          mDebugPaint.setStyle(Paint.Style.STROKE);          mDebugPaint.setTextSize(24); -        String headerDebugInfo = mNotificationPanelViewController.getHeaderDebugInfo(); -        if (headerDebugInfo != null) canvas.drawText(headerDebugInfo, 50, 100, mDebugPaint);          drawDebugInfo(canvas, mNotificationPanelViewController.getMaxPanelHeight(),                  Color.RED, "getMaxPanelHeight()"); diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index d3d38e5c21cd..2ef83dd42868 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -138,7 +138,6 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;  import com.android.systemui.keyguard.shared.model.TransitionState;  import com.android.systemui.keyguard.shared.model.TransitionStep; -import com.android.systemui.power.shared.model.WakefulnessModel;  import com.android.systemui.keyguard.ui.binder.KeyguardLongPressViewBinder;  import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;  import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingLockscreenHostedTransitionViewModel; @@ -162,9 +161,10 @@ import com.android.systemui.plugins.FalsingManager.FalsingTapListener;  import com.android.systemui.plugins.qs.QS;  import com.android.systemui.plugins.statusbar.StatusBarStateController;  import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; +import com.android.systemui.power.domain.interactor.PowerInteractor; +import com.android.systemui.power.shared.model.WakefulnessModel;  import com.android.systemui.res.R;  import com.android.systemui.shade.data.repository.ShadeRepository; -import com.android.systemui.power.domain.interactor.PowerInteractor;  import com.android.systemui.shade.transition.ShadeTransitionController;  import com.android.systemui.shared.system.QuickStepContract;  import com.android.systemui.statusbar.CommandQueue; @@ -200,7 +200,6 @@ import com.android.systemui.statusbar.phone.BounceInterpolator;  import com.android.systemui.statusbar.phone.CentralSurfaces;  import com.android.systemui.statusbar.phone.DozeParameters;  import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;  import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;  import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;  import com.android.systemui.statusbar.phone.KeyguardBottomAreaViewController; @@ -217,6 +216,7 @@ import com.android.systemui.statusbar.phone.TapAgainViewController;  import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;  import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;  import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;  import com.android.systemui.statusbar.policy.KeyguardStateController;  import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController; @@ -362,7 +362,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump      private boolean mIsLaunchAnimationRunning;      private float mOverExpansion;      private CentralSurfaces mCentralSurfaces; -    private HeadsUpManagerPhone mHeadsUpManager; +    private HeadsUpManager mHeadsUpManager;      private float mExpandedHeight = 0;      /** The current squish amount for the predictive back animation */      private float mCurrentBackProgress = 0.0f; @@ -1275,7 +1275,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump              KeyguardStatusView keyguardStatusView = mView.getRootView().findViewById(                      R.id.keyguard_status_view);              KeyguardStatusViewComponent statusViewComponent = -                    mKeyguardStatusViewComponentFactory.build(keyguardStatusView); +                    mKeyguardStatusViewComponentFactory.build(keyguardStatusView, +                            mView.getContext().getDisplay());              mKeyguardStatusViewController = statusViewComponent.getKeyguardStatusViewController();              mKeyguardStatusViewController.init();          } @@ -3025,7 +3026,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump          return headsUpVisible || isExpanded() || mBouncerShowing;      } -    private void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) { +    private void setHeadsUpManager(HeadsUpManager headsUpManager) {          mHeadsUpManager = headsUpManager;          mHeadsUpManager.addListener(mOnHeadsUpChangedListener);          mHeadsUpTouchHelper = new HeadsUpTouchHelper( @@ -3507,7 +3508,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump              GestureRecorder recorder,              Runnable hideExpandedRunnable,              NotificationShelfController notificationShelfController, -            HeadsUpManagerPhone headsUpManager) { +            HeadsUpManager headsUpManager) {          setHeadsUpManager(headsUpManager);          // TODO(b/254859580): this can be injected.          mCentralSurfaces = centralSurfaces; @@ -3556,10 +3557,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump          mView.getViewTreeObserver().removeOnGlobalLayoutListener(listener);      } -    String getHeaderDebugInfo() { -        return "USER " + mHeadsUpManager.getUser(); -    } -      @Override      public void onThemeChanged() {          mConfigurationListener.onThemeChanged(); diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index 6cf4ff569662..5414b3f30aa5 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -21,7 +21,6 @@ import static com.android.systemui.flags.Flags.TRACKPAD_GESTURE_COMMON;  import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;  import android.app.StatusBarManager; -import android.os.PowerManager;  import android.util.Log;  import android.view.GestureDetector;  import android.view.InputDevice; @@ -36,10 +35,11 @@ import com.android.keyguard.KeyguardMessageAreaController;  import com.android.keyguard.LockIconViewController;  import com.android.keyguard.dagger.KeyguardBouncerComponent;  import com.android.systemui.Dumpable; -import com.android.systemui.res.R;  import com.android.systemui.animation.ActivityLaunchAnimator;  import com.android.systemui.back.domain.interactor.BackActionInteractor; +import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;  import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor; +import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;  import com.android.systemui.bouncer.ui.binder.KeyguardBouncerViewBinder;  import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel;  import com.android.systemui.classifier.FalsingCollector; @@ -56,6 +56,7 @@ import com.android.systemui.keyguard.shared.model.TransitionStep;  import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;  import com.android.systemui.log.BouncerLogger;  import com.android.systemui.power.domain.interactor.PowerInteractor; +import com.android.systemui.res.R;  import com.android.systemui.shared.animation.DisableSubpixelTextTransitionListener;  import com.android.systemui.statusbar.DragDownHelper;  import com.android.systemui.statusbar.LockscreenShadeTransitionController; @@ -106,6 +107,8 @@ public class NotificationShadeWindowViewController implements Dumpable {      private final boolean mIsTrackpadCommonEnabled;      private final FeatureFlags mFeatureFlags;      private final KeyEventInteractor mKeyEventInteractor; +    private final PrimaryBouncerInteractor mPrimaryBouncerInteractor; +    private final AlternateBouncerInteractor mAlternateBouncerInteractor;      private GestureDetector mPulsingWakeupGestureHandler;      private GestureDetector mDreamingWakeupGestureHandler;      private View mBrightnessMirror; @@ -182,7 +185,9 @@ public class NotificationShadeWindowViewController implements Dumpable {              SystemClock clock,              BouncerMessageInteractor bouncerMessageInteractor,              BouncerLogger bouncerLogger, -            KeyEventInteractor keyEventInteractor) { +            KeyEventInteractor keyEventInteractor, +            PrimaryBouncerInteractor primaryBouncerInteractor, +            AlternateBouncerInteractor alternateBouncerInteractor) {          mLockscreenShadeTransitionController = transitionController;          mFalsingCollector = falsingCollector;          mStatusBarStateController = statusBarStateController; @@ -210,6 +215,8 @@ public class NotificationShadeWindowViewController implements Dumpable {          mIsTrackpadCommonEnabled = featureFlags.isEnabled(TRACKPAD_GESTURE_COMMON);          mFeatureFlags = featureFlags;          mKeyEventInteractor = keyEventInteractor; +        mPrimaryBouncerInteractor = primaryBouncerInteractor; +        mAlternateBouncerInteractor = alternateBouncerInteractor;          // This view is not part of the newly inflated expanded status bar.          mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container); @@ -351,16 +358,6 @@ public class NotificationShadeWindowViewController implements Dumpable {                  if (mStatusBarStateController.isDozing()) {                      mDozeScrimController.extendPulse();                  } -                mLockIconViewController.onTouchEvent( -                        ev, -                        /* onGestureDetectedRunnable */ -                        () -> { -                            mService.userActivity(); -                            mPowerInteractor.wakeUpIfDozing( -                                    "LOCK_ICON_TOUCH", -                                    PowerManager.WAKE_REASON_GESTURE); -                        } -                );                  // In case we start outside of the view bounds (below the status bar), we need to                  // dispatch the touch manually as the view system can't accommodate for touches @@ -415,8 +412,18 @@ public class NotificationShadeWindowViewController implements Dumpable {              private boolean shouldInterceptTouchEventInternal(MotionEvent ev) {                  mLastInterceptWasDragDownHelper = false; -                if (mStatusBarStateController.isDozing() && !mDozeServiceHost.isPulsing() -                        && !mDockManager.isDocked()) { +                // When the device starts dozing, there's a delay before the device's display state +                // changes from ON => DOZE to allow for the light reveal animation to run at +                // a higher refresh rate and to delay visual changes (ie: display blink) when +                // changing the display state. We'll call this specific state the +                // "aodDefermentState". In this state we: +                //     - don't want touches to get sent to underlying views, except the lock icon +                //     - handle the tap to wake gesture via the PulsingGestureListener +                if (mStatusBarStateController.isDozing() +                        && !mDozeServiceHost.isPulsing() +                        && !mDockManager.isDocked() +                        && !mLockIconViewController.willHandleTouchWhileDozing(ev) +                ) {                      if (ev.getAction() == MotionEvent.ACTION_DOWN) {                          mShadeLogger.d("NSWVC: capture all touch events in always-on");                      } @@ -432,16 +439,15 @@ public class NotificationShadeWindowViewController implements Dumpable {                      return true;                  } -                if (mLockIconViewController.onInterceptTouchEvent(ev)) { -                    // immediately return true; don't send the touch to the drag down helper -                    if (ev.getAction() == MotionEvent.ACTION_DOWN) { -                        mShadeLogger.d("NSWVC: don't send touch to drag down helper"); -                    } -                    return true; +                boolean bouncerShowing; +                if (mFeatureFlags.isEnabled(Flags.ALTERNATE_BOUNCER_VIEW)) { +                    bouncerShowing = mPrimaryBouncerInteractor.isBouncerShowing() +                            || mAlternateBouncerInteractor.isVisibleState(); +                } else { +                    bouncerShowing = mService.isBouncerShowing();                  } -                  if (mNotificationPanelViewController.isFullyExpanded() -                        && !mService.isBouncerShowing() +                        && !bouncerShowing                          && !mStatusBarStateController.isDozing()) {                      if (mDragDownHelper.isDragDownEnabled()) {                          // This handles drag down over lockscreen diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java index 447a15d34c05..2c4b0b990e6d 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java @@ -178,9 +178,6 @@ public interface ShadeController extends CoreStartable {      /** Listens for shade visibility changes. */      interface ShadeVisibilityListener { -        /** Called when the visibility of the shade changes. */ -        void visibilityChanged(boolean visible); -          /** Called when shade expanded and visible state changed. */          void expandedVisibleChanged(boolean expandedVisible);      } diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java index 367449b9d59d..fdc7eecd9b15 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java @@ -24,6 +24,7 @@ import android.view.ViewTreeObserver;  import android.view.WindowManager;  import android.view.WindowManagerGlobal; +import com.android.systemui.DejankUtils;  import com.android.systemui.assist.AssistManager;  import com.android.systemui.dagger.SysUISingleton;  import com.android.systemui.dagger.qualifiers.Main; @@ -75,6 +76,7 @@ public final class ShadeControllerImpl implements ShadeController {      private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();      private boolean mExpandedVisible; +    private boolean mLockscreenOrShadeVisible;      private NotificationPresenter mPresenter;      private NotificationShadeWindowViewController mNotificationShadeWindowViewController; @@ -399,8 +401,19 @@ public final class ShadeControllerImpl implements ShadeController {      }      private void notifyVisibilityChanged(boolean visible) { -        mShadeVisibilityListener.visibilityChanged(visible);          mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(visible); +        if (mLockscreenOrShadeVisible != visible) { +            mLockscreenOrShadeVisible = visible; +            if (visible) { +                // It would be best if this could be done as a side effect of listening to the +                // [WindowRootViewVisibilityInteractor.isLockscreenOrShadeVisible] flow inside +                // NotificationShadeWindowViewController. However, there's no guarantee that the +                // flow will emit in the same frame as when the visibility changed, and we want the +                // DejankUtils to be notified immediately, so we do it immediately here. +                DejankUtils.notifyRendererOfExpensiveFrame( +                        getNotificationShadeWindowView(), "onShadeVisibilityChanged"); +            } +        }      }      private void notifyExpandedVisibleChanged(boolean expandedVisible) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt index 6ee6cbf69a70..4e23e7d97a01 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt @@ -20,7 +20,7 @@ import com.android.systemui.statusbar.GestureRecorder  import com.android.systemui.statusbar.NotificationShelfController  import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController  import com.android.systemui.statusbar.phone.CentralSurfaces -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone +import com.android.systemui.statusbar.policy.HeadsUpManager  /**   * Allows CentralSurfacesImpl to interact with the shade. Only CentralSurfacesImpl should reference @@ -34,7 +34,7 @@ interface ShadeSurface : ShadeViewController {          recorder: GestureRecorder,          hideExpandedRunnable: Runnable,          notificationShelfController: NotificationShelfController, -        headsUpManager: HeadsUpManagerPhone +        headsUpManager: HeadsUpManager      )      /** Cancels any pending collapses. */ diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt index ac8333ae84ad..6117f9f80e6c 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt @@ -19,7 +19,11 @@ package com.android.systemui.shade.domain.interactor  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.keyguard.data.repository.KeyguardRepository +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.DozeStateModel +import com.android.systemui.keyguard.shared.model.KeyguardState  import com.android.systemui.keyguard.shared.model.StatusBarState +import com.android.systemui.power.domain.interactor.PowerInteractor  import com.android.systemui.scene.domain.interactor.SceneInteractor  import com.android.systemui.scene.shared.flag.SceneContainerFlags  import com.android.systemui.scene.shared.model.ObservableTransitionState @@ -27,8 +31,9 @@ import com.android.systemui.scene.shared.model.SceneKey  import com.android.systemui.shade.data.repository.ShadeRepository  import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository  import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor +import com.android.systemui.statusbar.phone.DozeParameters  import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository -import com.android.systemui.statusbar.policy.DeviceProvisionedController +import com.android.systemui.statusbar.policy.data.repository.DeviceProvisioningRepository  import com.android.systemui.user.domain.interactor.UserInteractor  import com.android.systemui.util.kotlin.pairwise  import javax.inject.Inject @@ -56,13 +61,16 @@ class ShadeInteractor  @Inject  constructor(      @Application scope: CoroutineScope, +    deviceProvisioningRepository: DeviceProvisioningRepository,      disableFlagsRepository: DisableFlagsRepository, +    dozeParams: DozeParameters,      sceneContainerFlags: SceneContainerFlags,      // TODO(b/300258424) convert to direct reference instead of provider      sceneInteractorProvider: Provider<SceneInteractor>,      keyguardRepository: KeyguardRepository, +    keyguardTransitionInteractor: KeyguardTransitionInteractor, +    powerInteractor: PowerInteractor,      userSetupRepository: UserSetupRepository, -    deviceProvisionedController: DeviceProvisionedController,      userInteractor: UserInteractor,      sharedNotificationContainerInteractor: SharedNotificationContainerInteractor,      repository: ShadeRepository, @@ -187,6 +195,26 @@ constructor(          combine(isUserInteractingWithShade, isUserInteractingWithShade) { shade, qs -> shade || qs }              .distinctUntilChanged() +    /** Are touches allowed on the notification panel? */ +    val isShadeTouchable: Flow<Boolean> = +        combine( +            powerInteractor.isAsleep, +            keyguardTransitionInteractor.isInTransitionToStateWhere { it == KeyguardState.AOD }, +            keyguardRepository.dozeTransitionModel.map { it.to == DozeStateModel.DOZE_PULSING }, +            deviceProvisioningRepository.isFactoryResetProtectionActive, +        ) { isAsleep, goingToSleep, isPulsing, isFrpActive -> +            when { +                // Touches are disabled when Factory Reset Protection is active +                isFrpActive -> false +                // If the device is going to sleep, only accept touches if we're still +                // animating +                goingToSleep -> dozeParams.shouldControlScreenOff() +                // If the device is asleep, only accept touches if there's a pulse +                isAsleep -> isPulsing +                else -> true +            } +        } +      /** Emits true if the shade can be expanded from QQS to QS and false otherwise. */      val isExpandToQsEnabled: Flow<Boolean> =          combine( @@ -194,8 +222,9 @@ constructor(              isShadeEnabled,              keyguardRepository.isDozing,              userSetupRepository.isUserSetupFlow, -        ) { disableFlags, isShadeEnabled, isDozing, isUserSetup -> -            deviceProvisionedController.isDeviceProvisioned && +            deviceProvisioningRepository.isDeviceProvisioned, +        ) { disableFlags, isShadeEnabled, isDozing, isUserSetup, isDeviceProvisioned -> +            isDeviceProvisioned &&                  // Disallow QS during setup if it's a simple user switcher. (The user intends to                  // use the lock screen user switcher, QS is not needed.)                  (isUserSetup || !userInteractor.isSimpleUserSwitcher) && @@ -232,7 +261,7 @@ constructor(                  when (state) {                      is ObservableTransitionState.Idle -> false                      is ObservableTransitionState.Transition -> -                        state.isUserInputDriven && +                        state.isInitiatedByUserInput &&                              (state.toScene == sceneKey || state.fromScene == sceneKey)                  }              } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java index d24f9d8f476c..77b095802b00 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java @@ -18,6 +18,8 @@ package com.android.systemui.statusbar;  import android.view.View; +import androidx.annotation.Nullable; +  import com.android.app.animation.Interpolators;  import com.android.systemui.res.R;  import com.android.systemui.statusbar.notification.stack.StackStateAnimator; @@ -113,7 +115,16 @@ public class CrossFadeHelper {          fadeIn(view, ANIMATION_DURATION_LENGTH, 0);      } +    public static void fadeIn(final View view, Runnable endRunnable) { +        fadeIn(view, ANIMATION_DURATION_LENGTH, /* delay= */ 0, endRunnable); +    } +      public static void fadeIn(final View view, long duration, int delay) { +        fadeIn(view, duration, delay, /* endRunnable= */ null); +    } + +    public static void fadeIn(final View view, long duration, int delay, +            @Nullable Runnable endRunnable) {          view.animate().cancel();          if (view.getVisibility() == View.INVISIBLE) {              view.setAlpha(0.0f); @@ -124,7 +135,7 @@ public class CrossFadeHelper {                  .setDuration(duration)                  .setStartDelay(delay)                  .setInterpolator(Interpolators.ALPHA_IN) -                .withEndAction(null); +                .withEndAction(endRunnable);          if (view.hasOverlappingRendering() && view.getLayerType() != View.LAYER_TYPE_HARDWARE) {              view.animate().withLayer();          } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt index 3640ae067537..4ea70264b152 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt @@ -31,22 +31,22 @@ import androidx.annotation.VisibleForTesting  import com.android.app.animation.Interpolators  import com.android.systemui.Dumpable  import com.android.systemui.Gefingerpoken -import com.android.systemui.res.R  import com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN  import com.android.systemui.classifier.FalsingCollector  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dump.DumpManager  import com.android.systemui.plugins.FalsingManager  import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.res.R  import com.android.systemui.shade.ShadeExpansionStateManager  import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator  import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow  import com.android.systemui.statusbar.notification.row.ExpandableView  import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager  import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone  import com.android.systemui.statusbar.phone.KeyguardBypassController  import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.policy.HeadsUpManager  import java.io.PrintWriter  import javax.inject.Inject  import kotlin.math.max @@ -63,7 +63,7 @@ constructor(      context: Context,      private val wakeUpCoordinator: NotificationWakeUpCoordinator,      private val bypassController: KeyguardBypassController, -    private val headsUpManager: HeadsUpManagerPhone, +    private val headsUpManager: HeadsUpManager,      private val roundnessManager: NotificationRoundnessManager,      configurationController: ConfigurationController,      private val statusBarStateController: StatusBarStateController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index f616b91c4712..3a4ad0e79994 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -51,6 +51,7 @@ import android.view.ViewGroup;  import android.view.accessibility.AccessibilityEvent;  import android.view.animation.Interpolator; +import androidx.annotation.Nullable;  import androidx.core.graphics.ColorUtils;  import com.android.app.animation.Interpolators; @@ -959,12 +960,17 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi      }      public void setDozing(boolean dozing, boolean fade, long delay) { +        setDozing(dozing, fade, delay, /* onChildCompleted= */ null); +    } + +    public void setDozing(boolean dozing, boolean fade, long delay, +            @Nullable Runnable endRunnable) {          mDozer.setDozing(f -> {              mDozeAmount = f;              updateDecorColor();              updateIconColor();              updateAllowAnimation(); -        }, dozing, fade, delay, this); +        }, dozing, fade, delay, this, endRunnable);      }      private void updateAllowAnimation() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java index 167efc784ff5..dc0eb7b4aab3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java @@ -24,6 +24,8 @@ import android.graphics.ColorMatrixColorFilter;  import android.view.View;  import android.widget.ImageView; +import androidx.annotation.Nullable; +  import com.android.app.animation.Interpolators;  import com.android.systemui.res.R;  import com.android.systemui.statusbar.notification.stack.StackStateAnimator; @@ -81,6 +83,11 @@ public class NotificationDozeHelper {      public void setDozing(Consumer<Float> listener, boolean dozing,              boolean animate, long delay, View view) { +        setDozing(listener, dozing, animate, delay, view, /* endRunnable= */ null); +    } + +    public void setDozing(Consumer<Float> listener, boolean dozing, +            boolean animate, long delay, View view, @Nullable Runnable endRunnable) {          if (animate) {              startIntensityAnimation(a -> listener.accept((Float) a.getAnimatedValue()), dozing,                      delay, @@ -89,6 +96,9 @@ public class NotificationDozeHelper {                          @Override                          public void onAnimationEnd(Animator animation) {                              view.setTag(DOZE_ANIMATOR_TAG, null); +                            if (endRunnable != null) { +                                endRunnable.run(); +                            }                          }                          @Override @@ -102,6 +112,9 @@ public class NotificationDozeHelper {                  animator.cancel();              }              listener.accept(dozing ? 1f : 0f); +            if (endRunnable != null) { +                endRunnable.run(); +            }          }      } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt index c62546f67f8d..756151bd57e0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt @@ -24,7 +24,7 @@ import com.android.systemui.animation.LaunchAnimator  import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository  import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow  import com.android.systemui.statusbar.notification.stack.NotificationListContainer -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone +import com.android.systemui.statusbar.policy.HeadsUpManager  import com.android.systemui.statusbar.policy.HeadsUpUtil  import kotlin.math.ceil  import kotlin.math.max @@ -35,7 +35,7 @@ private const val TAG = "NotificationLaunchAnimatorController"  class NotificationLaunchAnimatorControllerProvider(      private val notificationExpansionRepository: NotificationExpansionRepository,      private val notificationListContainer: NotificationListContainer, -    private val headsUpManager: HeadsUpManagerPhone, +    private val headsUpManager: HeadsUpManager,      private val jankMonitor: InteractionJankMonitor  ) {      @JvmOverloads @@ -62,7 +62,7 @@ class NotificationLaunchAnimatorControllerProvider(  class NotificationLaunchAnimatorController(      private val notificationExpansionRepository: NotificationExpansionRepository,      private val notificationListContainer: NotificationListContainer, -    private val headsUpManager: HeadsUpManagerPhone, +    private val headsUpManager: HeadsUpManager,      private val notification: ExpandableNotificationRow,      private val jankMonitor: InteractionJankMonitor,      private val onFinishAnimationCallback: Runnable? @@ -152,16 +152,17 @@ class NotificationLaunchAnimatorController(          }      } -    private val headsUpNotificationRow: ExpandableNotificationRow? get() { -        val summaryEntry = notificationEntry.parent?.summary +    private val headsUpNotificationRow: ExpandableNotificationRow? +        get() { +            val summaryEntry = notificationEntry.parent?.summary -        return when { -            headsUpManager.isAlerting(notificationKey) -> notification -            summaryEntry == null -> null -            headsUpManager.isAlerting(summaryEntry.key) -> summaryEntry.row -            else -> null +            return when { +                headsUpManager.isAlerting(notificationKey) -> notification +                summaryEntry == null -> null +                headsUpManager.isAlerting(summaryEntry.key) -> summaryEntry.row +                else -> null +            }          } -    }      private fun removeHun(animate: Boolean) {          val row = headsUpNotificationRow ?: return diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt index 07eb8a00a178..2d839704e0b7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt @@ -37,8 +37,8 @@ import com.android.systemui.statusbar.notification.collection.coordinator.dagger  import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter  import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener  import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider -import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderImpl  import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider +import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationListInteractor  import com.android.systemui.statusbar.policy.HeadsUpManager  import com.android.systemui.statusbar.policy.headsUpEvents  import com.android.systemui.util.asIndenting @@ -85,7 +85,7 @@ constructor(      @Application private val scope: CoroutineScope,      private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider,      private val secureSettings: SecureSettings, -    private val seenNotifsProvider: SeenNotificationsProviderImpl, +    private val notificationListInteractor: NotificationListInteractor,      private val statusBarStateController: StatusBarStateController,  ) : Coordinator, Dumpable { @@ -351,7 +351,7 @@ constructor(              override fun onCleanup() {                  logger.logProviderHasFilteredOutSeenNotifs(hasFilteredAnyNotifs) -                seenNotifsProvider.hasFilteredOutSeenNotifications = hasFilteredAnyNotifs +                notificationListInteractor.setHasFilteredOutSeenNotifications(hasFilteredAnyNotifs)                  hasFilteredAnyNotifs = false              }          } @@ -388,8 +388,8 @@ constructor(      override fun dump(pw: PrintWriter, args: Array<out String>) =          with(pw.asIndenting()) {              println( -                "seenNotifsProvider.hasFilteredOutSeenNotifications=" + -                    seenNotifsProvider.hasFilteredOutSeenNotifications +                "notificationListInteractor.hasFilteredOutSeenNotifications.value=" + +                    notificationListInteractor.hasFilteredOutSeenNotifications.value              )              println("unseen notifications:")              indentIfPossible { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt index 657c394d4e30..c0f674846991 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt @@ -28,6 +28,7 @@ import com.android.systemui.statusbar.notification.collection.coordinator.dagger  import com.android.systemui.statusbar.notification.row.NotificationGutsManager  import com.android.systemui.statusbar.policy.ConfigurationController  import com.android.systemui.util.Compile +import com.android.systemui.util.traceSection  import javax.inject.Inject  /** @@ -122,8 +123,10 @@ class ViewConfigCoordinator @Inject internal constructor(      private fun updateNotificationsOnUiModeChanged() {          log { "ViewConfigCoordinator.updateNotificationsOnUiModeChanged()" } -        mPipeline?.allNotifs?.forEach { entry -> -            entry.row?.onUiModeChanged() +        traceSection("updateNotifOnUiModeChanged") { +            mPipeline?.allNotifs?.forEach { entry -> +                entry.row?.onUiModeChanged() +            }          }      } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SeenNotificationsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SeenNotificationsProvider.kt deleted file mode 100644 index cff47e220299..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SeenNotificationsProvider.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.notification.collection.provider - -import com.android.systemui.dagger.SysUISingleton -import dagger.Binds -import dagger.Module -import javax.inject.Inject - -/** Keeps track of whether "seen" notification content has been filtered out of the shade. */ -interface SeenNotificationsProvider { -    /** Are any already-seen notifications currently filtered out of the shade? */ -    val hasFilteredOutSeenNotifications: Boolean -} - -@Module -interface SeenNotificationsProviderModule { -    @Binds -    fun bindSeenNotificationsProvider( -        impl: SeenNotificationsProviderImpl -    ): SeenNotificationsProvider -} - -@SysUISingleton -class SeenNotificationsProviderImpl @Inject constructor() : SeenNotificationsProvider { -    override var hasFilteredOutSeenNotifications: Boolean = false -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt index 59fc387c4608..1a88815acfaf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt @@ -231,18 +231,24 @@ private class ShadeNode(val controller: NodeController) {      fun getChildCount(): Int = controller.getChildCount()      fun addChildAt(child: ShadeNode, index: Int) { -        controller.addChildAt(child.controller, index) -        child.controller.onViewAdded() +        traceSection("ShadeNode#addChildAt") { +            controller.addChildAt(child.controller, index) +            child.controller.onViewAdded() +        }      }      fun moveChildTo(child: ShadeNode, index: Int) { -        controller.moveChildTo(child.controller, index) -        child.controller.onViewMoved() +        traceSection("ShadeNode#moveChildTo") { +            controller.moveChildTo(child.controller, index) +            child.controller.onViewMoved() +        }      }      fun removeChild(child: ShadeNode, isTransfer: Boolean) { -        controller.removeChild(child.controller, isTransfer) -        child.controller.onViewRemoved() +        traceSection("ShadeNode#removeChild") { +            controller.removeChild(child.controller, isTransfer) +            child.controller.onViewRemoved() +        }      }      fun offerToKeepInParentForAnimation(): Boolean { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index 8ee0de691557..8561869af352 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -20,10 +20,10 @@ import android.content.Context;  import com.android.internal.jank.InteractionJankMonitor;  import com.android.systemui.CoreStartable; -import com.android.systemui.res.R;  import com.android.systemui.dagger.SysUISingleton;  import com.android.systemui.dagger.qualifiers.UiBackground;  import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.res.R;  import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;  import com.android.systemui.shade.ShadeEventsModule;  import com.android.systemui.statusbar.NotificationListener; @@ -45,7 +45,6 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.Co  import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;  import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProviderImpl;  import com.android.systemui.statusbar.notification.collection.provider.NotificationVisibilityProviderImpl; -import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderModule;  import com.android.systemui.statusbar.notification.collection.provider.VisibilityLocationProviderDelegator;  import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;  import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl; @@ -54,6 +53,7 @@ import com.android.systemui.statusbar.notification.collection.render.GroupMember  import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager;  import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;  import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; +import com.android.systemui.statusbar.notification.data.NotificationDataLayerModule;  import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository;  import com.android.systemui.statusbar.notification.icon.ConversationIconManager;  import com.android.systemui.statusbar.notification.icon.IconManager; @@ -74,9 +74,9 @@ import com.android.systemui.statusbar.notification.stack.NotificationSectionsMan  import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;  import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;  import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModelModule; -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;  import com.android.systemui.statusbar.phone.KeyguardBypassController;  import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.util.kotlin.JavaAdapter;  import dagger.Binds; @@ -95,8 +95,8 @@ import javax.inject.Provider;  @Module(includes = {          CoordinatorsModule.class,          KeyguardNotificationVisibilityProviderModule.class, -        SeenNotificationsProviderModule.class,          ShadeEventsModule.class, +        NotificationDataLayerModule.class,          NotifPipelineChoreographerModule.class,          NotificationSectionHeadersModule.class,          NotificationListViewModelModule.class, @@ -206,7 +206,7 @@ public interface NotificationsModule {      static NotificationLaunchAnimatorControllerProvider provideNotifLaunchAnimControllerProvider(              NotificationExpansionRepository notificationExpansionRepository,              NotificationListContainer notificationListContainer, -            HeadsUpManagerPhone headsUpManager, +            HeadsUpManager headsUpManager,              InteractionJankMonitor jankMonitor) {          return new NotificationLaunchAnimatorControllerProvider(                  notificationExpansionRepository, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt new file mode 100644 index 000000000000..5435fb5449cd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.notification.data + +import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardStateRepositoryModule +import dagger.Module + +@Module(includes = [NotificationsKeyguardStateRepositoryModule::class]) +interface NotificationDataLayerModule diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepository.kt new file mode 100644 index 000000000000..cf03d1c5addc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepository.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.notification.data.repository + +import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator +import dagger.Binds +import dagger.Module +import javax.inject.Inject +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow + +/** View-states pertaining to notifications on the keyguard. */ +interface NotificationsKeyguardViewStateRepository { +    /** Are notifications fully hidden from view? */ +    val areNotificationsFullyHidden: Flow<Boolean> + +    /** Is a pulse expansion occurring? */ +    val isPulseExpanding: Flow<Boolean> +} + +@Module +interface NotificationsKeyguardStateRepositoryModule { +    @Binds +    fun bindImpl( +        impl: NotificationsKeyguardViewStateRepositoryImpl +    ): NotificationsKeyguardViewStateRepository +} + +@SysUISingleton +class NotificationsKeyguardViewStateRepositoryImpl +@Inject +constructor( +    wakeUpCoordinator: NotificationWakeUpCoordinator, +) : NotificationsKeyguardViewStateRepository { +    override val areNotificationsFullyHidden: Flow<Boolean> = conflatedCallbackFlow { +        val listener = +            object : NotificationWakeUpCoordinator.WakeUpListener { +                override fun onFullyHiddenChanged(isFullyHidden: Boolean) { +                    trySend(isFullyHidden) +                } +            } +        trySend(wakeUpCoordinator.notificationsFullyHidden) +        wakeUpCoordinator.addListener(listener) +        awaitClose { wakeUpCoordinator.removeListener(listener) } +    } + +    override val isPulseExpanding: Flow<Boolean> = conflatedCallbackFlow { +        val listener = +            object : NotificationWakeUpCoordinator.WakeUpListener { +                override fun onPulseExpansionChanged(expandingChanged: Boolean) { +                    trySend(expandingChanged) +                } +            } +        trySend(wakeUpCoordinator.isPulseExpanding()) +        wakeUpCoordinator.addListener(listener) +        awaitClose { wakeUpCoordinator.removeListener(listener) } +    } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractor.kt new file mode 100644 index 000000000000..87b8e55dbd1a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractor.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.notification.domain.interactor + +import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardViewStateRepository +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow + +/** Domain logic pertaining to notifications on the keyguard. */ +class NotificationsKeyguardInteractor +@Inject +constructor( +    repository: NotificationsKeyguardViewStateRepository, +) { +    /** Is a pulse expansion occurring? */ +    val isPulseExpanding: Flow<Boolean> = repository.isPulseExpanding + +    /** Are notifications fully hidden from view? */ +    val areNotificationsFullyHidden: Flow<Boolean> = repository.areNotificationsFullyHidden +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt index 5cc5e751ca8e..805a4dba111f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt @@ -26,26 +26,21 @@ import android.widget.FrameLayout  import androidx.annotation.ColorInt  import androidx.annotation.VisibleForTesting  import androidx.collection.ArrayMap -import com.android.app.animation.Interpolators  import com.android.internal.statusbar.StatusBarIcon  import com.android.internal.util.ContrastColorUtil  import com.android.settingslib.Utils  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.demomode.DemoMode  import com.android.systemui.demomode.DemoModeController -import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.FeatureFlagsClassic  import com.android.systemui.flags.Flags -import com.android.systemui.flags.Flags.NEW_AOD_TRANSITION  import com.android.systemui.flags.ViewRefactorFlag  import com.android.systemui.plugins.DarkIconDispatcher -import com.android.systemui.plugins.statusbar.StatusBarStateController  import com.android.systemui.res.R -import com.android.systemui.statusbar.CrossFadeHelper  import com.android.systemui.statusbar.NotificationListener  import com.android.systemui.statusbar.NotificationMediaManager  import com.android.systemui.statusbar.NotificationShelfController  import com.android.systemui.statusbar.StatusBarIconView -import com.android.systemui.statusbar.StatusBarState  import com.android.systemui.statusbar.notification.NotificationUtils  import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator  import com.android.systemui.statusbar.notification.collection.ListEntry @@ -60,6 +55,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController  import com.android.systemui.statusbar.phone.NotificationIconAreaController  import com.android.systemui.statusbar.phone.NotificationIconContainer  import com.android.systemui.statusbar.phone.ScreenOffAnimationController +import com.android.systemui.statusbar.policy.ConfigurationController  import com.android.systemui.statusbar.window.StatusBarWindowController  import com.android.wm.shell.bubbles.Bubbles  import java.util.Optional @@ -79,9 +75,9 @@ class NotificationIconAreaControllerViewBinderWrapperImpl  @Inject  constructor(      private val context: Context, -    private val statusBarStateController: StatusBarStateController,      private val wakeUpCoordinator: NotificationWakeUpCoordinator,      private val bypassController: KeyguardBypassController, +    private val configurationController: ConfigurationController,      private val mediaManager: NotificationMediaManager,      notificationListener: NotificationListener,      private val dozeParameters: DozeParameters, @@ -89,7 +85,7 @@ constructor(      private val bubblesOptional: Optional<Bubbles>,      demoModeController: DemoModeController,      darkIconDispatcher: DarkIconDispatcher, -    private val featureFlags: FeatureFlags, +    private val featureFlags: FeatureFlagsClassic,      private val statusBarWindowController: StatusBarWindowController,      private val screenOffAnimationController: ScreenOffAnimationController,      private val shelfIconsViewModel: NotificationIconContainerShelfViewModel, @@ -98,14 +94,12 @@ constructor(  ) :      NotificationIconAreaController,      DarkIconDispatcher.DarkReceiver, -    StatusBarStateController.StateListener,      NotificationWakeUpCoordinator.WakeUpListener,      DemoMode {      private val contrastColorUtil: ContrastColorUtil = ContrastColorUtil.getInstance(context)      private val updateStatusBarIcons = Runnable { updateStatusBarIcons() }      private val shelfRefactor = ViewRefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR) -    private val statusViewMigrated = featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)      private val tintAreas = ArrayList<Rect>()      private var iconSize = 0 @@ -118,9 +112,7 @@ constructor(      private var aodIcons: NotificationIconContainer? = null      private var aodBindJob: DisposableHandle? = null      private var aodIconAppearTranslation = 0 -    private var animationsEnabled = false      private var aodIconTint = 0 -    private var aodIconsVisible = false      private var showLowPriority = true      @VisibleForTesting @@ -133,7 +125,6 @@ constructor(          }      init { -        statusBarStateController.addCallback(this)          wakeUpCoordinator.addListener(this)          demoModeController.addCallback(this)          notificationListener.addNotificationSettingsListener(settingsListener) @@ -157,9 +148,15 @@ constructor(          }          this.aodIcons = aodIcons          this.aodIcons!!.setOnLockScreen(true) -        aodBindJob = NotificationIconContainerViewBinder.bind(aodIcons, aodIconsViewModel) -        updateAodIconsVisibility(animate = false, forceUpdate = changed) -        updateAnimations() +        aodBindJob = +            NotificationIconContainerViewBinder.bind( +                aodIcons, +                aodIconsViewModel, +                configurationController, +                dozeParameters, +                featureFlags, +                screenOffAnimationController, +            )          if (changed) {              updateAodNotificationIcons()          } @@ -171,7 +168,14 @@ constructor(      override fun setShelfIcons(icons: NotificationIconContainer) {          if (shelfRefactor.expectEnabled()) { -            NotificationIconContainerViewBinder.bind(icons, shelfIconsViewModel) +            NotificationIconContainerViewBinder.bind( +                icons, +                shelfIconsViewModel, +                configurationController, +                dozeParameters, +                featureFlags, +                screenOffAnimationController, +            )              shelfIcons = icons          }      } @@ -244,23 +248,7 @@ constructor(          notificationIcons!!.setIsolatedIconLocation(iconDrawingRect, requireStateUpdate)      } -    override fun onDozingChanged(isDozing: Boolean) { -        if (aodIcons == null) { -            return -        } -        val animate = (dozeParameters.alwaysOn && !dozeParameters.displayNeedsBlanking) -        aodIcons!!.setDozing(isDozing, animate, 0) -    } - -    override fun setAnimationsEnabled(enabled: Boolean) { -        animationsEnabled = enabled -        updateAnimations() -    } - -    override fun onStateChanged(newState: Int) { -        updateAodIconsVisibility(animate = false, forceUpdate = false) -        updateAnimations() -    } +    override fun setAnimationsEnabled(enabled: Boolean) = unsupported      override fun onThemeChanged() {          reloadAodColor() @@ -271,53 +259,11 @@ constructor(          return if (aodIcons == null) 0 else aodIcons!!.height      } -    @VisibleForTesting -    fun appearAodIcons() { -        if (aodIcons == null) { -            return -        } -        if (screenOffAnimationController.shouldAnimateAodIcons()) { -            if (!statusViewMigrated) { -                aodIcons!!.translationY = -aodIconAppearTranslation.toFloat() -            } -            aodIcons!!.alpha = 0f -            animateInAodIconTranslation() -            aodIcons!! -                .animate() -                .alpha(1f) -                .setInterpolator(Interpolators.LINEAR) -                .setDuration(AOD_ICONS_APPEAR_DURATION) -                .start() -        } else { -            aodIcons!!.alpha = 1.0f -            if (!statusViewMigrated) { -                aodIcons!!.translationY = 0f -            } -        } -    } -      override fun onFullyHiddenChanged(isFullyHidden: Boolean) { -        var animate = true -        if (!bypassController.bypassEnabled) { -            animate = dozeParameters.alwaysOn && !dozeParameters.displayNeedsBlanking -            if (!featureFlags.isEnabled(NEW_AOD_TRANSITION)) { -                // We only want the appear animations to happen when the notifications get fully -                // hidden, -                // since otherwise the unhide animation overlaps -                animate = animate and isFullyHidden -            } -        } -        updateAodIconsVisibility(animate, false /* force */)          updateAodNotificationIcons()          updateAodIconColors()      } -    override fun onPulseExpansionChanged(expandingChanged: Boolean) { -        if (expandingChanged) { -            updateAodIconsVisibility(animate = true, forceUpdate = false) -        } -    } -      override fun demoCommands(): List<String> {          val commands = ArrayList<String>()          commands.add(DemoMode.COMMAND_NOTIFICATIONS) @@ -348,7 +294,14 @@ constructor(          val layoutInflater = LayoutInflater.from(context)          notificationIconArea = inflateIconArea(layoutInflater)          notificationIcons = notificationIconArea?.findViewById(R.id.notificationIcons) -        NotificationIconContainerViewBinder.bind(notificationIcons!!, statusBarIconsViewModel) +        NotificationIconContainerViewBinder.bind( +            notificationIcons!!, +            statusBarIconsViewModel, +            configurationController, +            dozeParameters, +            featureFlags, +            screenOffAnimationController, +        )      }      private fun updateIconLayoutParams(context: Context) { @@ -598,25 +551,6 @@ constructor(          v.setDecorColor(tint)      } -    private fun updateAnimations() { -        val inShade = statusBarStateController.state == StatusBarState.SHADE -        if (aodIcons != null) { -            aodIcons!!.setAnimationsEnabled(animationsEnabled && !inShade) -        } -        notificationIcons!!.setAnimationsEnabled(animationsEnabled && inShade) -    } - -    private fun animateInAodIconTranslation() { -        if (!statusViewMigrated) { -            aodIcons!! -                .animate() -                .setInterpolator(Interpolators.DECELERATE_QUINT) -                .translationY(0f) -                .setDuration(AOD_ICONS_APPEAR_DURATION) -                .start() -        } -    } -      private fun reloadAodColor() {          aodIconTint =              Utils.getColorAttrDefaultColor( @@ -639,70 +573,13 @@ constructor(          }      } -    private fun updateAodIconsVisibility(animate: Boolean, forceUpdate: Boolean) { -        if (aodIcons == null) { -            return -        } -        var visible = (bypassController.bypassEnabled || wakeUpCoordinator.notificationsFullyHidden) - -        // Hide the AOD icons if we're not in the KEYGUARD state unless the screen off animation is -        // playing, in which case we want them to be visible since we're animating in the AOD UI and -        // will be switching to KEYGUARD shortly. -        if ( -            statusBarStateController.state != StatusBarState.KEYGUARD && -                !screenOffAnimationController.shouldShowAodIconsWhenShade() -        ) { -            visible = false -        } -        if (visible && wakeUpCoordinator.isPulseExpanding() && !bypassController.bypassEnabled) { -            visible = false -        } -        if (aodIconsVisible != visible || forceUpdate) { -            aodIconsVisible = visible -            aodIcons!!.animate().cancel() -            if (animate) { -                if (featureFlags.isEnabled(NEW_AOD_TRANSITION)) { -                    // Let's make sure the icon are translated to 0, since we cancelled it above -                    animateInAodIconTranslation() -                    if (aodIconsVisible) { -                        CrossFadeHelper.fadeIn(aodIcons) -                    } else { -                        CrossFadeHelper.fadeOut(aodIcons) -                    } -                } else { -                    val wasFullyInvisible = aodIcons!!.visibility != View.VISIBLE -                    if (aodIconsVisible) { -                        if (wasFullyInvisible) { -                            // No fading here, let's just appear the icons instead! -                            aodIcons!!.visibility = View.VISIBLE -                            aodIcons!!.alpha = 1.0f -                            appearAodIcons() -                        } else { -                            // Let's make sure the icon are translated to 0, since we cancelled it -                            // above -                            animateInAodIconTranslation() -                            // We were fading out, let's fade in instead -                            CrossFadeHelper.fadeIn(aodIcons) -                        } -                    } else { -                        // Let's make sure the icon are translated to 0, since we cancelled it above -                        animateInAodIconTranslation() -                        CrossFadeHelper.fadeOut(aodIcons) -                    } -                } -            } else { -                aodIcons!!.alpha = 1.0f -                if (!statusViewMigrated) { -                    aodIcons!!.translationY = 0f -                } -                aodIcons!!.visibility = if (visible) View.VISIBLE else View.INVISIBLE -            } -        } -    } -      companion object { -        private const val AOD_ICONS_APPEAR_DURATION: Long = 200 -          @ColorInt private val DEFAULT_AOD_ICON_COLOR = -0x1 + +        val unsupported: Nothing +            get() = +                error( +                    "Code path not supported when NOTIFICATION_ICON_CONTAINER_REFACTOR is disabled" +                )      }  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt index 8293bb329a01..0d2f00aa3627 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt @@ -15,19 +15,172 @@   */  package com.android.systemui.statusbar.notification.icon.ui.viewbinder +import android.content.res.Resources +import android.view.View +import androidx.annotation.DimenRes  import androidx.lifecycle.Lifecycle  import androidx.lifecycle.repeatOnLifecycle +import com.android.app.animation.Interpolators +import com.android.systemui.flags.FeatureFlagsClassic +import com.android.systemui.flags.Flags  import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.res.R +import com.android.systemui.statusbar.CrossFadeHelper  import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel +import com.android.systemui.statusbar.phone.DozeParameters  import com.android.systemui.statusbar.phone.NotificationIconContainer +import com.android.systemui.statusbar.phone.ScreenOffAnimationController +import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.policy.onDensityOrFontScaleChanged +import com.android.systemui.util.kotlin.stateFlow +import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.DisposableHandle +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch  /** Binds a [NotificationIconContainer] to its [view model][NotificationIconContainerViewModel]. */  object NotificationIconContainerViewBinder {      fun bind(          view: NotificationIconContainer,          viewModel: NotificationIconContainerViewModel, +        configurationController: ConfigurationController, +        dozeParameters: DozeParameters, +        featureFlags: FeatureFlagsClassic, +        screenOffAnimationController: ScreenOffAnimationController,      ): DisposableHandle { -        return view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) {} } +        return view.repeatWhenAttached { +            repeatOnLifecycle(Lifecycle.State.CREATED) { +                launch { viewModel.animationsEnabled.collect(view::setAnimationsEnabled) } +                launch { +                    viewModel.isDozing.collect { (isDozing, animate) -> +                        val animateIfNotBlanking = animate && !dozeParameters.displayNeedsBlanking +                        view.setDozing(isDozing, animateIfNotBlanking, /* delay= */ 0) { +                            viewModel.completeDozeAnimation() +                        } +                    } +                } +                // TODO(278765923): this should live where AOD is bound, not inside of the NIC +                //  view-binder +                launch { +                    val iconAppearTranslation = +                        view.resources.getConfigAwareDimensionPixelSize( +                            this, +                            configurationController, +                            R.dimen.shelf_appear_translation, +                        ) +                    bindVisibility( +                        viewModel, +                        view, +                        featureFlags, +                        screenOffAnimationController, +                        iconAppearTranslation, +                    ) { +                        viewModel.completeVisibilityAnimation() +                    } +                } +            } +        }      } +    private suspend fun bindVisibility( +        viewModel: NotificationIconContainerViewModel, +        view: NotificationIconContainer, +        featureFlags: FeatureFlagsClassic, +        screenOffAnimationController: ScreenOffAnimationController, +        iconAppearTranslation: StateFlow<Int>, +        onAnimationEnd: () -> Unit, +    ) { +        val statusViewMigrated = featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW) +        viewModel.isVisible.collect { (isVisible, animate) -> +            view.animate().cancel() +            when { +                !animate -> { +                    view.alpha = 1f +                    if (!statusViewMigrated) { +                        view.translationY = 0f +                    } +                    view.visibility = if (isVisible) View.VISIBLE else View.INVISIBLE +                } +                featureFlags.isEnabled(Flags.NEW_AOD_TRANSITION) -> { +                    animateInIconTranslation(view, statusViewMigrated) +                    if (isVisible) { +                        CrossFadeHelper.fadeIn(view, onAnimationEnd) +                    } else { +                        CrossFadeHelper.fadeOut(view, onAnimationEnd) +                    } +                } +                !isVisible -> { +                    // Let's make sure the icon are translated to 0, since we cancelled it above +                    animateInIconTranslation(view, statusViewMigrated) +                    CrossFadeHelper.fadeOut(view, onAnimationEnd) +                } +                view.visibility != View.VISIBLE -> { +                    // No fading here, let's just appear the icons instead! +                    view.visibility = View.VISIBLE +                    view.alpha = 1f +                    appearIcons( +                        view, +                        animate = screenOffAnimationController.shouldAnimateAodIcons(), +                        iconAppearTranslation.value, +                        statusViewMigrated, +                    ) +                    onAnimationEnd() +                } +                else -> { +                    // Let's make sure the icons are translated to 0, since we cancelled it above +                    animateInIconTranslation(view, statusViewMigrated) +                    // We were fading out, let's fade in instead +                    CrossFadeHelper.fadeIn(view, onAnimationEnd) +                } +            } +        } +    } + +    private fun appearIcons( +        view: View, +        animate: Boolean, +        iconAppearTranslation: Int, +        statusViewMigrated: Boolean, +    ) { +        if (animate) { +            if (!statusViewMigrated) { +                view.translationY = -iconAppearTranslation.toFloat() +            } +            view.alpha = 0f +            animateInIconTranslation(view, statusViewMigrated) +            view +                .animate() +                .alpha(1f) +                .setInterpolator(Interpolators.LINEAR) +                .setDuration(AOD_ICONS_APPEAR_DURATION) +                .start() +        } else { +            view.alpha = 1.0f +            if (!statusViewMigrated) { +                view.translationY = 0f +            } +        } +    } + +    private fun animateInIconTranslation(view: View, statusViewMigrated: Boolean) { +        if (!statusViewMigrated) { +            view +                .animate() +                .setInterpolator(Interpolators.DECELERATE_QUINT) +                .translationY(0f) +                .setDuration(AOD_ICONS_APPEAR_DURATION) +                .start() +        } +    } + +    private const val AOD_ICONS_APPEAR_DURATION: Long = 200  } + +fun Resources.getConfigAwareDimensionPixelSize( +    scope: CoroutineScope, +    configurationController: ConfigurationController, +    @DimenRes id: Int, +): StateFlow<Int> = +    scope.stateFlow( +        changedSignals = configurationController.onDensityOrFontScaleChanged, +        getValue = { getDimensionPixelSize(id) } +    ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt index f68b0ef79638..3289a3ce5574 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt @@ -15,8 +15,146 @@   */  package com.android.systemui.statusbar.notification.icon.ui.viewmodel +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor +import com.android.systemui.flags.FeatureFlagsClassic +import com.android.systemui.flags.Flags +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.TransitionStep +import com.android.systemui.shade.domain.interactor.ShadeInteractor +import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor +import com.android.systemui.statusbar.phone.DozeParameters +import com.android.systemui.statusbar.phone.ScreenOffAnimationController +import com.android.systemui.util.kotlin.pairwise +import com.android.systemui.util.kotlin.sample +import com.android.systemui.util.ui.AnimatableEvent +import com.android.systemui.util.ui.AnimatedValue +import com.android.systemui.util.ui.toAnimatedValueFlow  import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map  /** View-model for the row of notification icons displayed on the always-on display. */ -class NotificationIconContainerAlwaysOnDisplayViewModel @Inject constructor() : -    NotificationIconContainerViewModel +@SysUISingleton +class NotificationIconContainerAlwaysOnDisplayViewModel +@Inject +constructor( +    private val deviceEntryInteractor: DeviceEntryInteractor, +    private val dozeParameters: DozeParameters, +    private val featureFlags: FeatureFlagsClassic, +    keyguardInteractor: KeyguardInteractor, +    keyguardTransitionInteractor: KeyguardTransitionInteractor, +    private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor, +    screenOffAnimationController: ScreenOffAnimationController, +    shadeInteractor: ShadeInteractor, +) : NotificationIconContainerViewModel { + +    private val onDozeAnimationComplete = MutableSharedFlow<Unit>(extraBufferCapacity = 1) +    private val onVisAnimationComplete = MutableSharedFlow<Unit>(extraBufferCapacity = 1) + +    override val animationsEnabled: Flow<Boolean> = +        combine( +            shadeInteractor.isShadeTouchable, +            keyguardInteractor.isKeyguardVisible, +        ) { panelTouchesEnabled, isKeyguardVisible -> +            panelTouchesEnabled && isKeyguardVisible +        } + +    override val isDozing: Flow<AnimatedValue<Boolean>> = +        keyguardTransitionInteractor.startedKeyguardTransitionStep +            // Determine if we're dozing based on the most recent transition +            .map { step: TransitionStep -> +                val isDozing = step.to == KeyguardState.AOD || step.to == KeyguardState.DOZING +                isDozing to step +            } +            // Only emit changes based on whether we've started or stopped dozing +            .distinctUntilChanged { (wasDozing, _), (isDozing, _) -> wasDozing != isDozing } +            // Determine whether we need to animate +            .map { (isDozing, step) -> +                val animate = step.to == KeyguardState.AOD || step.from == KeyguardState.AOD +                AnimatableEvent(isDozing, animate) +            } +            .distinctUntilChanged() +            .toAnimatedValueFlow(completionEvents = onDozeAnimationComplete) + +    override val isVisible: Flow<AnimatedValue<Boolean>> = +        combine( +                keyguardTransitionInteractor.finishedKeyguardState.map { it != KeyguardState.GONE }, +                deviceEntryInteractor.isBypassEnabled, +                areNotifsFullyHiddenAnimated(), +                isPulseExpandingAnimated(), +            ) { +                onKeyguard: Boolean, +                bypassEnabled: Boolean, +                (notifsFullyHidden: Boolean, isAnimatingHide: Boolean), +                (pulseExpanding: Boolean, isAnimatingPulse: Boolean), +                -> +                val isAnimating = isAnimatingHide || isAnimatingPulse +                when { +                    // Hide the AOD icons if we're not in the KEYGUARD state unless the screen off +                    // animation is playing, in which case we want them to be visible if we're +                    // animating in the AOD UI and will be switching to KEYGUARD shortly. +                    !onKeyguard && !screenOffAnimationController.shouldShowAodIconsWhenShade() -> +                        AnimatedValue(false, isAnimating = false) +                    // If we're bypassing, then we're visible +                    bypassEnabled -> AnimatedValue(true, isAnimating) +                    // If we are pulsing (and not bypassing), then we are hidden +                    pulseExpanding -> AnimatedValue(false, isAnimating) +                    // If notifs are fully gone, then we're visible +                    notifsFullyHidden -> AnimatedValue(true, isAnimating) +                    // Otherwise, we're hidden +                    else -> AnimatedValue(false, isAnimating) +                } +            } +            .distinctUntilChanged() + +    override fun completeDozeAnimation() { +        onDozeAnimationComplete.tryEmit(Unit) +    } + +    override fun completeVisibilityAnimation() { +        onVisAnimationComplete.tryEmit(Unit) +    } + +    /** Is there an expanded pulse, are we animating in response? */ +    private fun isPulseExpandingAnimated(): Flow<AnimatedValue<Boolean>> { +        return notificationsKeyguardInteractor.isPulseExpanding +            .pairwise(initialValue = null) +            // If pulsing changes, start animating, unless it's the first emission +            .map { (prev, expanding) -> +                AnimatableEvent(expanding!!, startAnimating = prev != null) +            } +            .toAnimatedValueFlow(completionEvents = onVisAnimationComplete) +    } + +    /** Are notifications completely hidden from view, are we animating in response? */ +    private fun areNotifsFullyHiddenAnimated(): Flow<AnimatedValue<Boolean>> { +        return notificationsKeyguardInteractor.areNotificationsFullyHidden +            .pairwise(initialValue = null) +            .sample(deviceEntryInteractor.isBypassEnabled) { (prev, fullyHidden), bypassEnabled -> +                val animate = +                    when { +                        // Don't animate for the first value +                        prev == null -> false +                        // Always animate if bypass is enabled. +                        bypassEnabled -> true +                        // If we're not bypassing and we're not going to AOD, then we're not +                        // animating. +                        !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. +                        featureFlags.isEnabled(Flags.NEW_AOD_TRANSITION) -> true +                        else -> fullyHidden!! +                    } +                AnimatableEvent(fullyHidden!!, animate) +            } +            .toAnimatedValueFlow(completionEvents = onVisAnimationComplete) +    } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt index 933c76f19aee..c44a2b60142c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt @@ -15,8 +15,18 @@   */  package com.android.systemui.statusbar.notification.icon.ui.viewmodel +import com.android.systemui.util.ui.AnimatedValue  import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.flowOf  /** View-model for the overflow row of notification icons displayed in the notification shade. */  class NotificationIconContainerShelfViewModel @Inject constructor() : -    NotificationIconContainerViewModel +    NotificationIconContainerViewModel { +    override val animationsEnabled: Flow<Boolean> = flowOf(true) +    override val isDozing: Flow<AnimatedValue<Boolean>> = emptyFlow() +    override val isVisible: Flow<AnimatedValue<Boolean>> = emptyFlow() +    override fun completeDozeAnimation() {} +    override fun completeVisibilityAnimation() {} +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt index 2217646e6022..035687a4a91b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt @@ -15,8 +15,31 @@   */  package com.android.systemui.statusbar.notification.icon.ui.viewmodel +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.shade.domain.interactor.ShadeInteractor +import com.android.systemui.util.ui.AnimatedValue  import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.emptyFlow  /** View-model for the row of notification icons displayed in the status bar, */ -class NotificationIconContainerStatusBarViewModel @Inject constructor() : -    NotificationIconContainerViewModel +class NotificationIconContainerStatusBarViewModel +@Inject +constructor( +    keyguardInteractor: KeyguardInteractor, +    shadeInteractor: ShadeInteractor, +) : NotificationIconContainerViewModel { +    override val animationsEnabled: Flow<Boolean> = +        combine( +            shadeInteractor.isShadeTouchable, +            keyguardInteractor.isKeyguardShowing, +        ) { panelTouchesEnabled, isKeyguardShowing -> +            panelTouchesEnabled && !isKeyguardShowing +        } + +    override val isDozing: Flow<AnimatedValue<Boolean>> = emptyFlow() +    override val isVisible: Flow<AnimatedValue<Boolean>> = emptyFlow() +    override fun completeDozeAnimation() {} +    override fun completeVisibilityAnimation() {} +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt index 892b2be9ed6e..65eb22075ec7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt @@ -15,8 +15,32 @@   */  package com.android.systemui.statusbar.notification.icon.ui.viewmodel +import com.android.systemui.util.ui.AnimatedValue +import kotlinx.coroutines.flow.Flow +  /**   * View-model for the row of notification icons displayed in the NotificationShelf, StatusBar, and   * AOD.   */ -interface NotificationIconContainerViewModel +interface NotificationIconContainerViewModel { +    /** Are changes to the icon container animated? */ +    val animationsEnabled: Flow<Boolean> + +    /** Should icons be rendered in "dozing" mode? */ +    val isDozing: Flow<AnimatedValue<Boolean>> + +    /** Is the icon container visible? */ +    val isVisible: Flow<AnimatedValue<Boolean>> + +    /** +     * Signal completion of the [isDozing] animation; if [isDozing]'s [AnimatedValue.isAnimating] +     * property was `true`, calling this method will update it to `false. +     */ +    fun completeDozeAnimation() + +    /** +     * Signal completion of the [isVisible] animation; if [isVisible]'s [AnimatedValue.isAnimating] +     * property was `true`, calling this method will update it to `false. +     */ +    fun completeVisibilityAnimation() +} 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 c61258b5e0ec..847d94861401 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 @@ -355,12 +355,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView              AnimatorListenerAdapter animationListener) {          enableAppearDrawing(true);          mIsHeadsUpAnimation = isHeadsUpAnimation; -        if (mDrawingAppearAnimation) { -            startAppearAnimation(false /* isAppearing */, translationDirection, -                    delay, duration, onFinishedRunnable, animationListener); -        } else if (onFinishedRunnable != null) { -            onFinishedRunnable.run(); -        } +        startAppearAnimation(false /* isAppearing */, translationDirection, +                delay, duration, onFinishedRunnable, animationListener);          return 0;      } @@ -369,10 +365,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView              Runnable onFinishRunnable) {          enableAppearDrawing(true);          mIsHeadsUpAnimation = isHeadsUpAppear; -        if (mDrawingAppearAnimation) { -            startAppearAnimation(true /* isAppearing */, isHeadsUpAppear ? 0.0f : -1.0f, delay, -                    duration, null, null); -        } +        startAppearAnimation(true /* isAppearing */, isHeadsUpAppear ? 0.0f : -1.0f, delay, +                duration, null, null);      }      private void startAppearAnimation(boolean isAppearing, float translationDirection, long delay, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java index 42c80ed22717..40897dae4c44 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java @@ -42,9 +42,8 @@ import android.widget.LinearLayout;  import android.widget.TextView;  import com.android.internal.statusbar.IStatusBarService; -import com.android.systemui.Dependency; -import com.android.systemui.res.R;  import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; +import com.android.systemui.res.R;  import com.android.systemui.statusbar.notification.AssistantFeedbackController;  import com.android.systemui.statusbar.notification.collection.NotificationEntry;  import com.android.systemui.util.Compile; @@ -76,7 +75,9 @@ public class FeedbackInfo extends LinearLayout implements NotificationGuts.GutsC              final StatusBarNotification sbn,              final NotificationEntry entry,              final ExpandableNotificationRow row, -            final AssistantFeedbackController controller) { +            final AssistantFeedbackController controller, +            final IStatusBarService statusBarService, +            final NotificationGutsManager notificationGutsManager) {          mPkg = sbn.getPackageName();          mPm = pm;          mEntry = entry; @@ -84,8 +85,8 @@ public class FeedbackInfo extends LinearLayout implements NotificationGuts.GutsC          mRanking = entry.getRanking();          mFeedbackController = controller;          mAppName = mPkg; -        mStatusBarService = Dependency.get(IStatusBarService.class); -        mNotificationGutsManager = Dependency.get(NotificationGutsManager.class); +        mStatusBarService = statusBarService; +        mNotificationGutsManager = notificationGutsManager;          bindHeader();          bindPrompt(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index 6d6566058aed..9e9116bd70e7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -44,9 +44,9 @@ import com.android.internal.annotations.VisibleForTesting;  import com.android.internal.logging.MetricsLogger;  import com.android.internal.logging.UiEventLogger;  import com.android.internal.logging.nano.MetricsProto; +import com.android.internal.statusbar.IStatusBarService;  import com.android.settingslib.notification.ConversationIconFactory;  import com.android.systemui.CoreStartable; -import com.android.systemui.res.R;  import com.android.systemui.dagger.SysUISingleton;  import com.android.systemui.dagger.qualifiers.Background;  import com.android.systemui.dagger.qualifiers.Main; @@ -54,6 +54,7 @@ import com.android.systemui.people.widget.PeopleSpaceWidgetManager;  import com.android.systemui.plugins.ActivityStarter;  import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;  import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.res.R;  import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;  import com.android.systemui.settings.UserContextProvider;  import com.android.systemui.shade.ShadeController; @@ -69,8 +70,8 @@ import com.android.systemui.statusbar.notification.collection.render.NotifGutsVi  import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager;  import com.android.systemui.statusbar.notification.stack.NotificationListContainer;  import com.android.systemui.statusbar.phone.CentralSurfaces; -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;  import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.util.kotlin.JavaAdapter;  import com.android.systemui.wmshell.BubblesManager; @@ -99,6 +100,7 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta      // Dependencies:      private final NotificationLockscreenUserManager mLockscreenUserManager;      private final StatusBarStateController mStatusBarStateController; +    private final IStatusBarService mStatusBarService;      private final DeviceProvisionedController mDeviceProvisionedController;      private final AssistantFeedbackController mAssistantFeedbackController; @@ -127,7 +129,7 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta      private final ShadeController mShadeController;      private final WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;      private NotifGutsViewListener mGutsListener; -    private final HeadsUpManagerPhone mHeadsUpManagerPhone; +    private final HeadsUpManager mHeadsUpManager;      private final ActivityStarter mActivityStarter;      @Inject @@ -152,9 +154,10 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta              WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor,              NotificationLockscreenUserManager notificationLockscreenUserManager,              StatusBarStateController statusBarStateController, +            IStatusBarService statusBarService,              DeviceProvisionedController deviceProvisionedController,              MetricsLogger metricsLogger, -            HeadsUpManagerPhone headsUpManagerPhone, +            HeadsUpManager headsUpManager,              ActivityStarter activityStarter) {          mContext = context;          mMainHandler = mainHandler; @@ -177,9 +180,10 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta          mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor;          mLockscreenUserManager = notificationLockscreenUserManager;          mStatusBarStateController = statusBarStateController; +        mStatusBarService = statusBarService;          mDeviceProvisionedController = deviceProvisionedController;          mMetricsLogger = metricsLogger; -        mHeadsUpManagerPhone = headsUpManagerPhone; +        mHeadsUpManager = headsUpManager;          mActivityStarter = activityStarter;      } @@ -296,7 +300,7 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta              if (mGutsListener != null) {                  mGutsListener.onGutsClose(entry);              } -            mHeadsUpManagerPhone.setGutsShown(row.getEntry(), false); +            mHeadsUpManager.setGutsShown(row.getEntry(), false);          });          View gutsView = item.getGutsView(); @@ -358,7 +362,8 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta          PackageManager pmUser = CentralSurfaces.getPackageManagerForUser(mContext,                  userHandle.getIdentifier()); -        feedbackInfo.bindGuts(pmUser, sbn, row.getEntry(), row, mAssistantFeedbackController); +        feedbackInfo.bindGuts(pmUser, sbn, row.getEntry(), row, mAssistantFeedbackController, +                mStatusBarService, this);      }      /** @@ -676,7 +681,7 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta                  row.closeRemoteInput();                  mListContainer.onHeightChanged(row, true /* needsAnimation */);                  mGutsMenuItem = menuItem; -                mHeadsUpManagerPhone.setGutsShown(row.getEntry(), true); +                mHeadsUpManager.setGutsShown(row.getEntry(), true);              }          };          guts.post(mOpenRunnable); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 66b2555a4446..9695cb132ba9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -99,7 +99,6 @@ import com.android.systemui.statusbar.notification.collection.PipelineDumper;  import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;  import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;  import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider; -import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProvider;  import com.android.systemui.statusbar.notification.collection.provider.VisibilityLocationProviderDelegator;  import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;  import com.android.systemui.statusbar.notification.collection.render.NotifStackController; @@ -115,10 +114,10 @@ import com.android.systemui.statusbar.notification.row.ExpandableView;  import com.android.systemui.statusbar.notification.row.NotificationGuts;  import com.android.systemui.statusbar.notification.row.NotificationGutsManager;  import com.android.systemui.statusbar.notification.row.NotificationSnooze; +import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationListInteractor;  import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder;  import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel;  import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;  import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;  import com.android.systemui.statusbar.phone.KeyguardBypassController;  import com.android.systemui.statusbar.phone.NotificationIconAreaController; @@ -127,6 +126,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController;  import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;  import com.android.systemui.statusbar.policy.DeviceProvisionedController;  import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;  import com.android.systemui.statusbar.policy.SplitShadeStateController;  import com.android.systemui.statusbar.policy.ZenModeController; @@ -156,7 +156,7 @@ public class NotificationStackScrollLayoutController {      private final NotificationGutsManager mNotificationGutsManager;      private final NotificationsController mNotificationsController;      private final NotificationVisibilityProvider mVisibilityProvider; -    private final HeadsUpManagerPhone mHeadsUpManager; +    private final HeadsUpManager mHeadsUpManager;      private final NotificationRoundnessManager mNotificationRoundnessManager;      private final TunerService mTunerService;      private final DeviceProvisionedController mDeviceProvisionedController; @@ -194,7 +194,7 @@ public class NotificationStackScrollLayoutController {      private final GroupExpansionManager mGroupExpansionManager;      private final NotifPipelineFlags mNotifPipelineFlags; -    private final SeenNotificationsProvider mSeenNotificationsProvider; +    private final NotificationListInteractor mNotificationListInteractor;      private final KeyguardTransitionRepository mKeyguardTransitionRepo;      private NotificationStackScrollLayout mView; @@ -631,7 +631,7 @@ public class NotificationStackScrollLayoutController {              NotificationGutsManager notificationGutsManager,              NotificationsController notificationsController,              NotificationVisibilityProvider visibilityProvider, -            HeadsUpManagerPhone headsUpManager, +            HeadsUpManager headsUpManager,              NotificationRoundnessManager notificationRoundnessManager,              TunerService tunerService,              DeviceProvisionedController deviceProvisionedController, @@ -662,7 +662,7 @@ public class NotificationStackScrollLayoutController {              UiEventLogger uiEventLogger,              NotificationRemoteInputManager remoteInputManager,              VisibilityLocationProviderDelegator visibilityLocationProviderDelegator, -            SeenNotificationsProvider seenNotificationsProvider, +            NotificationListInteractor notificationListInteractor,              ShadeController shadeController,              InteractionJankMonitor jankMonitor,              StackStateLogger stackLogger, @@ -715,7 +715,7 @@ public class NotificationStackScrollLayoutController {          mUiEventLogger = uiEventLogger;          mRemoteInputManager = remoteInputManager;          mVisibilityLocationProviderDelegator = visibilityLocationProviderDelegator; -        mSeenNotificationsProvider = seenNotificationsProvider; +        mNotificationListInteractor = notificationListInteractor;          mShadeController = shadeController;          mNotifIconAreaController = notifIconAreaController;          mFeatureFlags = featureFlags; @@ -2006,7 +2006,7 @@ public class NotificationStackScrollLayoutController {          public void setNotifStats(@NonNull NotifStats notifStats) {              mNotifStats = notifStats;              mView.setHasFilteredOutSeenNotifications( -                    mSeenNotificationsProvider.getHasFilteredOutSeenNotifications()); +                    mNotificationListInteractor.getHasFilteredOutSeenNotifications().getValue());              updateFooter();              updateShowEmptyShadeView();          } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationListRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationListRepository.kt new file mode 100644 index 000000000000..f6ed8c884816 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationListRepository.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.stack.data.repository + +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +/** Repository for information about the current notification list. */ +@SysUISingleton +class NotificationListRepository @Inject constructor() { +    private val _hasFilteredOutSeenNotifications = MutableStateFlow(false) +    val hasFilteredOutSeenNotifications: StateFlow<Boolean> = +        _hasFilteredOutSeenNotifications.asStateFlow() + +    fun setHasFilteredOutSeenNotifications(value: Boolean) { +        _hasFilteredOutSeenNotifications.value = value +    } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationListInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationListInteractor.kt new file mode 100644 index 000000000000..3fd68a8bdd7c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationListInteractor.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.stack.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.stack.data.repository.NotificationListRepository +import javax.inject.Inject +import kotlinx.coroutines.flow.StateFlow + +/** Interactor for business logic associated with the notification stack. */ +@SysUISingleton +class NotificationListInteractor +@Inject +constructor( +    private val notificationListRepository: NotificationListRepository, +) { +    /** Are any already-seen notifications currently filtered out of the shade? */ +    val hasFilteredOutSeenNotifications: StateFlow<Boolean> +        get() = notificationListRepository.hasFilteredOutSeenNotifications + +    fun setHasFilteredOutSeenNotifications(value: Boolean) { +        notificationListRepository.setHasFilteredOutSeenNotifications(value) +    } +} 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 3e2f10dd1a0c..6e6318e780dc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -220,6 +220,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController.Configurati  import com.android.systemui.statusbar.policy.DeviceProvisionedController;  import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;  import com.android.systemui.statusbar.policy.ExtensionController; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.KeyguardStateController;  import com.android.systemui.statusbar.policy.UserInfoControllerImpl;  import com.android.systemui.statusbar.policy.UserSwitcherController; @@ -236,6 +237,8 @@ import com.android.wm.shell.bubbles.Bubbles;  import com.android.wm.shell.startingsurface.SplashscreenContentDrawer;  import com.android.wm.shell.startingsurface.StartingSurface; +import dagger.Lazy; +  import java.io.PrintWriter;  import java.io.StringWriter;  import java.util.List; @@ -247,8 +250,6 @@ import javax.inject.Inject;  import javax.inject.Named;  import javax.inject.Provider; -import dagger.Lazy; -  /**   * A class handling initialization and coordination between some of the key central surfaces in   * System UI: The notification shade, the keyguard (lockscreen), and the status bar. @@ -417,7 +418,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {      private final NotificationWakeUpCoordinator mWakeUpCoordinator;      private final KeyguardBypassController mKeyguardBypassController;      private final KeyguardStateController mKeyguardStateController; -    private final HeadsUpManagerPhone mHeadsUpManager; +    private final HeadsUpManager mHeadsUpManager;      private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;      private final FalsingCollector mFalsingCollector;      private final FalsingManager mFalsingManager; @@ -611,7 +612,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {              NotificationWakeUpCoordinator notificationWakeUpCoordinator,              KeyguardBypassController keyguardBypassController,              KeyguardStateController keyguardStateController, -            HeadsUpManagerPhone headsUpManagerPhone, +            HeadsUpManager headsUpManager,              DynamicPrivacyController dynamicPrivacyController,              FalsingManager falsingManager,              FalsingCollector falsingCollector, @@ -718,7 +719,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {          mWakeUpCoordinator = notificationWakeUpCoordinator;          mKeyguardBypassController = keyguardBypassController;          mKeyguardStateController = keyguardStateController; -        mHeadsUpManager = headsUpManagerPhone; +        mHeadsUpManager = headsUpManager;          mBackActionInteractor = backActionInteractor;          mKeyguardIndicationController = keyguardIndicationController;          mStatusBarTouchableRegionManager = statusBarTouchableRegionManager; @@ -1088,11 +1089,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {      void initShadeVisibilityListener() {          mShadeController.setVisibilityListener(new ShadeController.ShadeVisibilityListener() {              @Override -            public void visibilityChanged(boolean visible) { -                onShadeVisibilityChanged(visible); -            } - -            @Override              public void expandedVisibleChanged(boolean expandedVisible) {                  if (expandedVisible) {                      setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); @@ -1195,7 +1191,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {                  });          mStatusBarInitializer.initializeStatusBar(); -        mStatusBarTouchableRegionManager.setup(this, getNotificationShadeWindowView()); +        mStatusBarTouchableRegionManager.setup(getNotificationShadeWindowView());          createNavigationBar(result); @@ -2688,7 +2684,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {                  !mDozeServiceHost.isPulsing(), mDeviceProvisionedController.isFrpActive());          mShadeSurface.setTouchAndAnimationDisabled(disabled); -        mNotificationIconAreaController.setAnimationsEnabled(!disabled); +        if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) { +            mNotificationIconAreaController.setAnimationsEnabled(!disabled); +        }      }      final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { @@ -2844,13 +2842,16 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {          mScrimController.setExpansionAffectsAlpha(!unlocking);          if (mAlternateBouncerInteractor.isVisibleState()) { -            if ((!mKeyguardStateController.isOccluded() || mShadeSurface.isPanelExpanded()) -                    && (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED -                    || mTransitionToFullShadeProgress > 0f)) { -                mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED_SHADE); -            } else { -                mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED); +            if (!mFeatureFlags.isEnabled(Flags.ALTERNATE_BOUNCER_VIEW)) { +                if ((!mKeyguardStateController.isOccluded() || mShadeSurface.isPanelExpanded()) +                        && (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED +                        || mTransitionToFullShadeProgress > 0f)) { +                    mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED_SHADE); +                } else { +                    mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED); +                }              } +              // This will cancel the keyguardFadingAway animation if it is running. We need to do              // this as otherwise it can remain pending and leave keyguard in a weird state.              mUnlockScrimCallback.onCancelled(); @@ -2913,8 +2914,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {      protected boolean mDeviceInteractive; -    protected boolean mVisible; -      protected DevicePolicyManager mDevicePolicyManager;      private final PowerManager mPowerManager;      protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @@ -3032,16 +3031,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {                  afterKeyguardGone);      } -    private void onShadeVisibilityChanged(boolean visible) { -        if (mVisible != visible) { -            mVisible = visible; -            if (visible) { -                DejankUtils.notifyRendererOfExpensiveFrame( -                        getNotificationShadeWindowView(), "onShadeVisibilityChanged"); -            } -        } -    } -      private void clearNotificationEffects() {          try {              mBarService.clearNotificationEffects(); @@ -3163,7 +3152,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {              // TODO: Bring these out of CentralSurfaces.              mUserInfoControllerImpl.onDensityOrFontScaleChanged();              mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext); -            mHeadsUpManager.onDensityOrFontScaleChanged();          }          @Override @@ -3200,7 +3188,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {                      // down on the lockscreen), clear notification LED, vibration,                      // ringing.                      // Other transitions are covered in WindowRootViewVisibilityInteractor. -                    if (mVisible && (newState == StatusBarState.SHADE_LOCKED +                    if (mWindowRootViewVisibilityInteractor.isLockscreenOrShadeVisible().getValue() +                            && (newState == StatusBarState.SHADE_LOCKED                              || mStatusBarStateController.goingToFullShade())) {                          clearNotificationEffects();                      } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java index 4849f64659d0..d3d11ea4a9f3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java @@ -49,6 +49,7 @@ import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator  import com.android.systemui.statusbar.notification.collection.NotificationEntry;  import com.android.systemui.statusbar.policy.BatteryController;  import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;  import com.android.systemui.util.Assert; @@ -80,7 +81,7 @@ public final class DozeServiceHost implements DozeHost {      private final WakefulnessLifecycle mWakefulnessLifecycle;      private final SysuiStatusBarStateController mStatusBarStateController;      private final DeviceProvisionedController mDeviceProvisionedController; -    private final HeadsUpManagerPhone mHeadsUpManagerPhone; +    private final HeadsUpManager mHeadsUpManager;      private final BatteryController mBatteryController;      private final ScrimController mScrimController;      private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy; @@ -106,7 +107,7 @@ public final class DozeServiceHost implements DozeHost {              WakefulnessLifecycle wakefulnessLifecycle,              SysuiStatusBarStateController statusBarStateController,              DeviceProvisionedController deviceProvisionedController, -            HeadsUpManagerPhone headsUpManagerPhone, BatteryController batteryController, +            HeadsUpManager headsUpManager, BatteryController batteryController,              ScrimController scrimController,              Lazy<BiometricUnlockController> biometricUnlockControllerLazy,              Lazy<AssistManager> assistManagerLazy, @@ -123,7 +124,7 @@ public final class DozeServiceHost implements DozeHost {          mWakefulnessLifecycle = wakefulnessLifecycle;          mStatusBarStateController = statusBarStateController;          mDeviceProvisionedController = deviceProvisionedController; -        mHeadsUpManagerPhone = headsUpManagerPhone; +        mHeadsUpManager = headsUpManager;          mBatteryController = batteryController;          mScrimController = scrimController;          mBiometricUnlockControllerLazy = biometricUnlockControllerLazy; @@ -135,7 +136,7 @@ public final class DozeServiceHost implements DozeHost {          mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;          mAuthController = authController;          mNotificationIconAreaController = notificationIconAreaController; -        mHeadsUpManagerPhone.addListener(mOnHeadsUpChangedListener); +        mHeadsUpManager.addListener(mOnHeadsUpChangedListener);          mDozeInteractor = dozeInteractor;      } @@ -337,8 +338,8 @@ public final class DozeServiceHost implements DozeHost {          if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH) {              mScrimController.setWakeLockScreenSensorActive(true);          } -        if (mDozeScrimController.isPulsing() && mHeadsUpManagerPhone.hasNotifications()) { -            mHeadsUpManagerPhone.extendHeadsUp(); +        if (mDozeScrimController.isPulsing() && mHeadsUpManager.hasNotifications()) { +            mHeadsUpManager.extendHeadsUp();          } else {              mDozeScrimController.extendPulse();          } @@ -493,7 +494,7 @@ public final class DozeServiceHost implements DozeHost {                      mDozeScrimController.cancelPendingPulseTimeout();                  }              } -            if (!isHeadsUp && !mHeadsUpManagerPhone.hasNotifications()) { +            if (!isHeadsUp && !mHeadsUpManager.hasNotifications()) {                  // There are no longer any notifications to show.  We should end the                  // pulse now.                  stopPulsing(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java index 270c40e801cd..c493eeda7077 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java @@ -26,9 +26,9 @@ import androidx.annotation.NonNull;  import com.android.internal.annotations.VisibleForTesting;  import com.android.internal.widget.ViewClippingUtil; -import com.android.systemui.res.R;  import com.android.systemui.plugins.DarkIconDispatcher;  import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.res.R;  import com.android.systemui.shade.ShadeHeadsUpTracker;  import com.android.systemui.shade.ShadeViewController;  import com.android.systemui.statusbar.CommandQueue; @@ -43,6 +43,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationRoundnessMa  import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;  import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentScope;  import com.android.systemui.statusbar.policy.Clock; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.KeyguardStateController;  import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;  import com.android.systemui.util.ViewController; @@ -70,7 +71,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar      private static final SourceType HEADS_UP = SourceType.from("HeadsUp");      private static final SourceType PULSING = SourceType.from("Pulsing");      private final NotificationIconAreaController mNotificationIconAreaController; -    private final HeadsUpManagerPhone mHeadsUpManager; +    private final HeadsUpManager mHeadsUpManager;      private final NotificationStackScrollLayoutController mStackScrollerController;      private final DarkIconDispatcher mDarkIconDispatcher; @@ -108,7 +109,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar      @Inject      public HeadsUpAppearanceController(              NotificationIconAreaController notificationIconAreaController, -            HeadsUpManagerPhone headsUpManager, +            HeadsUpManager headsUpManager,              StatusBarStateController stateController,              PhoneStatusBarTransitions phoneStatusBarTransitions,              KeyguardBypassController bypassController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index a5ea1426164b..6b4382f731ea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -29,11 +29,11 @@ import androidx.collection.ArraySet;  import com.android.internal.annotations.VisibleForTesting;  import com.android.internal.logging.UiEventLogger;  import com.android.internal.policy.SystemBarUtils; -import com.android.systemui.Dumpable; -import com.android.systemui.res.R; +import com.android.systemui.dagger.SysUISingleton;  import com.android.systemui.dagger.qualifiers.Main;  import com.android.systemui.plugins.statusbar.StatusBarStateController;  import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; +import com.android.systemui.res.R;  import com.android.systemui.shade.ShadeExpansionStateManager;  import com.android.systemui.statusbar.StatusBarState;  import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -42,10 +42,12 @@ import com.android.systemui.statusbar.notification.collection.provider.VisualSta  import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;  import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;  import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; +import com.android.systemui.statusbar.policy.AnimationStateHandler; +import com.android.systemui.statusbar.policy.BaseHeadsUpManager;  import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;  import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; +import com.android.systemui.statusbar.policy.OnHeadsUpPhoneListenerChange;  import java.io.PrintWriter;  import java.util.ArrayList; @@ -53,11 +55,11 @@ import java.util.HashSet;  import java.util.List;  import java.util.Stack; -/** - * A implementation of HeadsUpManager for phone and car. - */ -public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, -        OnHeadsUpChangedListener { +import javax.inject.Inject; + +/** A implementation of HeadsUpManager for phone. */ +@SysUISingleton +public class HeadsUpManagerPhone extends BaseHeadsUpManager implements OnHeadsUpChangedListener {      private static final String TAG = "HeadsUpManagerPhone";      @VisibleForTesting @@ -102,7 +104,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,      ///////////////////////////////////////////////////////////////////////////////////////////////      //  Constructor: - +    @Inject      public HeadsUpManagerPhone(@NonNull final Context context,              HeadsUpManagerLogger logger,              StatusBarStateController statusBarStateController, @@ -154,7 +156,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,      /**       * Add a listener to receive callbacks onHeadsUpGoingAway       */ -    void addHeadsUpPhoneListener(OnHeadsUpPhoneListenerChange listener) { +    @Override +    public void addHeadsUpPhoneListener(OnHeadsUpPhoneListenerChange listener) {          mHeadsUpPhoneListeners.add(listener);      } @@ -162,7 +165,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,       * Gets the touchable region needed for heads up notifications. Returns null if no touchable       * region is required (ie: no heads up notification currently exists).       */ -    @Nullable Region getTouchableRegion() { +    @Override +    public @Nullable Region getTouchableRegion() {          NotificationEntry topEntry = getTopEntry();          // This call could be made in an inconsistent state while the pinnedMode hasn't been @@ -197,8 +201,9 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,       * @param key the key of the touched notification       * @return whether the touch is invalid and should be discarded       */ -    boolean shouldSwallowClick(@NonNull String key) { -        HeadsUpManager.HeadsUpEntry entry = getHeadsUpEntry(key); +    @Override +    public boolean shouldSwallowClick(@NonNull String key) { +        BaseHeadsUpManager.HeadsUpEntry entry = getHeadsUpEntry(key);          return entry != null && mClock.currentTimeMillis() < entry.mPostTime;      } @@ -238,7 +243,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,       * 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.       */ -    void setHeadsUpGoingAway(boolean headsUpGoingAway) { +    @Override +    public void setHeadsUpGoingAway(boolean headsUpGoingAway) {          if (headsUpGoingAway != mHeadsUpGoingAway) {              mHeadsUpGoingAway = headsUpGoingAway;              for (OnHeadsUpPhoneListenerChange listener : mHeadsUpPhoneListeners) { @@ -247,7 +253,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,          }      } -    boolean isHeadsUpGoingAway() { +    @Override +    public boolean isHeadsUpGoingAway() {          return mHeadsUpGoingAway;      } @@ -260,8 +267,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,      public void setRemoteInputActive(              @NonNull NotificationEntry entry, boolean remoteInputActive) {          HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(entry.getKey()); -        if (headsUpEntry != null && headsUpEntry.remoteInputActive != remoteInputActive) { -            headsUpEntry.remoteInputActive = remoteInputActive; +        if (headsUpEntry != null && headsUpEntry.mRemoteInputActive != remoteInputActive) { +            headsUpEntry.mRemoteInputActive = remoteInputActive;              if (remoteInputActive) {                  headsUpEntry.removeAutoRemovalCallbacks("setRemoteInputActive(true)");              } else { @@ -313,6 +320,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,          mSwipedOutKeys.add(key);      } +    @Override      public boolean removeNotification(@NonNull String key, boolean releaseImmediately,              boolean animate) {          if (animate) { @@ -411,7 +419,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,      ///////////////////////////////////////////////////////////////////////////////////////////////      //  HeadsUpEntryPhone: -    protected class HeadsUpEntryPhone extends HeadsUpManager.HeadsUpEntry { +    protected class HeadsUpEntryPhone extends BaseHeadsUpManager.HeadsUpEntry {          private boolean mGutsShownPinned; @@ -459,11 +467,11 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,          @Override          public void setExpanded(boolean expanded) { -            if (this.expanded == expanded) { +            if (this.mExpanded == expanded) {                  return;              } -            this.expanded = expanded; +            this.mExpanded = expanded;              if (expanded) {                  removeAutoRemovalCallbacks("setExpanded(true)");              } else { @@ -504,21 +512,6 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,          }      } -    public interface AnimationStateHandler { -        void setHeadsUpGoingAwayAnimationsAllowed(boolean allowed); -    } - -    /** -     * Listener to register for HeadsUpNotification Phone changes. -     */ -    public interface OnHeadsUpPhoneListenerChange { -        /** -         * Called when a heads up notification is 'going away' or no longer 'going away'. -         * See {@link HeadsUpManagerPhone#setHeadsUpGoingAway}. -         */ -        void onHeadsUpGoingAwayStateChanged(boolean headsUpGoingAway); -    } -      private final StateListener mStatusBarStateListener = new StateListener() {          @Override          public void onStateChanged(int newState) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt new file mode 100644 index 000000000000..0d0f2cd50a29 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt @@ -0,0 +1,11 @@ +package com.android.systemui.statusbar.phone + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.policy.HeadsUpManager +import dagger.Binds +import dagger.Module + +@Module +interface HeadsUpModule { +    @Binds @SysUISingleton fun bindsHeadsUpManager(hum: HeadsUpManagerPhone): HeadsUpManager +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java index dcbaac20eacc..198272e9b162 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java @@ -26,13 +26,14 @@ import com.android.systemui.Gefingerpoken;  import com.android.systemui.statusbar.notification.collection.NotificationEntry;  import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;  import com.android.systemui.statusbar.notification.row.ExpandableView; +import com.android.systemui.statusbar.policy.HeadsUpManager;  /**   * A helper class to handle touches on the heads-up views.   */  public class HeadsUpTouchHelper implements Gefingerpoken { -    private final HeadsUpManagerPhone mHeadsUpManager; +    private final HeadsUpManager mHeadsUpManager;      private final IStatusBarService mStatusBarService;      private final Callback mCallback;      private int mTrackingPointer; @@ -45,7 +46,7 @@ public class HeadsUpTouchHelper implements Gefingerpoken {      private final HeadsUpNotificationViewController mPanel;      private ExpandableNotificationRow mPickedChild; -    public HeadsUpTouchHelper(HeadsUpManagerPhone headsUpManager, +    public HeadsUpTouchHelper(HeadsUpManager headsUpManager,              IStatusBarService statusBarService,              Callback callback,              HeadsUpNotificationViewController notificationPanelView) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java index 7cbaf63bc6db..b15c0fdd5a4c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -33,6 +33,7 @@ import android.view.View;  import android.view.ViewGroup;  import android.view.animation.Interpolator; +import androidx.annotation.Nullable;  import androidx.annotation.VisibleForTesting;  import androidx.collection.ArrayMap; @@ -624,12 +625,32 @@ public class NotificationIconContainer extends ViewGroup {      }      public void setDozing(boolean dozing, boolean fade, long delay) { +        setDozing(dozing, fade, delay, /* endRunnable= */ null); +    } + +    public void setDozing(boolean dozing, boolean fade, long delay, +            @Nullable Runnable endRunnable) {          mDozing = dozing;          mDisallowNextAnimation |= !fade; -        for (int i = 0; i < getChildCount(); i++) { +        final int childCount = getChildCount(); +        // Track all the child invocations of setDozing, invoking the top-level endRunnable once +        // they have all completed. +        final Runnable onChildCompleted = endRunnable == null ? null : new Runnable() { +            private int mPendingCallbacks = childCount; + +            @Override +            public void run() { +                if (--mPendingCallbacks == 0) { +                    endRunnable.run(); +                } +            } +        }; +        for (int i = 0; i < childCount; i++) {              View view = getChildAt(i);              if (view instanceof StatusBarIconView) { -                ((StatusBarIconView) view).setDozing(dozing, fade, delay); +                ((StatusBarIconView) view).setDozing(dozing, fade, delay, onChildCompleted); +            } else if (onChildCompleted != null) { +                onChildCompleted.run();              }          }      } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java index 4b39854e43ff..235ed25e2ea1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java @@ -24,6 +24,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager;  import com.android.systemui.statusbar.NotificationShadeWindowController;  import com.android.systemui.statusbar.StatusBarState;  import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;  import com.android.systemui.statusbar.window.StatusBarWindowController; @@ -39,7 +40,7 @@ public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener,      private final ShadeViewController mShadeViewController;      private final NotificationStackScrollLayoutController mNsslController;      private final KeyguardBypassController mKeyguardBypassController; -    private final HeadsUpManagerPhone mHeadsUpManager; +    private final HeadsUpManager mHeadsUpManager;      private final StatusBarStateController mStatusBarStateController;      private final NotificationRemoteInputManager mNotificationRemoteInputManager; @@ -50,7 +51,7 @@ public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener,              ShadeViewController shadeViewController,              NotificationStackScrollLayoutController nsslController,              KeyguardBypassController keyguardBypassController, -            HeadsUpManagerPhone headsUpManager, +            HeadsUpManager headsUpManager,              StatusBarStateController statusBarStateController,              NotificationRemoteInputManager notificationRemoteInputManager) {          mNotificationShadeWindowController = notificationShadeWindowController; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index eedf35f1e9d4..62b2445de13a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -1573,6 +1573,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb       * notification shade's child views.       */      public boolean shouldInterceptTouchEvent(MotionEvent event) { +        if (mFlags.isEnabled(Flags.ALTERNATE_BOUNCER_VIEW)) { +            return false; +        }          return mAlternateBouncerInteractor.isVisibleState();      } @@ -1581,6 +1584,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb       * showing.       */      public boolean onTouch(MotionEvent event) { +        if (mFlags.isEnabled(Flags.ALTERNATE_BOUNCER_VIEW)) { +            return false; +        } +          boolean handleTouch = shouldInterceptTouchEvent(event);          if (handleTouch) {              final boolean actionDown = event.getActionMasked() == MotionEvent.ACTION_DOWN; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index dc4c7095237e..dbee080f238d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -76,6 +76,7 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte  import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;  import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowDragController;  import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.HeadsUpUtil;  import com.android.systemui.statusbar.policy.KeyguardStateController;  import com.android.systemui.wmshell.BubblesManager; @@ -102,7 +103,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit      private final Executor mUiBgExecutor;      private final NotificationVisibilityProvider mVisibilityProvider; -    private final HeadsUpManagerPhone mHeadsUpManager; +    private final HeadsUpManager mHeadsUpManager;      private final ActivityStarter mActivityStarter;      private final NotificationClickNotifier mClickNotifier;      private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @@ -141,7 +142,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit              Handler mainThreadHandler,              Executor uiBgExecutor,              NotificationVisibilityProvider visibilityProvider, -            HeadsUpManagerPhone headsUpManager, +            HeadsUpManager headsUpManager,              ActivityStarter activityStarter,              NotificationClickNotifier clickNotifier,              StatusBarKeyguardViewManager statusBarKeyguardViewManager, @@ -213,7 +214,9 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit       */      @Override      public void onNotificationClicked(NotificationEntry entry, ExpandableNotificationRow row) { -        mLogger.logStartingActivityFromClick(entry); +        mLogger.logStartingActivityFromClick(entry, row.isHeadsUpState(), +                mKeyguardStateController.isVisible(), +                mNotificationShadeWindowController.getPanelExpanded());          if (mRemoteInputManager.isRemoteInputActive(entry)) {              // We have an active remote input typed and the user clicked on the notification. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt index 2d30a12c3948..4211cabcbc56 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt @@ -30,11 +30,16 @@ import javax.inject.Inject  class StatusBarNotificationActivityStarterLogger @Inject constructor(      @NotifInteractionLog private val buffer: LogBuffer  ) { -    fun logStartingActivityFromClick(entry: NotificationEntry) { +    fun logStartingActivityFromClick(entry: NotificationEntry, isHeadsUpState: Boolean, +                                     isKeyguardVisible: Boolean, isPanelExpanded: Boolean) {          buffer.log(TAG, DEBUG, {              str1 = entry.logKey +            bool1 = isHeadsUpState +            bool2 = isKeyguardVisible +            bool3 = isPanelExpanded          }, { -            "(1/5) onNotificationClicked: $str1" +            "(1/5) onNotificationClicked: $str1 isHeadsUpState: $bool1 " + +                    "isKeyguardVisible: $bool2 isPanelExpanded: $bool3"          })      } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index fb7f9d1ec19b..2d14f6b3c508 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -31,11 +31,11 @@ import android.view.View;  import com.android.internal.statusbar.IStatusBarService;  import com.android.systemui.InitController; -import com.android.systemui.res.R;  import com.android.systemui.dagger.SysUISingleton;  import com.android.systemui.plugins.ActivityStarter;  import com.android.systemui.plugins.ActivityStarter.OnDismissAction;  import com.android.systemui.power.domain.interactor.PowerInteractor; +import com.android.systemui.res.R;  import com.android.systemui.shade.NotificationShadeWindowView;  import com.android.systemui.shade.QuickSettingsController;  import com.android.systemui.shade.ShadeViewController; @@ -60,6 +60,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager;  import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;  import com.android.systemui.statusbar.notification.stack.NotificationListContainer;  import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.KeyguardStateController;  import javax.inject.Inject; @@ -76,7 +77,7 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu      private final NotificationMediaManager mMediaManager;      private final NotificationGutsManager mGutsManager;      private final ShadeViewController mNotificationPanel; -    private final HeadsUpManagerPhone mHeadsUpManager; +    private final HeadsUpManager mHeadsUpManager;      private final AboveShelfObserver mAboveShelfObserver;      private final DozeScrimController mDozeScrimController;      private final NotificationsInteractor mNotificationsInteractor; @@ -98,7 +99,7 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu              Context context,              ShadeViewController panel,              QuickSettingsController quickSettingsController, -            HeadsUpManagerPhone headsUp, +            HeadsUpManager headsUp,              NotificationShadeWindowView statusBarWindow,              ActivityStarter activityStarter,              NotificationStackScrollLayoutController stackScrollerController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java index 40bd8d3446b5..ba73c1098637 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java @@ -31,15 +31,18 @@ import android.view.WindowInsets;  import com.android.internal.policy.SystemBarUtils;  import com.android.systemui.Dumpable; -import com.android.systemui.res.R;  import com.android.systemui.ScreenDecorations; +import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor; +import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;  import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.res.R;  import com.android.systemui.scene.domain.interactor.SceneInteractor;  import com.android.systemui.scene.shared.flag.SceneContainerFlags;  import com.android.systemui.shade.ShadeExpansionStateManager;  import com.android.systemui.statusbar.NotificationShadeWindowController;  import com.android.systemui.statusbar.policy.ConfigurationController;  import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;  import com.android.systemui.util.kotlin.JavaAdapter; @@ -58,13 +61,12 @@ public final class StatusBarTouchableRegionManager implements Dumpable {      private static final String TAG = "TouchableRegionManager";      private final Context mContext; -    private final HeadsUpManagerPhone mHeadsUpManager; +    private final HeadsUpManager mHeadsUpManager;      private final NotificationShadeWindowController mNotificationShadeWindowController;      private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;      private boolean mIsStatusBarExpanded = false;      private boolean mShouldAdjustInsets = false; -    private CentralSurfaces mCentralSurfaces;      private View mNotificationShadeWindowView;      private View mNotificationPanelView;      private boolean mForceCollapsedUntilLayout = false; @@ -72,6 +74,8 @@ public final class StatusBarTouchableRegionManager implements Dumpable {      private Region mTouchableRegion = new Region();      private int mDisplayCutoutTouchableRegionSize;      private int mStatusBarHeight; +    private final PrimaryBouncerInteractor mPrimaryBouncerInteractor; +    private final AlternateBouncerInteractor mAlternateBouncerInteractor;      private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener; @@ -80,12 +84,14 @@ public final class StatusBarTouchableRegionManager implements Dumpable {              Context context,              NotificationShadeWindowController notificationShadeWindowController,              ConfigurationController configurationController, -            HeadsUpManagerPhone headsUpManager, +            HeadsUpManager headsUpManager,              ShadeExpansionStateManager shadeExpansionStateManager,              Provider<SceneInteractor> sceneInteractor,              Provider<JavaAdapter> javaAdapter,              SceneContainerFlags sceneContainerFlags, -            UnlockedScreenOffAnimationController unlockedScreenOffAnimationController +            UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, +            PrimaryBouncerInteractor primaryBouncerInteractor, +            AlternateBouncerInteractor alternateBouncerInteractor      ) {          mContext = context;          initResources(); @@ -128,13 +134,12 @@ public final class StatusBarTouchableRegionManager implements Dumpable {                      this::onShadeExpansionFullyChanged);          } +        mPrimaryBouncerInteractor = primaryBouncerInteractor; +        mAlternateBouncerInteractor = alternateBouncerInteractor;          mOnComputeInternalInsetsListener = this::onComputeInternalInsets;      } -    protected void setup( -            @NonNull CentralSurfaces centralSurfaces, -            @NonNull View notificationShadeWindowView) { -        mCentralSurfaces = centralSurfaces; +    protected void setup(@NonNull View notificationShadeWindowView) {          mNotificationShadeWindowView = notificationShadeWindowView;          mNotificationPanelView = mNotificationShadeWindowView.findViewById(R.id.notification_panel);      } @@ -260,7 +265,8 @@ public final class StatusBarTouchableRegionManager implements Dumpable {          // since we don't want stray touches to go through the light reveal scrim to whatever is          // underneath.          return mIsStatusBarExpanded -                || mCentralSurfaces.isBouncerShowing() +                || mPrimaryBouncerInteractor.isShowing().getValue() +                || mAlternateBouncerInteractor.isVisibleState()                  || mUnlockedScreenOffAnimationController.isAnimationPlaying();      } 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 babd435c62ba..63c022c5bb6b 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 @@ -38,11 +38,11 @@ import com.android.app.animation.Interpolators;  import com.android.app.animation.InterpolatorsAndroidX;  import com.android.keyguard.KeyguardUpdateMonitor;  import com.android.systemui.Dumpable; -import com.android.systemui.res.R;  import com.android.systemui.dagger.qualifiers.Main;  import com.android.systemui.dump.DumpManager;  import com.android.systemui.flags.FeatureFlags;  import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.res.R;  import com.android.systemui.shade.ShadeExpansionStateManager;  import com.android.systemui.shade.ShadeViewController;  import com.android.systemui.statusbar.CommandQueue; @@ -74,8 +74,6 @@ import com.android.systemui.util.CarrierConfigTracker.CarrierConfigChangedListen  import com.android.systemui.util.CarrierConfigTracker.DefaultDataSubscriptionChangedListener;  import com.android.systemui.util.settings.SecureSettings; -import kotlin.Unit; -  import java.io.PrintWriter;  import java.util.ArrayList;  import java.util.Arrays; @@ -85,6 +83,7 @@ import java.util.Set;  import java.util.concurrent.Executor;  import javax.inject.Inject; +import kotlin.Unit;  /**   * Contains the collapsed status bar and handles hiding/showing based on disable flags @@ -279,7 +278,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue      public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {          super.onViewCreated(view, savedInstanceState);          mDumpManager.registerDumpable(getClass().getSimpleName(), this); -        mStatusBarFragmentComponent = mStatusBarFragmentComponentFactory.create(this); +        mStatusBarFragmentComponent = mStatusBarFragmentComponentFactory.create( +                (PhoneStatusBarView) getView());          mStatusBarFragmentComponent.init();          mStartableStates.clear();          for (Startable startable : mStatusBarFragmentComponent.getStartables()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java index d9a58442d856..0618abbf00d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java @@ -27,11 +27,11 @@ import com.android.systemui.statusbar.phone.StatusBarBoundsProvider;  import com.android.systemui.statusbar.phone.StatusBarDemoMode;  import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment; -import java.util.Set; -  import dagger.BindsInstance;  import dagger.Subcomponent; +import java.util.Set; +  /**   * A subcomponent that gets re-created each time we create a new {@link CollapsedStatusBarFragment}.   * @@ -54,7 +54,7 @@ public interface StatusBarFragmentComponent {      @Subcomponent.Factory      interface Factory {          StatusBarFragmentComponent create( -                @BindsInstance CollapsedStatusBarFragment collapsedStatusBarFragment); +                @BindsInstance @RootView PhoneStatusBarView phoneStatusBarView);      }      /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java index 6ef877bd57bf..3741f143dd8d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java @@ -19,15 +19,14 @@ package com.android.systemui.statusbar.phone.fragment.dagger;  import android.view.View;  import android.view.ViewStub; -import com.android.systemui.res.R;  import com.android.systemui.battery.BatteryMeterView;  import com.android.systemui.dagger.qualifiers.RootView; +import com.android.systemui.res.R;  import com.android.systemui.statusbar.HeadsUpStatusBarView;  import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions;  import com.android.systemui.statusbar.phone.PhoneStatusBarView;  import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;  import com.android.systemui.statusbar.phone.StatusBarLocation; -import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;  import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;  import com.android.systemui.statusbar.policy.Clock;  import com.android.systemui.statusbar.window.StatusBarWindowController; @@ -51,15 +50,6 @@ public interface StatusBarFragmentModule {      /** */      @Provides -    @RootView -    @StatusBarFragmentScope -    static PhoneStatusBarView providePhoneStatusBarView( -            CollapsedStatusBarFragment collapsedStatusBarFragment) { -        return (PhoneStatusBarView) collapsedStatusBarFragment.getView(); -    } - -    /** */ -    @Provides      @StatusBarFragmentScope      static BatteryMeterView provideBatteryMeterView(@RootView PhoneStatusBarView view) {          return view.findViewById(R.id.battery); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java index e59ec044bece..cec76f3140cd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java @@ -34,8 +34,8 @@ import com.android.internal.logging.MetricsLogger;  import com.android.internal.logging.UiEvent;  import com.android.internal.logging.UiEventLogger;  import com.android.systemui.EventLogTags; -import com.android.systemui.res.R;  import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.res.R;  import com.android.systemui.statusbar.AlertingNotificationManager;  import com.android.systemui.statusbar.notification.collection.NotificationEntry;  import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; @@ -47,7 +47,8 @@ import java.io.PrintWriter;   * A manager which handles heads up notifications which is a special mode where   * they simply peek from the top of the screen.   */ -public abstract class HeadsUpManager extends AlertingNotificationManager { +public abstract class BaseHeadsUpManager extends AlertingNotificationManager implements +        HeadsUpManager {      private static final String TAG = "HeadsUpManager";      private static final String SETTING_HEADS_UP_SNOOZE_LENGTH_MS = "heads_up_snooze_length_ms"; @@ -81,7 +82,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {          }      } -    public HeadsUpManager(@NonNull final Context context, +    public BaseHeadsUpManager(@NonNull final Context context,              HeadsUpManagerLogger logger,              @Main Handler handler,              AccessibilityManagerWrapper accessibilityManagerWrapper, @@ -131,6 +132,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {          mListeners.remove(listener);      } +    /** Updates the notification with the given key. */      public void updateNotification(@NonNull String key, boolean alert) {          super.updateNotification(key, alert);          HeadsUpEntry headsUpEntry = getHeadsUpEntry(key); @@ -146,7 +148,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {              // the NotificationEntry into AlertingNotificationManager's mAlertEntries map.              return hasFullScreenIntent(entry);          } -        return hasFullScreenIntent(entry) && !headsUpEntry.wasUnpinned; +        return hasFullScreenIntent(entry) && !headsUpEntry.mWasUnpinned;      }      protected boolean hasFullScreenIntent(@NonNull NotificationEntry entry) { @@ -154,11 +156,11 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {      }      protected void setEntryPinned( -            @NonNull HeadsUpManager.HeadsUpEntry headsUpEntry, boolean isPinned) { +            @NonNull BaseHeadsUpManager.HeadsUpEntry headsUpEntry, boolean isPinned) {          mLogger.logSetEntryPinned(headsUpEntry.mEntry, isPinned);          NotificationEntry entry = headsUpEntry.mEntry;          if (!isPinned) { -            headsUpEntry.wasUnpinned = true; +            headsUpEntry.mWasUnpinned = true;          }          if (entry.isRowPinned() != isPinned) {              entry.setRowPinned(isPinned); @@ -292,10 +294,12 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {          mUser = user;      } +    /** Returns the ID of the current user. */      public int getUser() {          return  mUser;      } +    @Override      public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {          pw.println("HeadsUpManager state:");          dumpInternal(pw, args); @@ -309,9 +313,9 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {          for (AlertEntry entry: mAlertEntries.values()) {              pw.print("  HeadsUpEntry="); pw.println(entry.mEntry);          } -        int N = mSnoozedPackages.size(); -        pw.println("  snoozed packages: " + N); -        for (int i = 0; i < N; i++) { +        int n = mSnoozedPackages.size(); +        pw.println("  snoozed packages: " + n); +        for (int i = 0; i < n; i++) {              pw.print("    "); pw.print(mSnoozedPackages.valueAt(i));              pw.print(", "); pw.println(mSnoozedPackages.keyAt(i));          } @@ -399,20 +403,20 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {       *       * @param entry the entry that might be indirectly removed by the user's action       * -     * @see com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator#mActionPressListener +     * @see HeadsUpCoordinator#mActionPressListener       * @see #canRemoveImmediately(String)       */      public void setUserActionMayIndirectlyRemove(@NonNull NotificationEntry entry) {          HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.getKey());          if (headsUpEntry != null) { -            headsUpEntry.userActionMayIndirectlyRemove = true; +            headsUpEntry.mUserActionMayIndirectlyRemove = true;          }      }      @Override      public boolean canRemoveImmediately(@NonNull String key) {          HeadsUpEntry headsUpEntry = getHeadsUpEntry(key); -        if (headsUpEntry != null && headsUpEntry.userActionMayIndirectlyRemove) { +        if (headsUpEntry != null && headsUpEntry.mUserActionMayIndirectlyRemove) {              return true;          }          return super.canRemoveImmediately(key); @@ -424,9 +428,6 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {          return new HeadsUpEntry();      } -    public void onDensityOrFontScaleChanged() { -    } -      /**       * Determines if the notification is for a critical call that must display on top of an active       * input notification. @@ -445,16 +446,16 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {       * lifecycle automatically when created.       */      protected class HeadsUpEntry extends AlertEntry { -        public boolean remoteInputActive; -        public boolean userActionMayIndirectlyRemove; +        public boolean mRemoteInputActive; +        public boolean mUserActionMayIndirectlyRemove; -        protected boolean expanded; -        protected boolean wasUnpinned; +        protected boolean mExpanded; +        protected boolean mWasUnpinned;          @Override          public boolean isSticky() { -            return (mEntry.isRowPinned() && expanded) -                    || remoteInputActive +            return (mEntry.isRowPinned() && mExpanded) +                    || mRemoteInputActive                      || hasFullScreenIntent(mEntry);          } @@ -490,9 +491,9 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {                  return 1;              } -            if (remoteInputActive && !headsUpEntry.remoteInputActive) { +            if (mRemoteInputActive && !headsUpEntry.mRemoteInputActive) {                  return -1; -            } else if (!remoteInputActive && headsUpEntry.remoteInputActive) { +            } else if (!mRemoteInputActive && headsUpEntry.mRemoteInputActive) {                  return 1;              } @@ -500,14 +501,14 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {          }          public void setExpanded(boolean expanded) { -            this.expanded = expanded; +            this.mExpanded = expanded;          }          @Override          public void reset() {              super.reset(); -            expanded = false; -            remoteInputActive = false; +            mExpanded = false; +            mRemoteInputActive = false;          }          @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt new file mode 100644 index 000000000000..21acfb41f10c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package com.android.systemui.statusbar.policy + +import com.android.systemui.common.coroutine.ConflatedCallbackFlow +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow + +/** + * A [Flow] that emits whenever screen density or font scale has changed. + * + * @see ConfigurationController.ConfigurationListener.onDensityOrFontScaleChanged + */ +val ConfigurationController.onDensityOrFontScaleChanged: Flow<Unit> +    get() = +        ConflatedCallbackFlow.conflatedCallbackFlow { +            val listener = +                object : ConfigurationController.ConfigurationListener { +                    override fun onDensityOrFontScaleChanged() { +                        trySend(Unit) +                    } +                } +            addCallback(listener) +            awaitClose { removeCallback(listener) } +        } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt new file mode 100644 index 000000000000..d9527fe98b1a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt @@ -0,0 +1,245 @@ +package com.android.systemui.statusbar.policy + +import android.graphics.Region +import com.android.systemui.Dumpable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import dagger.Binds +import dagger.Module +import java.io.PrintWriter +import java.util.stream.Stream +import javax.inject.Inject + +/** + * A manager which handles heads up notifications which is a special mode where they simply peek + * from the top of the screen. + */ +interface HeadsUpManager : Dumpable { +    /** The stream of all current notifications managed by this manager. */ +    val allEntries: Stream<NotificationEntry> + +    /** Add a listener to receive callbacks onHeadsUpGoingAway. */ +    fun addHeadsUpPhoneListener(listener: OnHeadsUpPhoneListenerChange) + +    /** Adds an OnHeadUpChangedListener to observe events. */ +    fun addListener(listener: OnHeadsUpChangedListener) + +    fun addSwipedOutNotification(key: String) + +    /** +     * Whether or not the alert can be removed currently. If it hasn't been on screen long enough it +     * should not be removed unless forced +     * +     * @param key the key to check if removable +     * @return true if the alert entry can be removed +     */ +    fun canRemoveImmediately(key: String): Boolean + +    /** +     * Compare two entries and decide how they should be ranked. +     * +     * @return -1 if the first argument should be ranked higher than the second, 1 if the second one +     *   should be ranked higher and 0 if they are equal. +     */ +    fun compare(a: NotificationEntry?, b: NotificationEntry?): Int +    /** +     * Extends the lifetime of the currently showing pulsing notification so that the pulse lasts +     * longer. +     */ +    fun extendHeadsUp() + +    /** Returns when a HUN entry should be removed in milliseconds from now. */ +    fun getEarliestRemovalTime(key: String?): Long + +    /** Returns the top Heads Up Notification, which appears to show at first. */ +    fun getTopEntry(): NotificationEntry? + +    /** +     * Gets the touchable region needed for heads up notifications. Returns null if no touchable +     * region is required (ie: no heads up notification currently exists). +     */ +    fun getTouchableRegion(): Region? + +    /** +     * Whether or not there are any active alerting notifications. +     * +     * @return true if there is an alert, false otherwise +     */ +    fun hasNotifications(): Boolean = false + +    /** Returns whether there are any pinned Heads Up Notifications or not. */ +    fun hasPinnedHeadsUp(): Boolean + +    /** Returns whether or not the given notification is alerting and managed by this manager. */ +    fun isAlerting(key: String): Boolean + +    fun isHeadsUpGoingAway(): Boolean + +    /** Returns if the given notification is snoozed or not. */ +    fun isSnoozed(packageName: String): Boolean + +    /** Returns whether the entry is (pinned and expanded) or (has an active remote input). */ +    fun isSticky(key: String?): Boolean + +    fun isTrackingHeadsUp(): Boolean + +    fun onExpandingFinished() + +    /** Removes the OnHeadUpChangedListener from the observer list. */ +    fun removeListener(listener: OnHeadsUpChangedListener) + +    /** +     * Try to remove the notification. May not succeed if the notification has not been shown long +     * enough and needs to be kept around. +     * +     * @param key the key of the notification to remove +     * @param releaseImmediately force a remove regardless of earliest removal time +     * @return true if notification is removed, false otherwise +     */ +    fun removeNotification(key: String, releaseImmediately: Boolean): Boolean + +    /** +     * Try to remove the notification. May not succeed if the notification has not been shown long +     * enough and needs to be kept around. +     * +     * @param key the key of the notification to remove +     * @param releaseImmediately force a remove regardless of earliest removal time +     * @param animate if true, animate the removal +     * @return true if notification is removed, false otherwise +     */ +    fun removeNotification(key: String, releaseImmediately: Boolean, animate: Boolean): Boolean + +    /** Clears all managed notifications. */ +    fun releaseAllImmediately() + +    fun setAnimationStateHandler(handler: AnimationStateHandler) + +    /** +     * Set an entry to be expanded and therefore stick in the heads up area if it's pinned until +     * it's collapsed again. +     */ +    fun setExpanded(entry: NotificationEntry, expanded: Boolean) + +    /** +     * Sets whether an entry's guts are exposed and therefore it should stick in the heads up area +     * if it's pinned until it's hidden again. +     */ +    fun setGutsShown(entry: NotificationEntry, gutsShown: Boolean) + +    /** +     * 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. +     */ +    fun setHeadsUpGoingAway(headsUpGoingAway: Boolean) + +    /** +     * Notifies that a remote input textbox in notification gets active or inactive. +     * +     * @param entry The entry of the target notification. +     * @param remoteInputActive True to notify active, False to notify inactive. +     */ +    fun setRemoteInputActive(entry: NotificationEntry, remoteInputActive: Boolean) + +    fun setTrackingHeadsUp(tracking: Boolean) + +    /** Sets the current user. */ +    fun setUser(user: Int) + +    /** +     * Notes that the user took an action on an entry that might indirectly cause the system or the +     * app to remove the notification. +     * +     * @param entry the entry that might be indirectly removed by the user's action +     * @see +     *   com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator.mActionPressListener +     * @see .canRemoveImmediately +     */ +    fun setUserActionMayIndirectlyRemove(entry: NotificationEntry) + +    /** +     * Decides whether a click is invalid for a notification, i.e. it has not been shown long enough +     * that a user might have consciously clicked on it. +     * +     * @param key the key of the touched notification +     * @return whether the touch is invalid and should be discarded +     */ +    fun shouldSwallowClick(key: String): Boolean + +    /** +     * Called when posting a new notification that should alert the user and appear on screen. Adds +     * the notification to be managed. +     * +     * @param entry entry to show +     */ +    fun showNotification(entry: NotificationEntry) + +    fun snooze() + +    /** +     * Unpins all pinned Heads Up Notifications. +     * +     * @param userUnPinned The unpinned action is trigger by user real operation. +     */ +    fun unpinAll(userUnPinned: Boolean) + +    fun updateNotification(key: String, alert: Boolean) +} + +/** Sets the animation state of the HeadsUpManager. */ +interface AnimationStateHandler { +    fun setHeadsUpGoingAwayAnimationsAllowed(allowed: Boolean) +} + +/** Listener to register for HeadsUpNotification Phone changes. */ +interface OnHeadsUpPhoneListenerChange { +    /** +     * Called when a heads up notification is 'going away' or no longer 'going away'. See +     * [HeadsUpManager.setHeadsUpGoingAway]. +     */ +    fun onHeadsUpGoingAwayStateChanged(headsUpGoingAway: Boolean) +} + +/* No op impl of HeadsUpManager. */ +class HeadsUpManagerEmptyImpl @Inject constructor() : HeadsUpManager { +    override val allEntries = Stream.empty<NotificationEntry>() +    override fun addHeadsUpPhoneListener(listener: OnHeadsUpPhoneListenerChange) {} +    override fun addListener(listener: OnHeadsUpChangedListener) {} +    override fun addSwipedOutNotification(key: String) {} +    override fun canRemoveImmediately(key: String) = false +    override fun compare(a: NotificationEntry?, b: NotificationEntry?) = 0 +    override fun dump(pw: PrintWriter, args: Array<out String>) {} +    override fun extendHeadsUp() {} +    override fun getEarliestRemovalTime(key: String?) = 0L +    override fun getTouchableRegion(): Region? = null +    override fun getTopEntry() = null +    override fun hasPinnedHeadsUp() = false +    override fun isAlerting(key: String) = false +    override fun isHeadsUpGoingAway() = false +    override fun isSnoozed(packageName: String) = false +    override fun isSticky(key: String?) = false +    override fun isTrackingHeadsUp() = false +    override fun onExpandingFinished() {} +    override fun releaseAllImmediately() {} +    override fun removeListener(listener: OnHeadsUpChangedListener) {} +    override fun removeNotification(key: String, releaseImmediately: Boolean) = false +    override fun removeNotification(key: String, releaseImmediately: Boolean, animate: Boolean) = +        false +    override fun setAnimationStateHandler(handler: AnimationStateHandler) {} +    override fun setExpanded(entry: NotificationEntry, expanded: Boolean) {} +    override fun setGutsShown(entry: NotificationEntry, gutsShown: Boolean) {} +    override fun setHeadsUpGoingAway(headsUpGoingAway: Boolean) {} +    override fun setRemoteInputActive(entry: NotificationEntry, remoteInputActive: Boolean) {} +    override fun setTrackingHeadsUp(tracking: Boolean) {} +    override fun setUser(user: Int) {} +    override fun setUserActionMayIndirectlyRemove(entry: NotificationEntry) {} +    override fun shouldSwallowClick(key: String): Boolean = false +    override fun showNotification(entry: NotificationEntry) {} +    override fun snooze() {} +    override fun unpinAll(userUnPinned: Boolean) {} +    override fun updateNotification(key: String, alert: Boolean) {} +} + +@Module +interface HeadsUpEmptyImplModule { +    @Binds @SysUISingleton fun bindsHeadsUpManager(noOpHum: HeadsUpManagerEmptyImpl): HeadsUpManager +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ResourcesSplitShadeStateController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ResourcesSplitShadeStateController.kt index c302d6aeadbc..859e636a7714 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ResourcesSplitShadeStateController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ResourcesSplitShadeStateController.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.policy  import android.content.res.Resources  import com.android.systemui.res.R +import javax.inject.Inject  /**   * Fake SplitShadeStateController @@ -24,7 +25,7 @@ import com.android.systemui.res.R   * Identical behaviour to legacy implementation (that used LargeScreenUtils.kt) I.E., behaviour   * based solely on resources, no extra flag logic.   */ -class ResourcesSplitShadeStateController : SplitShadeStateController { +class ResourcesSplitShadeStateController @Inject constructor() : SplitShadeStateController {      override fun shouldUseSplitNotificationShade(resources: Resources): Boolean {          return resources.getBoolean(R.bool.config_use_split_notification_shade)      } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java index a77c69236946..818ba9512e15 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java @@ -70,6 +70,7 @@ import com.android.systemui.statusbar.policy.ZenModeController;  import com.android.systemui.statusbar.policy.ZenModeControllerImpl;  import com.android.systemui.statusbar.policy.bluetooth.BluetoothRepository;  import com.android.systemui.statusbar.policy.bluetooth.BluetoothRepositoryImpl; +import com.android.systemui.statusbar.policy.data.repository.DeviceProvisioningRepositoryModule;  import dagger.Binds;  import dagger.Module; @@ -80,7 +81,7 @@ import java.util.concurrent.Executor;  import javax.inject.Named;  /** Dagger Module for code in the statusbar.policy package. */ -@Module +@Module(includes = { DeviceProvisioningRepositoryModule.class })  public interface StatusBarPolicyModule {      String DEVICE_STATE_ROTATION_LOCK_DEFAULTS = "DEVICE_STATE_ROTATION_LOCK_DEFAULTS"; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepository.kt new file mode 100644 index 000000000000..1160d657ba88 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepository.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.policy.data.repository + +import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.statusbar.policy.DeviceProvisionedController +import dagger.Binds +import dagger.Module +import javax.inject.Inject +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow + +/** Tracks state related to device provisioning. */ +interface DeviceProvisioningRepository { +    /** +     * Whether this device has been provisioned. +     * +     * @see android.provider.Settings.Global.DEVICE_PROVISIONED +     */ +    val isDeviceProvisioned: Flow<Boolean> + +    /** Whether Factory Reset Protection (FRP) is currently active, locking the device. */ +    val isFactoryResetProtectionActive: Flow<Boolean> +} + +@Module +interface DeviceProvisioningRepositoryModule { +    @Binds fun bindsImpl(impl: DeviceProvisioningRepositoryImpl): DeviceProvisioningRepository +} + +class DeviceProvisioningRepositoryImpl +@Inject +constructor( +    private val deviceProvisionedController: DeviceProvisionedController, +) : DeviceProvisioningRepository { + +    override val isDeviceProvisioned: Flow<Boolean> = conflatedCallbackFlow { +        val listener = +            object : DeviceProvisionedController.DeviceProvisionedListener { +                override fun onDeviceProvisionedChanged() { +                    trySend(deviceProvisionedController.isDeviceProvisioned) +                } +            } +        deviceProvisionedController.addCallback(listener) +        trySend(deviceProvisionedController.isDeviceProvisioned) +        awaitClose { deviceProvisionedController.removeCallback(listener) } +    } + +    override val isFactoryResetProtectionActive: Flow<Boolean> = conflatedCallbackFlow { +        val listener = +            object : DeviceProvisionedController.DeviceProvisionedListener { +                override fun onFrpActiveChanged() { +                    trySend(deviceProvisionedController.isFrpActive) +                } +            } +        deviceProvisionedController.addCallback(listener) +        trySend(deviceProvisionedController.isFrpActive) +        awaitClose { deviceProvisionedController.removeCallback(listener) } +    } +} diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt index ce9d6fd752c5..dbc3bf3a75a2 100644 --- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt @@ -325,6 +325,7 @@ constructor(                              addAction(Intent.ACTION_USER_SWITCHED)                              addAction(Intent.ACTION_USER_STOPPED)                              addAction(Intent.ACTION_USER_UNLOCKED) +                            addAction(Intent.ACTION_LOCALE_CHANGED)                          },                      user = UserHandle.SYSTEM,                      map = { intent, _ -> intent }, @@ -615,6 +616,7 @@ constructor(      ) {          val shouldRefreshAllUsers =              when (intent.action) { +                Intent.ACTION_LOCALE_CHANGED -> true                  Intent.ACTION_USER_SWITCHED -> {                      dismissDialog()                      val selectedUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1) @@ -644,6 +646,11 @@ constructor(      }      private fun restartSecondaryService(@UserIdInt userId: Int) { +        // Do not start service for user that is marked for deletion. +        if (!manager.aliveUsers.map { it.id }.contains(userId)) { +            return +        } +          val intent = Intent(applicationContext, SystemUISecondaryUserService::class.java)          // Disconnect from the old secondary user's service          val secondaryUserId = repository.secondaryUserId @@ -657,6 +664,7 @@ constructor(          // Connect to the new secondary user's service (purely to ensure that a persistent          // SystemUI application is created for that user) +          if (userId != Process.myUserHandle().identifier) {              applicationContext.startServiceAsUser(                  intent, diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt index d3f83b1e18bd..20f0fa8cf46b 100644 --- a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt @@ -68,6 +68,7 @@ constructor(      private val hasCancelButtonBeenClicked = MutableStateFlow(false)      private val isFinishRequiredDueToExecutedAction = MutableStateFlow(false) +    private val userSwitched = MutableStateFlow(false)      /**       * Whether the observer should finish the experience. Once consumed, [onFinished] must be called @@ -89,6 +90,7 @@ constructor(      fun onFinished() {          hasCancelButtonBeenClicked.value = false          isFinishRequiredDueToExecutedAction.value = false +        userSwitched.value = false      }      /** Notifies that the user has clicked the "open menu" button. */ @@ -121,8 +123,9 @@ constructor(              hasCancelButtonBeenClicked,              // If an executed action told us to finish, we should finish,              isFinishRequiredDueToExecutedAction, -        ) { cancelButtonClicked, executedActionFinish -> -            cancelButtonClicked || executedActionFinish +            userSwitched, +        ) { cancelButtonClicked, executedActionFinish, userSwitched -> +            cancelButtonClicked || executedActionFinish || userSwitched          }      private fun toViewModel( @@ -191,7 +194,10 @@ constructor(          return if (!model.isSelectable) {              null          } else { -            { userInteractor.selectUser(model.id) } +            { +                userInteractor.selectUser(model.id) +                userSwitched.value = true +            }          }      }  } diff --git a/packages/SystemUI/src/com/android/systemui/util/ReferenceExt.kt b/packages/SystemUI/src/com/android/systemui/util/ReferenceExt.kt new file mode 100644 index 000000000000..ac04d31041b6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/ReferenceExt.kt @@ -0,0 +1,50 @@ +package com.android.systemui.util + +import java.lang.ref.SoftReference +import java.lang.ref.WeakReference +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty + +/** + * Creates a Kotlin idiomatic weak reference. + * + * Usage: + * ``` + * var weakReferenceObj: Object? by weakReference(null) + * weakReferenceObj = Object() + * ``` + */ +fun <T> weakReference(obj: T? = null): ReadWriteProperty<Any?, T?> { +    return object : ReadWriteProperty<Any?, T?> { +        var weakRef = WeakReference<T?>(obj) +        override fun getValue(thisRef: Any?, property: KProperty<*>): T? { +            return weakRef.get() +        } + +        override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) { +            weakRef = WeakReference(value) +        } +    } +} + +/** + * Creates a Kotlin idiomatic soft reference. + * + * Usage: + * ``` + * var softReferenceObj: Object? by softReference(null) + * softReferenceObj = Object() + * ``` + */ +fun <T> softReference(obj: T? = null): ReadWriteProperty<Any?, T?> { +    return object : ReadWriteProperty<Any?, T?> { +        var softRef = SoftReference<T?>(obj) +        override fun getValue(thisRef: Any?, property: KProperty<*>): T? { +            return softRef.get() +        } + +        override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) { +            softRef = SoftReference(value) +        } +    } +} diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt index 47d505ea36d5..83ff78980880 100644 --- a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt @@ -18,19 +18,24 @@ package com.android.systemui.util.kotlin  import com.android.systemui.util.time.SystemClock  import com.android.systemui.util.time.SystemClockImpl -import kotlinx.coroutines.CoroutineStart  import java.util.concurrent.atomic.AtomicReference +import kotlin.math.max +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.CoroutineStart  import kotlinx.coroutines.Dispatchers  import kotlinx.coroutines.Job  import kotlinx.coroutines.coroutineScope  import kotlinx.coroutines.delay  import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow  import kotlinx.coroutines.flow.channelFlow  import kotlinx.coroutines.flow.distinctUntilChanged  import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.map  import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn  import kotlinx.coroutines.launch -import kotlin.math.max  /**   * Returns a new [Flow] that combines the two most recent emissions from [this] using [transform]. @@ -44,8 +49,7 @@ fun <T, R> Flow<T>.pairwiseBy(transform: suspend (old: T, new: T) -> R): Flow<R>      var previousValue: Any? = noVal      collect { newVal ->          if (previousValue != noVal) { -            @Suppress("UNCHECKED_CAST") -            emit(transform(previousValue as T, newVal)) +            @Suppress("UNCHECKED_CAST") emit(transform(previousValue as T, newVal))          }          previousValue = newVal      } @@ -60,13 +64,11 @@ fun <T, R> Flow<T>.pairwiseBy(transform: suspend (old: T, new: T) -> R): Flow<R>  fun <T, R> Flow<T>.pairwiseBy(      initialValue: T,      transform: suspend (previousValue: T, newValue: T) -> R, -): Flow<R> = -    onStart { emit(initialValue) }.pairwiseBy(transform) +): Flow<R> = onStart { emit(initialValue) }.pairwiseBy(transform)  /**   * Returns a new [Flow] that combines the two most recent emissions from [this] using [transform].   * - *   * The output of [getInitialValue] will be used as the "old" value for the first emission. As   * opposed to the initial value in the above [pairwiseBy], [getInitialValue] can do some work before   * returning the initial value. @@ -76,8 +78,7 @@ fun <T, R> Flow<T>.pairwiseBy(  fun <T, R> Flow<T>.pairwiseBy(      getInitialValue: suspend () -> T,      transform: suspend (previousValue: T, newValue: T) -> R, -): Flow<R> = -    onStart { emit(getInitialValue()) }.pairwiseBy(transform) +): Flow<R> = onStart { emit(getInitialValue()) }.pairwiseBy(transform)  /**   * Returns a new [Flow] that produces the two most recent emissions from [this]. Note that the new @@ -88,8 +89,8 @@ fun <T, R> Flow<T>.pairwiseBy(  fun <T> Flow<T>.pairwise(): Flow<WithPrev<T>> = pairwiseBy(::WithPrev)  /** - * Returns a new [Flow] that produces the two most recent emissions from [this]. [initialValue] - * will be used as the "old" value for the first emission. + * Returns a new [Flow] that produces the two most recent emissions from [this]. [initialValue] will + * be used as the "old" value for the first emission.   *   * Useful for code that needs to compare the current value to the previous value.   */ @@ -102,9 +103,9 @@ data class WithPrev<T>(val previousValue: T, val newValue: T)   * Returns a new [Flow] that combines the [Set] changes between each emission from [this] using   * [transform].   * - * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause - * a change event to be emitted that contains no removals, and all elements from that first [Set] - * as additions. + * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause a + * change event to be emitted that contains no removals, and all elements from that first [Set] as + * additions.   *   * If [emitFirstEvent] is `false`, then the first emission is ignored and no changes are emitted   * until a second [Set] has been emitted from the upstream [Flow]. @@ -112,22 +113,23 @@ data class WithPrev<T>(val previousValue: T, val newValue: T)  fun <T, R> Flow<Set<T>>.setChangesBy(      transform: suspend (removed: Set<T>, added: Set<T>) -> R,      emitFirstEvent: Boolean = true, -): Flow<R> = (if (emitFirstEvent) onStart { emit(emptySet()) } else this) -    .distinctUntilChanged() -    .pairwiseBy { old: Set<T>, new: Set<T> -> -        // If an element was present in the old set, but not the new one, then it was removed -        val removed = old - new -        // If an element is present in the new set, but on the old one, then it was added -        val added = new - old -        transform(removed, added) -    } +): Flow<R> = +    (if (emitFirstEvent) onStart { emit(emptySet()) } else this) +        .distinctUntilChanged() +        .pairwiseBy { old: Set<T>, new: Set<T> -> +            // If an element was present in the old set, but not the new one, then it was removed +            val removed = old - new +            // If an element is present in the new set, but on the old one, then it was added +            val added = new - old +            transform(removed, added) +        }  /**   * Returns a new [Flow] that produces the [Set] changes between each emission from [this].   * - * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause - * a change event to be emitted that contains no removals, and all elements from that first [Set] - * as additions. + * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause a + * change event to be emitted that contains no removals, and all elements from that first [Set] as + * additions.   *   * If [emitFirstEvent] is `false`, then the first emission is ignored and no changes are emitted   * until a second [Set] has been emitted from the upstream [Flow]. @@ -153,14 +155,11 @@ fun <A, B, C> Flow<A>.sample(other: Flow<B>, transform: suspend (A, B) -> C): Fl      coroutineScope {          val noVal = Any()          val sampledRef = AtomicReference(noVal) -        val job = launch(Dispatchers.Unconfined) { -            other.collect { sampledRef.set(it) } -        } +        val job = launch(Dispatchers.Unconfined) { other.collect { sampledRef.set(it) } }          collect {              val sampled = sampledRef.get()              if (sampled != noVal) { -                @Suppress("UNCHECKED_CAST") -                emit(transform(it, sampled as B)) +                @Suppress("UNCHECKED_CAST") emit(transform(it, sampled as B))              }          }          job.cancel() @@ -181,7 +180,6 @@ fun <A> Flow<*>.sample(other: Flow<A>): Flow<A> = sample(other) { _, a -> a }   * latest value is emitted.   *   * Example: - *   * ```kotlin   * flow {   *     emit(1)     // t=0ms @@ -210,7 +208,6 @@ fun <T> Flow<T>.throttle(periodMs: Long): Flow<T> = this.throttle(periodMs, Syst   * during this period, only The latest value is emitted.   *   * Example: - *   * ```kotlin   * flow {   *     emit(1)     // t=0ms @@ -248,10 +245,11 @@ fun <T> Flow<T>.throttle(periodMs: Long, clock: SystemClock): Flow<T> = channelF                  // We create delayJob to allow cancellation during the delay period                  delayJob = launch {                      delay(timeUntilNextEmit) -                    sendJob = outerScope.launch(start = CoroutineStart.UNDISPATCHED) { -                        send(it) -                        previousEmitTimeMs = clock.elapsedRealtime() -                    } +                    sendJob = +                        outerScope.launch(start = CoroutineStart.UNDISPATCHED) { +                            send(it) +                            previousEmitTimeMs = clock.elapsedRealtime() +                        }                  }              } else {                  send(it) @@ -259,4 +257,15 @@ fun <T> Flow<T>.throttle(periodMs: Long, clock: SystemClock): Flow<T> = channelF              }          }      } -}
\ No newline at end of file +} + +/** + * Returns a [StateFlow] launched in the surrounding [CoroutineScope]. This [StateFlow] gets its + * value by invoking [getValue] whenever an event is emitted from [changedSignals]. It will also + * immediately invoke [getValue] to establish its initial value. + */ +inline fun <T> CoroutineScope.stateFlow( +    changedSignals: Flow<Unit>, +    crossinline getValue: () -> T, +): StateFlow<T> = +    changedSignals.map { getValue() }.stateIn(this, SharingStarted.Eagerly, getValue()) diff --git a/packages/SystemUI/src/com/android/systemui/util/ui/AnimatedValue.kt b/packages/SystemUI/src/com/android/systemui/util/ui/AnimatedValue.kt new file mode 100644 index 000000000000..51d2afabd7f9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/ui/AnimatedValue.kt @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.util.ui + +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.transformLatest + +/** + * A state comprised of a [value] of type [T] paired with a boolean indicating whether or not the + * [value] [isAnimating] in the UI. + */ +data class AnimatedValue<T>( +    val value: T, +    val isAnimating: Boolean, +) + +/** + * An event comprised of a [value] of type [T] paired with a [boolean][startAnimating] indicating + * whether or not this event should start an animation. + */ +data class AnimatableEvent<T>( +    val value: T, +    val startAnimating: Boolean, +) + +/** + * Returns a [Flow] that tracks an [AnimatedValue] state. The input [Flow] is used to update the + * [AnimatedValue.value], as well as [AnimatedValue.isAnimating] if the event's + * [AnimatableEvent.startAnimating] value is `true`. When [completionEvents] emits a value, the + * [AnimatedValue.isAnimating] will flip to `false`. + */ +fun <T> Flow<AnimatableEvent<T>>.toAnimatedValueFlow( +    completionEvents: Flow<Any?>, +): Flow<AnimatedValue<T>> = transformLatest { (value, startAnimating) -> +    emit(AnimatedValue(value, isAnimating = startAnimating)) +    if (startAnimating) { +        // Wait for a completion now that we've started animating +        completionEvents +            .map { Unit } // replace the event so that it's never `null` +            .firstOrNull() // `null` indicates an empty flow +            // emit the new state if the flow was not empty. +            ?.run { emit(AnimatedValue(value, isAnimating = false)) } +    } +} diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java index 750b6f95d52e..2132904caa84 100644 --- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java +++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java @@ -40,12 +40,13 @@ import com.android.internal.logging.UiEventLogger;  import com.android.keyguard.KeyguardUpdateMonitor;  import com.android.keyguard.KeyguardUpdateMonitorCallback;  import com.android.settingslib.Utils; -import com.android.systemui.res.R;  import com.android.systemui.classifier.FalsingCollector;  import com.android.systemui.dagger.qualifiers.Background;  import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;  import com.android.systemui.plugins.ActivityStarter;  import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.res.R;  import com.android.systemui.settings.UserTracker;  import com.android.systemui.statusbar.phone.KeyguardDismissUtil;  import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; @@ -68,6 +69,7 @@ public class WalletActivity extends ComponentActivity implements      private final Executor mExecutor;      private final Handler mHandler;      private final FalsingManager mFalsingManager; +    private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;      private FalsingCollector mFalsingCollector;      private final UserTracker mUserTracker;      private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @@ -91,7 +93,8 @@ public class WalletActivity extends ComponentActivity implements              UserTracker userTracker,              KeyguardUpdateMonitor keyguardUpdateMonitor,              StatusBarKeyguardViewManager keyguardViewManager, -            UiEventLogger uiEventLogger) { +            UiEventLogger uiEventLogger, +            KeyguardFaceAuthInteractor keyguardFaceAuthInteractor) {          mKeyguardStateController = keyguardStateController;          mKeyguardDismissUtil = keyguardDismissUtil;          mActivityStarter = activityStarter; @@ -103,6 +106,7 @@ public class WalletActivity extends ComponentActivity implements          mKeyguardUpdateMonitor = keyguardUpdateMonitor;          mKeyguardViewManager = keyguardViewManager;          mUiEventLogger = uiEventLogger; +        mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor;      }      @Override @@ -209,6 +213,7 @@ public class WalletActivity extends ComponentActivity implements                  true,                  Utils.getColorAttrDefaultColor(                          this, com.android.internal.R.attr.colorAccentPrimary)); +        mKeyguardFaceAuthInteractor.onWalletLaunched();          mKeyguardViewManager.requestFace(true);      } diff --git a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt index 8990583cf9de..167e3417c162 100644 --- a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt +++ b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt @@ -18,61 +18,94 @@ package com.android  import android.app.ActivityManager  import android.app.admin.DevicePolicyManager  import android.os.UserManager +import android.util.DisplayMetrics +import com.android.internal.logging.MetricsLogger  import com.android.keyguard.KeyguardSecurityModel  import com.android.keyguard.KeyguardUpdateMonitor  import com.android.systemui.GuestResumeSessionReceiver  import com.android.systemui.demomode.DemoModeController +import com.android.systemui.dump.DumpManager +import com.android.systemui.keyguard.ScreenLifecycle +import com.android.systemui.keyguard.WakefulnessLifecycle  import com.android.systemui.log.LogBuffer  import com.android.systemui.log.dagger.BroadcastDispatcherLog  import com.android.systemui.log.dagger.SceneFrameworkLog +import com.android.systemui.media.controls.ui.MediaHierarchyManager  import com.android.systemui.plugins.ActivityStarter  import com.android.systemui.plugins.DarkIconDispatcher  import com.android.systemui.plugins.statusbar.StatusBarStateController  import com.android.systemui.statusbar.NotificationListener +import com.android.systemui.statusbar.NotificationLockscreenUserManager  import com.android.systemui.statusbar.NotificationMediaManager +import com.android.systemui.statusbar.NotificationShadeDepthController +import com.android.systemui.statusbar.SysuiStatusBarStateController  import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator +import com.android.systemui.statusbar.notification.stack.AmbientState +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController +import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator  import com.android.systemui.statusbar.phone.DozeParameters  import com.android.systemui.statusbar.phone.KeyguardBypassController +import com.android.systemui.statusbar.phone.LSShadeTransitionLogger  import com.android.systemui.statusbar.phone.ScreenOffAnimationController -import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.phone.ScrimController  import com.android.systemui.statusbar.policy.DeviceProvisionedController -import com.android.systemui.statusbar.policy.SplitShadeStateController  import com.android.systemui.statusbar.window.StatusBarWindowController  import com.android.systemui.util.mockito.mock  import com.android.wm.shell.bubbles.Bubbles +import dagger.Binds  import dagger.Module  import dagger.Provides  import java.util.Optional -@Module +@Module(includes = [TestMocksModule.Bindings::class])  data class TestMocksModule(      @get:Provides val activityStarter: ActivityStarter = mock(), +    @get:Provides val ambientState: AmbientState = mock(),      @get:Provides val bubbles: Optional<Bubbles> = Optional.of(mock()), -    @get:Provides val configurationController: ConfigurationController = mock(),      @get:Provides val darkIconDispatcher: DarkIconDispatcher = mock(),      @get:Provides val demoModeController: DemoModeController = mock(),      @get:Provides val deviceProvisionedController: DeviceProvisionedController = mock(),      @get:Provides val dozeParameters: DozeParameters = mock(), +    @get:Provides val dumpManager: DumpManager = mock(),      @get:Provides val guestResumeSessionReceiver: GuestResumeSessionReceiver = mock(),      @get:Provides val keyguardBypassController: KeyguardBypassController = mock(),      @get:Provides val keyguardSecurityModel: KeyguardSecurityModel = mock(),      @get:Provides val keyguardUpdateMonitor: KeyguardUpdateMonitor = mock(), -    @get:Provides val notifListener: NotificationListener = mock(), -    @get:Provides val notifMediaManager: NotificationMediaManager = mock(), -    @get:Provides val screenOffAnimController: ScreenOffAnimationController = mock(), -    @get:Provides val splitShadeStateController: SplitShadeStateController = mock(), -    @get:Provides val statusBarStateController: StatusBarStateController = mock(), +    @get:Provides val mediaHierarchyManager: MediaHierarchyManager = mock(), +    @get:Provides val notificationListener: NotificationListener = mock(), +    @get:Provides val notificationLockscreenUserManager: NotificationLockscreenUserManager = mock(), +    @get:Provides val notificationMediaManager: NotificationMediaManager = mock(), +    @get:Provides val notificationShadeDepthController: NotificationShadeDepthController = mock(), +    @get:Provides +    val notificationStackScrollLayoutController: NotificationStackScrollLayoutController = mock(), +    @get:Provides val notificationStackSizeCalculator: NotificationStackSizeCalculator = mock(), +    @get:Provides val notificationWakeUpCoordinator: NotificationWakeUpCoordinator = mock(), +    @get:Provides val screenLifecycle: ScreenLifecycle = mock(), +    @get:Provides val screenOffAnimationController: ScreenOffAnimationController = mock(), +    @get:Provides val scrimController: ScrimController = mock(), +    @get:Provides val statusBarStateController: SysuiStatusBarStateController = mock(),      @get:Provides val statusBarWindowController: StatusBarWindowController = mock(), -    @get:Provides val wakeUpCoordinator: NotificationWakeUpCoordinator = mock(), +    @get:Provides val wakefulnessLifecycle: WakefulnessLifecycle = mock(),      // log buffers      @get:[Provides BroadcastDispatcherLog]      val broadcastDispatcherLogger: LogBuffer = mock(),      @get:[Provides SceneFrameworkLog]      val sceneLogger: LogBuffer = mock(), +    @get:Provides val lsShadeTransitionLogger: LSShadeTransitionLogger = mock(),      // framework mocks      @get:Provides val activityManager: ActivityManager = mock(),      @get:Provides val devicePolicyManager: DevicePolicyManager = mock(), +    @get:Provides val displayMetrics: DisplayMetrics = mock(), +    @get:Provides val metricsLogger: MetricsLogger = mock(),      @get:Provides val userManager: UserManager = mock(), -) +) { +    @Module +    interface Bindings { +        @Binds +        fun bindStatusBarStateController( +            sysuiStatusBarStateController: SysuiStatusBarStateController, +        ): StatusBarStateController +    } +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt index f943acd9180e..d8a2c5f76fce 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt @@ -25,7 +25,6 @@ import androidx.test.filters.SmallTest  import com.android.internal.util.LatencyTracker  import com.android.internal.widget.LockPatternUtils  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.classifier.FalsingCollector  import com.android.systemui.flags.FakeFeatureFlags @@ -47,7 +46,6 @@ import org.mockito.Mockito.`when`  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @TestableLooper.RunWithLooper  class KeyguardPasswordViewControllerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt index e09009389f8b..dc1618d128b3 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt @@ -25,7 +25,6 @@ import androidx.test.filters.SmallTest  import com.android.internal.util.LatencyTracker  import com.android.internal.widget.LockPatternUtils  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.classifier.FalsingCollector  import com.android.systemui.classifier.FalsingCollectorFake @@ -53,7 +52,6 @@ import org.mockito.Mockito.`when`  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @TestableLooper.RunWithLooper  class KeyguardPatternViewControllerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java index 8322b37151de..4a24e4a1f40f 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java @@ -31,14 +31,13 @@ import androidx.test.filters.SmallTest;  import com.android.internal.util.LatencyTracker;  import com.android.internal.widget.LockPatternUtils;  import com.android.keyguard.KeyguardSecurityModel.SecurityMode; -import com.android.systemui.res.R; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.classifier.FalsingCollector;  import com.android.systemui.classifier.FalsingCollectorFake;  import com.android.systemui.classifier.SingleTapClassifier;  import com.android.systemui.flags.FakeFeatureFlags;  import com.android.systemui.flags.Flags; +import com.android.systemui.res.R;  import org.junit.Before;  import org.junit.Test; @@ -47,7 +46,6 @@ import org.mockito.Mock;  import org.mockito.MockitoAnnotations;  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4.class)  @RunWithLooper  public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt index 2f08804d8c05..9df4dd4df4d2 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt @@ -26,7 +26,6 @@ import com.android.internal.util.LatencyTracker  import com.android.internal.widget.LockPatternUtils  import com.android.keyguard.KeyguardSecurityModel.SecurityMode  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.classifier.FalsingCollector  import com.android.systemui.classifier.FalsingCollectorFake @@ -53,7 +52,6 @@ import org.mockito.Mockito.`when`  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @TestableLooper.RunWithLooper  class KeyguardPinViewControllerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java index f3a1b68a87ae..5102957c71ed 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java @@ -69,7 +69,8 @@ public class KeyguardPresentationTest extends SysuiTestCase {          when(mMockKeyguardSliceView.getContext()).thenReturn(mContext);          when(mMockKeyguardStatusView.getContext()).thenReturn(mContext);          when(mMockKeyguardStatusView.findViewById(R.id.clock)).thenReturn(mMockKeyguardStatusView); -        when(mKeyguardStatusViewComponentFactory.build(any(KeyguardStatusView.class))) +        when(mKeyguardStatusViewComponentFactory.build(any(KeyguardStatusView.class), +                any(Display.class)))                  .thenReturn(mKeyguardStatusViewComponent);          when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())                  .thenReturn(mKeyguardClockSwitchController); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt index d54843d39d21..62f9a9dcce70 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt @@ -36,7 +36,6 @@ import com.android.internal.logging.UiEventLogger  import com.android.internal.widget.LockPatternUtils  import com.android.keyguard.KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback  import com.android.keyguard.KeyguardSecurityModel.SecurityMode -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate  import com.android.systemui.biometrics.SideFpsController @@ -100,7 +99,6 @@ import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @RunWithLooper  class KeyguardSecurityContainerControllerTest : SysuiTestCase() { @@ -812,6 +810,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {                      SceneKey.Bouncer,                      flowOf(.5f),                      false, +                    isUserInputOngoing = flowOf(false),                  )              runCurrent()              sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason") @@ -827,7 +826,8 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {                      SceneKey.Bouncer,                      SceneKey.Gone,                      flowOf(.5f), -                    false +                    false, +                    isUserInputOngoing = flowOf(false),                  )              runCurrent()              sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason") @@ -844,7 +844,8 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {                      SceneKey.Gone,                      SceneKey.Bouncer,                      flowOf(.5f), -                    false +                    false, +                    isUserInputOngoing = flowOf(false),                  )              runCurrent()              sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason") @@ -862,7 +863,8 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {                      SceneKey.Bouncer,                      SceneKey.Gone,                      flowOf(.5f), -                    false +                    false, +                    isUserInputOngoing = flowOf(false),                  )              runCurrent()              sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason") @@ -878,6 +880,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {                      SceneKey.Lockscreen,                      flowOf(.5f),                      false, +                    isUserInputOngoing = flowOf(false),                  )              runCurrent()              sceneInteractor.onSceneChanged(SceneModel(SceneKey.Lockscreen, null), "reason") @@ -895,6 +898,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {                      SceneKey.Gone,                      flowOf(.5f),                      false, +                    isUserInputOngoing = flowOf(false),                  )              runCurrent()              sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason") diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java index aad11d90f5a4..156e06843d15 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -56,11 +56,10 @@ import androidx.constraintlayout.widget.ConstraintSet;  import androidx.test.ext.junit.runners.AndroidJUnit4;  import androidx.test.filters.SmallTest; -import com.android.systemui.res.R; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.classifier.FalsingA11yDelegate;  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.settings.GlobalSettings; @@ -76,7 +75,6 @@ import org.mockito.junit.MockitoRule;  import java.util.ArrayList;  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4.class)  @TestableLooper.RunWithLooper()  public class KeyguardSecurityContainerTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java index b02b1f9df9fb..7bb6ef1c8895 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java @@ -35,10 +35,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;  import androidx.test.filters.SmallTest;  import com.android.keyguard.KeyguardSecurityModel.SecurityMode; -import com.android.systemui.res.R; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.res.R;  import org.junit.Before;  import org.junit.Rule; @@ -50,7 +49,6 @@ import org.mockito.junit.MockitoJUnit;  import org.mockito.junit.MockitoRule;  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4.class)  @TestableLooper.RunWithLooper()  public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt index d0bb5a999327..4290b8b28687 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt @@ -25,7 +25,6 @@ import androidx.test.filters.SmallTest  import com.android.internal.util.LatencyTracker  import com.android.internal.widget.LockPatternUtils  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.classifier.FalsingCollector  import com.android.systemui.flags.FakeFeatureFlags @@ -44,7 +43,6 @@ import org.mockito.Mockito.`when`  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @TestableLooper.RunWithLooper  class KeyguardSimPinViewControllerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt index 59cd26cc6b9b..31ee6411f93b 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt @@ -25,7 +25,6 @@ import androidx.test.filters.SmallTest  import com.android.internal.util.LatencyTracker  import com.android.internal.widget.LockPatternUtils  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.classifier.FalsingCollector  import com.android.systemui.flags.FakeFeatureFlags @@ -40,7 +39,6 @@ import org.mockito.Mockito  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @TestableLooper.RunWithLooper  class KeyguardSimPukViewControllerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java index e4e2b0a8d89f..9a908d778943 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java @@ -29,9 +29,9 @@ import android.testing.AndroidTestingRunner;  import android.testing.TestableLooper;  import android.view.View; -import com.android.systemui.res.R;  import com.android.systemui.plugins.ClockConfig;  import com.android.systemui.plugins.ClockController; +import com.android.systemui.res.R;  import com.android.systemui.statusbar.notification.AnimatableProperty;  import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; @@ -81,7 +81,7 @@ public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControll      public void updatePosition_primaryClockAnimation() {          ClockController mockClock = mock(ClockController.class);          when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock); -        when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", false, true)); +        when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", "", "", false, true));          mController.updatePosition(10, 15, 20f, true); @@ -96,7 +96,7 @@ public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControll      public void updatePosition_alternateClockAnimation() {          ClockController mockClock = mock(ClockController.class);          when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock); -        when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", true, true)); +        when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", "", "", true, true));          mController.updatePosition(10, 15, 20f, true); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java index 21a28222ccf4..d61ca697642a 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java @@ -39,10 +39,10 @@ import android.view.View;  import android.view.WindowManager;  import android.view.accessibility.AccessibilityManager; -import com.android.systemui.res.R;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.biometrics.AuthController;  import com.android.systemui.biometrics.AuthRippleController; +import com.android.systemui.bouncer.domain.interactor.BouncerInteractor;  import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;  import com.android.systemui.doze.util.BurnInHelperKt;  import com.android.systemui.dump.DumpManager; @@ -51,6 +51,8 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory;  import com.android.systemui.plugins.FalsingManager;  import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.res.R; +import com.android.systemui.scene.SceneTestUtils;  import com.android.systemui.statusbar.StatusBarState;  import com.android.systemui.statusbar.VibratorHelper;  import com.android.systemui.statusbar.policy.ConfigurationController; @@ -75,6 +77,8 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {      protected MockitoSession mStaticMockSession; +    protected final SceneTestUtils mSceneTestUtils = new SceneTestUtils(this); +    protected @Mock BouncerInteractor mBouncerInteractor;      protected @Mock LockIconView mLockIconView;      protected @Mock AnimatedStateListDrawable mIconDrawable;      protected @Mock Context mContext; @@ -93,6 +97,7 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {      protected @Mock AuthRippleController mAuthRippleController;      protected FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock());      protected FakeFeatureFlags mFeatureFlags; +      protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor;      protected LockIconViewController mUnderTest; @@ -148,6 +153,7 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {          mFeatureFlags.set(MIGRATE_LOCK_ICON, false);          mFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);          mFeatureFlags.set(LOCKSCREEN_ENABLE_LANDSCAPE, false); +          mUnderTest = new LockIconViewController(                  mStatusBarStateController,                  mKeyguardUpdateMonitor, @@ -168,7 +174,9 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {                  KeyguardInteractorFactory.create(mFeatureFlags).getKeyguardInteractor(),                  mFeatureFlags,                  mPrimaryBouncerInteractor, -                mContext +                mContext, +                () -> mBouncerInteractor, +                mSceneTestUtils.getSceneContainerFlags()          );      } @@ -227,8 +235,8 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {          setupLockIconViewMocks();      } -    protected void init(boolean useMigrationFlag) { -        mFeatureFlags.set(DOZING_MIGRATION_1, useMigrationFlag); +    protected void init(boolean useDozeMigrationFlag) { +        mFeatureFlags.set(DOZING_MIGRATION_1, useDozeMigrationFlag);          mUnderTest.setLockIconView(mLockIconView);      }  } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java index 7b920939263e..4bacc3dfca0d 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java @@ -26,6 +26,7 @@ import static org.mockito.ArgumentMatchers.any;  import static org.mockito.Mockito.anyBoolean;  import static org.mockito.Mockito.anyInt;  import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never;  import static org.mockito.Mockito.reset;  import static org.mockito.Mockito.verify;  import static org.mockito.Mockito.when; @@ -404,6 +405,49 @@ public class LockIconViewControllerTest extends LockIconViewControllerBaseTest {          // THEN uses perform haptic feedback          verify(mVibrator).performHapticFeedback(any(), eq(UdfpsController.LONG_PRESS)); +    } + +    @Test +    public void longPress_showBouncer_sceneContainerNotEnabled() { +        init(/* useMigrationFlag= */ false); +        mSceneTestUtils.getSceneContainerFlags().setEnabled(false); +        mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true); +        when(mFalsingManager.isFalseLongTap(anyInt())).thenReturn(false); + +        // WHEN longPress +        mUnderTest.onLongPress(); + +        // THEN show primary bouncer via keyguard view controller, not scene container +        verify(mKeyguardViewController).showPrimaryBouncer(anyBoolean()); +        verify(mBouncerInteractor, never()).showOrUnlockDevice(any()); +    } + +    @Test +    public void longPress_showBouncer() { +        init(/* useMigrationFlag= */ false); +        mSceneTestUtils.getSceneContainerFlags().setEnabled(true); +        mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true); +        when(mFalsingManager.isFalseLongTap(anyInt())).thenReturn(false); + +        // WHEN longPress +        mUnderTest.onLongPress(); + +        // THEN show primary bouncer +        verify(mKeyguardViewController, never()).showPrimaryBouncer(anyBoolean()); +        verify(mBouncerInteractor).showOrUnlockDevice(any()); +    } + +    @Test +    public void longPress_falsingTriggered_doesNotShowBouncer() { +        init(/* useMigrationFlag= */ false); +        mSceneTestUtils.getSceneContainerFlags().setEnabled(true); +        mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true); +        when(mFalsingManager.isFalseLongTap(anyInt())).thenReturn(true); + +        // WHEN longPress +        mUnderTest.onLongPress(); +        // THEN don't show primary bouncer +        verify(mBouncerInteractor, never()).showOrUnlockDevice(any());      }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt index 59c7e7669b63..8faf715521f8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt @@ -166,6 +166,9 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {          waitForIdleSync()          verify(controller).onLaunchAnimationCancelled()          verify(controller, never()).onLaunchAnimationStart(anyBoolean()) +        verify(listener).onLaunchAnimationCancelled() +        verify(listener, never()).onLaunchAnimationStart() +        assertNull(runner.delegate)      }      @Test @@ -176,6 +179,9 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {          waitForIdleSync()          verify(controller).onLaunchAnimationCancelled()          verify(controller, never()).onLaunchAnimationStart(anyBoolean()) +        verify(listener).onLaunchAnimationCancelled() +        verify(listener, never()).onLaunchAnimationStart() +        assertNull(runner.delegate)      }      @Test @@ -194,6 +200,15 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {          }      } +    @Test +    fun disposeRunner_delegateDereferenced() { +        val runner = activityLaunchAnimator.createRunner(controller) +        assertNotNull(runner.delegate) +        runner.dispose() +        waitForIdleSync() +        assertNull(runner.delegate) +    } +      private fun fakeWindow(): RemoteAnimationTarget {          val bounds = Rect(10 /* left */, 20 /* top */, 30 /* right */, 40 /* bottom */)          val taskInfo = ActivityManager.RunningTaskInfo() diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt index 0283382d02be..6ac84bc503a2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt @@ -21,6 +21,7 @@ package com.android.systemui.authentication.data.repository  import android.app.admin.DevicePolicyManager  import android.content.Intent  import android.content.pm.UserInfo +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.internal.widget.LockPatternUtils  import com.android.keyguard.KeyguardSecurityModel @@ -40,13 +41,12 @@ import kotlinx.coroutines.test.runTest  import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  import org.mockito.ArgumentMatchers.anyInt  import org.mockito.Mock  import org.mockito.MockitoAnnotations  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class AuthenticationRepositoryTest : SysuiTestCase() {      @Mock private lateinit var lockPatternUtils: LockPatternUtils diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt index a102890db7b0..2f5f4606c5f0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt @@ -17,6 +17,7 @@  package com.android.systemui.authentication.domain.interactor  import android.app.admin.DevicePolicyManager +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.authentication.data.model.AuthenticationMethodModel as DataLayerAuthenticationMethodModel @@ -35,11 +36,10 @@ import kotlinx.coroutines.test.runCurrent  import kotlinx.coroutines.test.runTest  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class AuthenticationInteractorTest : SysuiTestCase() {      private val utils = SceneTestUtils(this) diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index 2bc0171939b4..885abcb72f1a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -17,12 +17,15 @@  package com.android.systemui.biometrics;  import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; +  import static com.google.common.truth.Truth.assertThat; +  import static junit.framework.Assert.assertEquals;  import static junit.framework.Assert.assertFalse;  import static junit.framework.Assert.assertNotSame;  import static junit.framework.Assert.assertNull;  import static junit.framework.Assert.assertTrue; +  import static org.mockito.ArgumentMatchers.any;  import static org.mockito.ArgumentMatchers.anyInt;  import static org.mockito.ArgumentMatchers.anyLong; @@ -79,7 +82,6 @@ import androidx.test.filters.SmallTest;  import com.android.internal.R;  import com.android.internal.jank.InteractionJankMonitor;  import com.android.internal.widget.LockPatternUtils; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;  import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor; @@ -114,7 +116,6 @@ import java.util.Random;  @RunWith(AndroidJUnit4.class)  @RunWithLooper  @SmallTest -@RoboPilotTest  public class AuthControllerTest extends SysuiTestCase {      private static final long REQUEST_ID = 22; diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt index 73654609ad7f..d68a3131da4c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt @@ -16,36 +16,18 @@  package com.android.systemui.biometrics -import android.app.ActivityManager -import android.os.UserManager  import androidx.test.filters.SmallTest -import com.android.internal.logging.UiEventLogger -import com.android.keyguard.KeyguardUpdateMonitor +import com.android.SysUITestModule  import com.android.systemui.SysuiTestCase -import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository -import com.android.systemui.flags.FakeFeatureFlags +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.flags.FakeFeatureFlagsClassicModule  import com.android.systemui.flags.Flags -import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory -import com.android.systemui.plugins.ActivityStarter -import com.android.systemui.scene.SceneTestUtils -import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags  import com.android.systemui.shade.data.repository.FakeShadeRepository -import com.android.systemui.shade.domain.interactor.ShadeInteractor -import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository -import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor -import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository -import com.android.systemui.statusbar.policy.DeviceProvisionedController -import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController -import com.android.systemui.telephony.data.repository.FakeTelephonyRepository -import com.android.systemui.telephony.domain.interactor.TelephonyInteractor -import com.android.systemui.user.data.repository.FakeUserRepository -import com.android.systemui.user.domain.interactor.GuestUserInteractor -import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode -import com.android.systemui.user.domain.interactor.RefreshUsersScheduler -import com.android.systemui.user.domain.interactor.UserInteractor -import com.android.systemui.util.mockito.mock +import com.android.systemui.user.domain.UserDomainLayerModule +import dagger.BindsInstance +import dagger.Component  import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope  import kotlinx.coroutines.test.runCurrent  import kotlinx.coroutines.test.runTest  import org.junit.Before @@ -58,91 +40,27 @@ import org.mockito.MockitoAnnotations  @SmallTest  @OptIn(ExperimentalCoroutinesApi::class)  class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() { -    private val utils = SceneTestUtils(this) -    private val testScope = utils.testScope -    private val testDispatcher = utils.testDispatcher -    private val disableFlagsRepository = FakeDisableFlagsRepository() -    private val featureFlags = FakeFeatureFlags() -    private val keyguardRepository = FakeKeyguardRepository() -    private val shadeRepository = FakeShadeRepository() -    private val sceneContainerFlags = FakeSceneContainerFlags() -    private val sceneInteractor = utils.sceneInteractor() -    private val userSetupRepository = FakeUserSetupRepository() -    private val userRepository = FakeUserRepository() -    private val configurationRepository = FakeConfigurationRepository() -    private val sharedNotificationContainerInteractor = -        SharedNotificationContainerInteractor( -            configurationRepository, -            mContext, -            ResourcesSplitShadeStateController() -        ) - -    private lateinit var detector: AuthDialogPanelInteractionDetector -    private lateinit var shadeInteractor: ShadeInteractor -    private lateinit var userInteractor: UserInteractor + +    private val testComponent: TestComponent = +        DaggerAuthDialogPanelInteractionDetectorTest_TestComponent.factory() +            .create( +                test = this, +                featureFlags = +                    FakeFeatureFlagsClassicModule { +                        set(Flags.FACE_AUTH_REFACTOR, false) +                        set(Flags.FULL_SCREEN_USER_SWITCHER, true) +                    }, +            )      @Mock private lateinit var action: Runnable -    @Mock private lateinit var activityManager: ActivityManager -    @Mock private lateinit var activityStarter: ActivityStarter -    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController -    @Mock private lateinit var guestInteractor: GuestUserInteractor -    @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode -    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor -    @Mock private lateinit var manager: UserManager -    @Mock private lateinit var uiEventLogger: UiEventLogger + +    private val testScope = testComponent.testScope +    private val shadeRepository = testComponent.shadeRepository +    private val detector = testComponent.detector      @Before      fun setUp() {          MockitoAnnotations.initMocks(this) - -        featureFlags.set(Flags.FACE_AUTH_REFACTOR, false) -        featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true) - -        val refreshUsersScheduler = -            RefreshUsersScheduler( -                applicationScope = testScope.backgroundScope, -                mainDispatcher = testDispatcher, -                repository = userRepository, -            ) -        userInteractor = -            UserInteractor( -                applicationContext = context, -                repository = userRepository, -                activityStarter = activityStarter, -                keyguardInteractor = -                    KeyguardInteractorFactory.create(featureFlags = featureFlags) -                        .keyguardInteractor, -                featureFlags = featureFlags, -                manager = manager, -                headlessSystemUserMode = headlessSystemUserMode, -                applicationScope = testScope.backgroundScope, -                telephonyInteractor = -                    TelephonyInteractor( -                        repository = FakeTelephonyRepository(), -                    ), -                broadcastDispatcher = fakeBroadcastDispatcher, -                keyguardUpdateMonitor = keyguardUpdateMonitor, -                backgroundDispatcher = testDispatcher, -                activityManager = activityManager, -                refreshUsersScheduler = refreshUsersScheduler, -                guestUserInteractor = guestInteractor, -                uiEventLogger = uiEventLogger, -                userRestrictionChecker = mock(), -            ) -        shadeInteractor = -            ShadeInteractor( -                testScope.backgroundScope, -                disableFlagsRepository, -                sceneContainerFlags, -                { sceneInteractor }, -                keyguardRepository, -                userSetupRepository, -                deviceProvisionedController, -                userInteractor, -                sharedNotificationContainerInteractor, -                shadeRepository, -            ) -        detector = AuthDialogPanelInteractionDetector(testScope, { shadeInteractor })      }      @Test @@ -215,4 +133,27 @@ class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {              // Clean up job              detector.disable()          } + +    @SysUISingleton +    @Component( +        modules = +            [ +                SysUITestModule::class, +                UserDomainLayerModule::class, +            ] +    ) +    interface TestComponent { + +        val detector: AuthDialogPanelInteractionDetector +        val shadeRepository: FakeShadeRepository +        val testScope: TestScope + +        @Component.Factory +        interface Factory { +            fun create( +                @BindsInstance test: SysuiTestCase, +                featureFlags: FakeFeatureFlagsClassicModule, +            ): TestComponent +        } +    }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java index 8547fa33c9de..714461b715d6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java @@ -38,7 +38,6 @@ import android.view.Surface;  import androidx.test.ext.junit.runners.AndroidJUnit4;  import androidx.test.filters.SmallTest; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import kotlin.Unit; @@ -53,7 +52,6 @@ import org.mockito.Mock;  import org.mockito.MockitoAnnotations;  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4.class)  @RunWithLooper(setAsMainLooper = true)  public class BiometricDisplayListenerTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt index ab5d8bea585b..39f0d570cb26 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.biometrics  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.keyguard.logging.BiometricMessageDeferralLogger -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.dump.DumpManager  import org.junit.Assert.assertEquals @@ -34,7 +33,6 @@ import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class FaceHelpMessageDeferralTest : SysuiTestCase() {      val threshold = .75f diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt index 57cf834bfa38..ef06e0efa01d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt @@ -53,7 +53,6 @@ import androidx.test.filters.SmallTest  import com.airbnb.lottie.LottieAnimationView  import com.android.keyguard.KeyguardUpdateMonitor  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.SysuiTestableContext  import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository @@ -98,7 +97,6 @@ private const val SENSOR_ID = 1  private const val REAR_DISPLAY_MODE_DEVICE_STATE = 3  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @TestableLooper.RunWithLooper  class SideFpsControllerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt index 469f65a6cae5..e2aa984de46b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.biometrics  import android.testing.TestableLooper  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor  import com.android.systemui.dump.DumpManager @@ -35,7 +34,6 @@ import org.mockito.Mock  import org.mockito.junit.MockitoJUnit  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @TestableLooper.RunWithLooper  class UdfpsBpViewControllerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt index 21e614f3db3a..e9e9624580b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt @@ -38,7 +38,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.keyguard.KeyguardUpdateMonitor  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.animation.ActivityLaunchAnimator  import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams @@ -83,7 +82,6 @@ private const val SENSOR_HEIGHT = 60  @ExperimentalCoroutinesApi  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @RunWithLooper(setAsMainLooper = true)  class UdfpsControllerOverlayTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index ee3bd0d79ad8..a36f4e9ac217 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -20,12 +20,15 @@ import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPR  import static android.view.MotionEvent.ACTION_DOWN;  import static android.view.MotionEvent.ACTION_MOVE;  import static android.view.MotionEvent.ACTION_UP; +  import static com.android.internal.util.FunctionalUtils.ThrowingConsumer;  import static com.android.systemui.classifier.Classifier.UDFPS_AUTHENTICATION;  import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION; +  import static junit.framework.Assert.assertEquals;  import static junit.framework.Assert.assertFalse;  import static junit.framework.Assert.assertTrue; +  import static org.mockito.ArgumentMatchers.any;  import static org.mockito.ArgumentMatchers.anyBoolean;  import static org.mockito.ArgumentMatchers.anyFloat; @@ -74,8 +77,6 @@ import androidx.test.filters.SmallTest;  import com.android.internal.logging.InstanceIdSequence;  import com.android.internal.util.LatencyTracker;  import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.systemui.res.R; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.animation.ActivityLaunchAnimator;  import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams; @@ -94,6 +95,7 @@ import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardViewModels;  import com.android.systemui.log.SessionTracker;  import com.android.systemui.plugins.FalsingManager;  import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.res.R;  import com.android.systemui.statusbar.LockscreenShadeTransitionController;  import com.android.systemui.statusbar.VibratorHelper;  import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; @@ -125,7 +127,6 @@ import java.util.Optional;  import javax.inject.Provider;  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4.class)  @RunWithLooper(setAsMainLooper = true)  public class UdfpsControllerTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java index 280bfdf1aa8c..cd9189bef7f1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java @@ -27,7 +27,6 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;  import androidx.test.ext.junit.runners.AndroidJUnit4;  import androidx.test.filters.SmallTest; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import org.junit.Test; @@ -38,7 +37,6 @@ import java.util.List;  @RunWith(AndroidJUnit4.class)  @SmallTest -@RoboPilotTest  public class UdfpsDialogMeasureAdapterTest extends SysuiTestCase {      @Test      public void testUdfpsBottomSpacerHeightForPortrait() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java index 1afb223b4089..5239966f1923 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java @@ -30,7 +30,6 @@ import android.testing.TestableLooper.RunWithLooper;  import androidx.test.ext.junit.runners.AndroidJUnit4;  import androidx.test.filters.SmallTest; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.util.concurrency.FakeExecution; @@ -41,7 +40,6 @@ import org.mockito.Mock;  import org.mockito.MockitoAnnotations;  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4.class)  @RunWithLooper(setAsMainLooper = true)  public class UdfpsDisplayModeTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerTest.java index 8508f45b02f3..b018a3e2ca6c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerTest.java @@ -31,14 +31,12 @@ import android.view.MotionEvent;  import androidx.test.ext.junit.runners.AndroidJUnit4;  import androidx.test.filters.SmallTest; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.statusbar.StatusBarState;  import org.junit.Test;  import org.junit.runner.RunWith;  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4.class)  @TestableLooper.RunWithLooper(setAsMainLooper = true) diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt index 17f435b75d5a..da4548bc14c0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt @@ -21,7 +21,6 @@ import android.testing.TestableLooper  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.keyguard.KeyguardSecurityModel -import com.android.systemui.RoboPilotTest  import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository  import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepositoryImpl  import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor @@ -58,7 +57,6 @@ import org.mockito.MockitoAnnotations  @RunWith(AndroidJUnit4::class)  @SmallTest -@RoboPilotTest  @TestableLooper.RunWithLooper  @kotlinx.coroutines.ExperimentalCoroutinesApi  class UdfpsKeyguardViewLegacyControllerWithCoroutinesTest : diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt index 6d552544fee7..8b374ae54127 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt @@ -21,7 +21,6 @@ import android.testing.TestableLooper  import android.view.MotionEvent  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.biometrics.UdfpsController.UdfpsOverlayController  import com.android.systemui.statusbar.commandline.CommandRegistry @@ -40,7 +39,6 @@ import org.mockito.Mockito.`when` as whenEver  import org.mockito.junit.MockitoJUnit  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @TestableLooper.RunWithLooper  class UdfpsShellTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt index ebadfc78a079..0c8e7a5d356a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt @@ -26,7 +26,6 @@ import android.view.Surface  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams  import com.android.systemui.util.mockito.any @@ -50,7 +49,6 @@ private const val SENSOR_Y = 250  private const val SENSOR_RADIUS = 10  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @TestableLooper.RunWithLooper  class UdfpsViewTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt index 0d172706b127..2d8adca04a5e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.bouncer.domain.interactor  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.keyguard.KeyguardUpdateMonitor -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository  import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepositoryImpl @@ -43,7 +42,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class AlternateBouncerInteractorTest : SysuiTestCase() {      private lateinit var underTest: AlternateBouncerInteractor diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt index a9ba36a9fde4..915661b8a776 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt @@ -16,6 +16,7 @@  package com.android.systemui.bouncer.domain.interactor +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.authentication.data.model.AuthenticationMethodModel @@ -38,11 +39,10 @@ import kotlinx.coroutines.test.runTest  import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class BouncerInteractorTest : SysuiTestCase() {      private val utils = SceneTestUtils(this) diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt index a81ca86f338d..4aea4f329858 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.bouncer.domain.interactor  import android.view.View  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import org.junit.Before  import org.junit.Test @@ -29,7 +28,6 @@ import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class PrimaryBouncerCallbackInteractorTest : SysuiTestCase() {      private val mPrimaryBouncerCallbackInteractor = PrimaryBouncerCallbackInteractor() diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt index cb0b74f3015d..2018e614ba00 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt @@ -21,7 +21,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.keyguard.KeyguardSecurityModel  import com.android.keyguard.KeyguardUpdateMonitor -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository  import com.android.systemui.bouncer.ui.BouncerView @@ -43,7 +42,6 @@ import org.mockito.Mockito  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class PrimaryBouncerInteractorWithCoroutinesTest : SysuiTestCase() {      private lateinit var repository: FakeKeyguardBouncerRepository diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt index b5177e1587ee..8e1f5ac58b68 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt @@ -16,6 +16,7 @@  package com.android.systemui.bouncer.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.authentication.data.model.AuthenticationMethodModel @@ -29,10 +30,9 @@ import kotlinx.coroutines.flow.MutableStateFlow  import kotlinx.coroutines.test.runTest  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class AuthMethodBouncerViewModelTest : SysuiTestCase() {      private val utils = SceneTestUtils(this) diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt index b75355a82406..2c97809bf367 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt @@ -16,6 +16,7 @@  package com.android.systemui.bouncer.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.authentication.data.model.AuthenticationMethodModel as DataLayerAuthenticationMethodModel @@ -35,11 +36,10 @@ import kotlinx.coroutines.test.runCurrent  import kotlinx.coroutines.test.runTest  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class BouncerViewModelTest : SysuiTestCase() {      private val utils = SceneTestUtils(this) diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt index 333bd214fe9a..802f8e6043fd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt @@ -21,7 +21,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.keyguard.KeyguardSecurityModel  import com.android.keyguard.KeyguardUpdateMonitor -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository  import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor @@ -50,7 +49,6 @@ import org.mockito.Mockito  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @kotlinx.coroutines.ExperimentalCoroutinesApi  class KeyguardBouncerViewModelTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt index 0926399a8617..ba8dcef683c7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt @@ -16,6 +16,7 @@  package com.android.systemui.bouncer.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.authentication.data.model.AuthenticationMethodModel @@ -35,11 +36,10 @@ import kotlinx.coroutines.test.runTest  import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class PasswordBouncerViewModelTest : SysuiTestCase() {      private val utils = SceneTestUtils(this) diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt index 2e7c9aaa67e8..bfaa6edefdca 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt @@ -16,6 +16,7 @@  package com.android.systemui.bouncer.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.authentication.data.model.AuthenticationMethodModel @@ -38,11 +39,10 @@ import kotlinx.coroutines.test.runTest  import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class PatternBouncerViewModelTest : SysuiTestCase() {      private val utils = SceneTestUtils(this) diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt index 255bbe3ae231..7873899f2d35 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt @@ -16,6 +16,7 @@  package com.android.systemui.bouncer.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.authentication.data.model.AuthenticationMethodModel @@ -37,11 +38,10 @@ import kotlinx.coroutines.test.runTest  import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class PinBouncerViewModelTest : SysuiTestCase() {      private val utils = SceneTestUtils(this) @@ -92,7 +92,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {              underTest.onShown() -            assertThat(message?.text).isEqualTo(ENTER_YOUR_PIN) +            assertThat(message?.text).ignoringCase().isEqualTo(ENTER_YOUR_PIN)              assertThat(pin).isEmpty()              assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))              assertThat(underTest.authenticationMethod) @@ -209,7 +209,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {              underTest.onAuthenticateButtonClicked()              assertThat(pin).isEmpty() -            assertThat(message?.text).isEqualTo(WRONG_PIN) +            assertThat(message?.text).ignoringCase().isEqualTo(WRONG_PIN)              assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))          } @@ -227,7 +227,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {              underTest.onPinButtonClicked(4)              underTest.onPinButtonClicked(5) // PIN is now wrong!              underTest.onAuthenticateButtonClicked() -            assertThat(message?.text).isEqualTo(WRONG_PIN) +            assertThat(message?.text).ignoringCase().isEqualTo(WRONG_PIN)              assertThat(pin).isEmpty()              assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) @@ -273,7 +273,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {              ) // PIN is now wrong!              assertThat(pin).isEmpty() -            assertThat(message?.text).isEqualTo(WRONG_PIN) +            assertThat(message?.text).ignoringCase().isEqualTo(WRONG_PIN)              assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))          } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModelTest.kt index 4c279ea08fd7..55016bb1fc07 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinInputViewModelTest.kt @@ -1,5 +1,6 @@  package com.android.systemui.bouncer.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.bouncer.ui.viewmodel.EntryToken.ClearAll @@ -16,14 +17,13 @@ import java.lang.Character.isDigit  import org.junit.Assert.assertThrows  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  /**   * This test uses a mnemonic code to create and verify PinInput instances: strings of digits [0-9]   * for [Digit] tokens, as well as a `C` for the [ClearAll] token.   */  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class PinInputViewModelTest : SysuiTestCase() {      @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt index 7fa828fbfadd..3df9cbb29e4a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt @@ -9,7 +9,6 @@ import android.os.UserHandle  import android.os.UserManager  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.broadcast.BroadcastDispatcher  import com.android.systemui.coroutines.collectLastValue @@ -40,7 +39,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class CommunalWidgetRepositoryImplTest : SysuiTestCase() {      @Mock private lateinit var appWidgetManager: AppWidgetManager diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt index ddf788e47bf2..cdc42e096830 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.communal.domain.interactor  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.communal.data.repository.FakeCommunalRepository  import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository @@ -37,7 +36,6 @@ import org.mockito.Mock  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @OptIn(ExperimentalCoroutinesApi::class)  @RunWith(AndroidJUnit4::class)  class CommunalInteractorTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt index a10eb295476e..41a8be9663b7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt @@ -5,7 +5,6 @@ import androidx.constraintlayout.widget.ConstraintLayout  import androidx.constraintlayout.widget.ConstraintSet  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.communal.ui.view.layout.sections.DefaultCommunalWidgetSection  import org.junit.Before @@ -15,7 +14,6 @@ import org.mockito.Mock  import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @TestableLooper.RunWithLooper(setAsMainLooper = true)  @SmallTest diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt index 8e8cbe4a7cf2..2c80035873f0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryTest.kt @@ -1,6 +1,7 @@  package com.android.systemui.deviceentry.data.repository  import android.content.pm.UserInfo +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.internal.widget.LockPatternUtils  import com.android.systemui.SysuiTestCase @@ -11,6 +12,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController  import com.android.systemui.user.data.repository.FakeUserRepository  import com.android.systemui.util.mockito.argumentCaptor  import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.mockito.withArgCaptor  import com.google.common.truth.Truth.assertThat  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.runBlocking @@ -19,14 +21,14 @@ import kotlinx.coroutines.test.runTest  import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  import org.mockito.Mock  import org.mockito.Mockito +import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class DeviceEntryRepositoryTest : SysuiTestCase() {      @Mock private lateinit var lockPatternUtils: LockPatternUtils @@ -54,6 +56,7 @@ class DeviceEntryRepositoryTest : SysuiTestCase() {                  keyguardBypassController = keyguardBypassController,                  keyguardStateController = keyguardStateController,              ) +        testScope.runCurrent()      }      @Test @@ -66,8 +69,7 @@ class DeviceEntryRepositoryTest : SysuiTestCase() {              assertThat(isUnlocked).isFalse()              val captor = argumentCaptor<KeyguardStateController.Callback>() -            Mockito.verify(keyguardStateController, Mockito.atLeastOnce()) -                .addCallback(captor.capture()) +            verify(keyguardStateController, Mockito.atLeastOnce()).addCallback(captor.capture())              whenever(keyguardStateController.isUnlocked).thenReturn(true)              captor.value.onUnlockedChanged() @@ -98,7 +100,12 @@ class DeviceEntryRepositoryTest : SysuiTestCase() {          testScope.runTest {              whenever(keyguardBypassController.isBypassEnabled).thenAnswer { false }              whenever(keyguardBypassController.bypassEnabled).thenAnswer { false } -            assertThat(underTest.isBypassEnabled()).isFalse() +            withArgCaptor { +                    verify(keyguardBypassController).registerOnBypassStateChangedListener(capture()) +                } +                .onBypassStateChanged(false) +            runCurrent() +            assertThat(underTest.isBypassEnabled.value).isFalse()          }      @Test @@ -106,7 +113,12 @@ class DeviceEntryRepositoryTest : SysuiTestCase() {          testScope.runTest {              whenever(keyguardBypassController.isBypassEnabled).thenAnswer { true }              whenever(keyguardBypassController.bypassEnabled).thenAnswer { true } -            assertThat(underTest.isBypassEnabled()).isTrue() +            withArgCaptor { +                    verify(keyguardBypassController).registerOnBypassStateChangedListener(capture()) +                } +                .onBypassStateChanged(true) +            runCurrent() +            assertThat(underTest.isBypassEnabled.value).isTrue()          }      companion object { diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt index 55582e123969..c13fde75a068 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt @@ -1,5 +1,6 @@  package com.android.systemui.deviceentry.domain.interactor +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.authentication.data.model.AuthenticationMethodModel @@ -14,11 +15,10 @@ import kotlinx.coroutines.test.runCurrent  import kotlinx.coroutines.test.runTest  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class DeviceEntryInteractorTest : SysuiTestCase() {      private val utils = SceneTestUtils(this) @@ -218,14 +218,14 @@ class DeviceEntryInteractorTest : SysuiTestCase() {      fun isBypassEnabled_enabledInRepository_true() =          testScope.runTest {              utils.deviceEntryRepository.setBypassEnabled(true) -            assertThat(underTest.isBypassEnabled()).isTrue() +            assertThat(underTest.isBypassEnabled.value).isTrue()          }      @Test      fun isBypassEnabled_disabledInRepository_false() =          testScope.runTest {              utils.deviceEntryRepository.setBypassEnabled(false) -            assertThat(underTest.isBypassEnabled()).isFalse() +            assertThat(underTest.isBypassEnabled.value).isFalse()          }      private fun switchToScene(sceneKey: SceneKey) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt index 781ad6b10b70..8a35ef11a364 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt @@ -6,7 +6,6 @@ import android.animation.ValueAnimator  import android.view.View  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.complication.ComplicationHostViewController  import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel @@ -30,7 +29,6 @@ import org.mockito.Mockito.times  import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4::class)  class DreamOverlayAnimationsControllerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt index 21192fa11da3..2c6c793c97f5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt @@ -17,7 +17,6 @@ package com.android.systemui.dreams  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.google.common.truth.Truth.assertThat  import org.junit.Before @@ -30,7 +29,6 @@ import org.mockito.Mockito.times  import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4::class)  class DreamOverlayCallbackControllerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java index 7c36642f5417..2af6566e993a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java @@ -38,7 +38,6 @@ import androidx.test.filters.SmallTest;  import com.android.dream.lowlight.LowLightTransitionCoordinator;  import com.android.keyguard.BouncerPanelExpansionCalculator; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;  import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback; @@ -53,7 +52,6 @@ import org.mockito.ArgumentCaptor;  import org.mockito.Mock;  import org.mockito.MockitoAnnotations; -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4.class)  public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java index be7638ef31e6..d379dc6f3dc1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java @@ -26,7 +26,6 @@ import android.service.notification.StatusBarNotification;  import androidx.test.ext.junit.runners.AndroidJUnit4;  import androidx.test.filters.SmallTest; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.statusbar.NotificationListener;  import com.android.systemui.statusbar.NotificationListener.NotificationHandler; @@ -38,7 +37,6 @@ import org.mockito.ArgumentCaptor;  import org.mockito.Mock;  import org.mockito.MockitoAnnotations; -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4.class)  public class DreamOverlayNotificationCountProviderTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java index 8379f73402cf..e5f997257cfa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java @@ -49,7 +49,6 @@ import androidx.test.filters.SmallTest;  import com.android.internal.logging.UiEventLogger;  import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.complication.ComplicationLayoutEngine;  import com.android.systemui.dreams.complication.HideComplicationTouchHandler; @@ -72,7 +71,6 @@ import org.mockito.Mock;  import org.mockito.Mockito;  import org.mockito.MockitoAnnotations; -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4.class)  public class DreamOverlayServiceTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java index 2ef227c245c3..365f67b5e566 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java @@ -29,7 +29,6 @@ import static org.mockito.Mockito.when;  import androidx.test.ext.junit.runners.AndroidJUnit4;  import androidx.test.filters.SmallTest; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.complication.Complication;  import com.android.systemui.flags.FeatureFlags; @@ -48,7 +47,6 @@ import org.mockito.MockitoAnnotations;  import java.util.Collection; -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4.class)  public class DreamOverlayStateControllerTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java index 12cb332c7cc5..7ff345cdcf7e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java @@ -24,7 +24,6 @@ import static org.mockito.Mockito.verify;  import androidx.test.ext.junit.runners.AndroidJUnit4;  import androidx.test.filters.SmallTest; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import org.junit.Before; @@ -36,7 +35,6 @@ import org.mockito.MockitoAnnotations;  import java.util.List;  import java.util.concurrent.Executor; -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4.class)  public class DreamOverlayStatusBarItemsProviderTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java index 9566e81ed08d..39db2beb4c44 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java @@ -46,11 +46,10 @@ import android.view.View;  import androidx.test.ext.junit.runners.AndroidJUnit4;  import androidx.test.filters.SmallTest; -import com.android.systemui.res.R; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.log.LogBuffer;  import com.android.systemui.log.core.FakeLogBuffer; +import com.android.systemui.res.R;  import com.android.systemui.settings.UserTracker;  import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;  import com.android.systemui.statusbar.policy.NextAlarmController; @@ -72,7 +71,6 @@ import java.util.List;  import java.util.Optional;  import java.util.concurrent.Executor; -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4.class)  public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java index d32788df30be..315a24bfd945 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java @@ -30,7 +30,6 @@ import androidx.concurrent.futures.CallbackToFutureAdapter;  import androidx.test.ext.junit.runners.AndroidJUnit4;  import androidx.test.filters.SmallTest; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.complication.Complication;  import com.android.systemui.dreams.DreamOverlayStateController; @@ -49,7 +48,6 @@ import org.mockito.Mock;  import org.mockito.Mockito;  import org.mockito.MockitoAnnotations; -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4.class)  public class HideComplicationTouchHandlerTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java index 4a7700fe1ca2..e0c6ab20c6e1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java @@ -26,7 +26,6 @@ import static org.mockito.Mockito.verify;  import androidx.test.ext.junit.runners.AndroidJUnit4;  import androidx.test.filters.SmallTest; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.assist.AssistManager;  import com.android.systemui.assist.AssistManager.VisualQueryAttentionListener; @@ -41,7 +40,6 @@ import org.mockito.MockitoAnnotations;  import kotlinx.coroutines.CoroutineScope; -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4.class)  public class AssistantAttentionConditionTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java index cd2efded7e85..480754c17616 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java @@ -31,7 +31,6 @@ import androidx.test.filters.SmallTest;  import com.android.keyguard.KeyguardUpdateMonitor;  import com.android.keyguard.KeyguardUpdateMonitorCallback; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.shared.condition.Condition; @@ -44,7 +43,6 @@ import org.mockito.MockitoAnnotations;  import kotlinx.coroutines.CoroutineScope; -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4.class)  public class DreamConditionTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java index ffcaeee52596..3d1efa59a11b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java @@ -17,6 +17,7 @@  package com.android.systemui.dreams.touch;  import static com.google.common.truth.Truth.assertThat; +  import static org.mockito.ArgumentMatchers.any;  import static org.mockito.ArgumentMatchers.anyFloat;  import static org.mockito.ArgumentMatchers.eq; @@ -40,7 +41,6 @@ import androidx.test.filters.SmallTest;  import com.android.internal.logging.UiEventLogger;  import com.android.internal.widget.LockPatternUtils; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;  import com.android.systemui.dreams.touch.scrim.ScrimController; @@ -64,7 +64,6 @@ import org.mockito.MockitoAnnotations;  import java.util.Collections;  import java.util.Optional; -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4.class)  public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java index ff6d97d3b380..6aa821f15ab1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java @@ -27,7 +27,6 @@ import android.view.MotionEvent;  import androidx.test.ext.junit.runners.AndroidJUnit4;  import androidx.test.filters.SmallTest; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.shade.ShadeViewController;  import com.android.systemui.shared.system.InputChannelCompat; @@ -43,7 +42,6 @@ import org.mockito.MockitoAnnotations;  import java.util.Optional; -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4.class)  public class ShadeTouchHandlerTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java index da393818c6f7..017fdbe8ac01 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java @@ -26,7 +26,6 @@ import android.os.PowerManager;  import androidx.test.ext.junit.runners.AndroidJUnit4;  import androidx.test.filters.SmallTest; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.shade.ShadeExpansionChangeEvent;  import com.android.systemui.util.concurrency.FakeExecutor; @@ -38,7 +37,6 @@ import org.junit.runner.RunWith;  import org.mockito.Mock;  import org.mockito.MockitoAnnotations; -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4.class)  public class BouncerlessScrimControllerTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java index 81f6fe3e24d3..4ee4a60fbeaf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java @@ -25,7 +25,6 @@ import static org.mockito.Mockito.when;  import androidx.test.ext.junit.runners.AndroidJUnit4;  import androidx.test.filters.SmallTest; -import com.android.systemui.RoboPilotTest;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.statusbar.policy.KeyguardStateController;  import com.android.systemui.util.concurrency.FakeExecutor; @@ -38,7 +37,6 @@ import org.mockito.ArgumentCaptor;  import org.mockito.Mock;  import org.mockito.MockitoAnnotations; -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4.class)  public class ScrimManagerTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index 291dda20fdc3..a6468234b9b6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -16,7 +16,6 @@  package com.android.systemui.keyguard; -import static android.os.PowerManager.WAKE_REASON_WAKE_MOTION;  import static android.provider.Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT;  import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;  import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_TIMEOUT; @@ -635,29 +634,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {      }      @Test -    public void lockAfterSpecifiedAfterDreamStarted() { -        int currentUserId = 99; -        int userSpecificTimeout = 5999; -        KeyguardUpdateMonitor.setCurrentUser(currentUserId); - -        // set mDeviceInteractive to true -        mViewMediator.onStartedWakingUp(WAKE_REASON_WAKE_MOTION, false); -        mFeatureFlags.set(Flags.LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING, false); -        when(mLockPatternUtils.isSecure(currentUserId)).thenReturn(true); -        when(mDevicePolicyManager.getMaximumTimeToLock(null, currentUserId)).thenReturn(0L); -        when(mSecureSettings.getIntForUser(LOCK_SCREEN_LOCK_AFTER_TIMEOUT, -                KEYGUARD_LOCK_AFTER_DELAY_DEFAULT, currentUserId)).thenReturn(userSpecificTimeout); -        mSystemClock.setElapsedRealtime(0L); -        ArgumentCaptor<PendingIntent> pendingIntent = ArgumentCaptor.forClass(PendingIntent.class); - -        mViewMediator.onDreamingStarted(); - -        verify(mAlarmManager).setExactAndAllowWhileIdle(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), -                eq(Long.valueOf(userSpecificTimeout)), pendingIntent.capture()); -        assertEquals(DELAYED_KEYGUARD_ACTION, pendingIntent.getValue().getIntent().getAction()); -    } - -    @Test      public void testHideSurfaceBehindKeyguardMarksKeyguardNotGoingAway() {          mViewMediator.hideSurfaceBehindKeyguard(); @@ -1023,7 +999,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {          mViewMediator.setShowingLocked(false);          when(mKeyguardStateController.isShowing()).thenReturn(false); -        mFeatureFlags.set(Flags.LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING, false);          mViewMediator.onDreamingStarted();          assertFalse(mViewMediator.isShowingAndNotOccluded());      } @@ -1034,7 +1009,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {          mViewMediator.setShowingLocked(true);          when(mKeyguardStateController.isShowing()).thenReturn(true); -        mFeatureFlags.set(Flags.LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING, true);          mViewMediator.onDreamingStarted();          assertTrue(mViewMediator.isShowingAndNotOccluded());      } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt index cfee3b8f06ea..e20d3afaca53 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt @@ -23,7 +23,6 @@ import android.content.Context  import android.content.pm.PackageManager  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.camera.CameraGestureHelper  import com.android.systemui.settings.UserTracker @@ -43,7 +42,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class CameraQuickAffordanceConfigTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt index 49168d087958..faf97517ac59 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt @@ -26,7 +26,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.settingslib.notification.EnableZenModeDialog  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.animation.Expandable  import com.android.systemui.common.shared.model.ContentDescription @@ -61,7 +60,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class DoNotDisturbQuickAffordanceConfigTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt index c85c7f678536..548b5646f5d4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt @@ -17,7 +17,6 @@  package com.android.systemui.keyguard.data.quickaffordance -import com.android.systemui.RoboPilotTest  import com.android.systemui.animation.Expandable  import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult  import kotlinx.coroutines.flow.Flow @@ -25,7 +24,6 @@ import kotlinx.coroutines.flow.MutableStateFlow  import kotlinx.coroutines.yield  /** Fake implementation of a quick affordance data source. */ -@RoboPilotTest  class FakeKeyguardQuickAffordanceConfig(      override val key: String,      private val pickerName: String = key, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt index c3e28ae84805..4ae144c03314 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt @@ -21,7 +21,6 @@ import android.content.Context  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.common.shared.model.Icon  import com.android.systemui.keyguard.shared.quickaffordance.ActivationState  import com.android.systemui.statusbar.policy.FlashlightController @@ -42,7 +41,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class FlashlightQuickAffordanceConfigTest : LeakCheckedTest() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt index ef56a9892060..7d68cc0a3560 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt @@ -20,7 +20,6 @@ package com.android.systemui.keyguard.data.quickaffordance  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.animation.Expandable  import com.android.systemui.controls.controller.ControlsController @@ -41,7 +40,6 @@ import org.mockito.Mockito.`when` as whenever  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class HomeControlsKeyguardQuickAffordanceConfigTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt index 4f071bd9904f..1e80fb69c107 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt @@ -23,7 +23,6 @@ import android.provider.Settings  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.settings.FakeUserTracker  import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots @@ -49,7 +48,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class KeyguardQuickAffordanceLegacySettingSyncerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt index bd0b71df3e5c..99a01858471c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt @@ -23,7 +23,6 @@ import android.content.pm.UserInfo  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.backup.BackupHelper  import com.android.systemui.settings.FakeUserTracker @@ -53,7 +52,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class KeyguardQuickAffordanceLocalUserSelectionManagerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt index 0797d07807b4..a1c9f87ee7bc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt @@ -21,7 +21,6 @@ import android.content.pm.UserInfo  import android.os.UserHandle  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.settings.FakeUserTracker  import com.android.systemui.shared.customization.data.content.FakeCustomizationProviderClient @@ -44,7 +43,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class KeyguardQuickAffordanceRemoteUserSelectionManagerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt index d8c0341e1979..b15352bfe6ab 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt @@ -21,7 +21,6 @@ import android.content.Context  import android.media.AudioManager  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.settings.UserFileManager  import com.android.systemui.settings.UserTracker @@ -46,7 +45,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class MuteQuickAffordanceConfigTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt index 9d983b8c8943..521dea34513e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt @@ -20,7 +20,6 @@ package com.android.systemui.keyguard.data.quickaffordance  import android.content.Intent  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult  import com.android.systemui.qrcodescanner.controller.QRCodeScannerController @@ -40,7 +39,6 @@ import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt index 613c4ce4ccef..02db0d7a9a50 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt @@ -24,7 +24,6 @@ import android.service.quickaccesswallet.WalletCard  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.animation.ActivityLaunchAnimator  import com.android.systemui.animation.Expandable @@ -51,7 +50,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt index 1414bace3090..a9b9c9011636 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt @@ -21,7 +21,6 @@ import android.app.admin.DevicePolicyManager  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.ActivityIntentHelper -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.camera.CameraIntentsWrapper  import com.android.systemui.coroutines.collectLastValue @@ -45,7 +44,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class VideoCameraQuickAffordanceConfigTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt index 944b059450c9..d8cdf29284ed 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt @@ -32,7 +32,6 @@ import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUT  import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT  import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT  import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.biometrics.AuthController  import com.android.systemui.biometrics.data.repository.FaceSensorInfo @@ -79,7 +78,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @TestableLooper.RunWithLooper(setAsMainLooper = true)  @RunWith(AndroidJUnit4::class)  class BiometricSettingsRepositoryTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt index 307204da1761..819d08a2086e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt @@ -44,7 +44,6 @@ import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_NOTIFICATION_PAN  import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER  import com.android.keyguard.KeyguardUpdateMonitor  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository  import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository @@ -122,7 +121,6 @@ import java.io.StringWriter  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {      private lateinit var underTest: DeviceEntryFaceAuthRepositoryImpl diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt index def016ad8381..a58bc52bf8e5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt @@ -22,7 +22,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.keyguard.KeyguardUpdateMonitor  import com.android.keyguard.KeyguardUpdateMonitorCallback -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.biometrics.AuthController  import com.android.systemui.coroutines.collectLastValue @@ -49,7 +48,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() {      @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt index 7eb8a26d9ab6..9be5558f5cc2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.data.repository  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.keyguard.shared.model.DevicePosture @@ -39,7 +38,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class DevicePostureRepositoryTest : SysuiTestCase() {      private lateinit var underTest: DevicePostureRepository diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt index 126b841610b4..567e0a9717fc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt @@ -22,7 +22,6 @@ import android.os.UserHandle  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig @@ -56,7 +55,6 @@ import org.mockito.ArgumentMatchers.anyString  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt index 7983e30c66fb..b9119e10b720 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt @@ -22,7 +22,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.keyguard.KeyguardUpdateMonitor  import com.android.keyguard.KeyguardUpdateMonitorCallback -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.biometrics.AuthController  import com.android.systemui.common.shared.model.Position @@ -64,7 +63,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class KeyguardRepositoryImplTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt index 4942cf84a6fc..799bd5ac5739 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt @@ -20,7 +20,6 @@ import android.graphics.Point  import android.testing.TestableLooper  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.animation.AnimatorTestRule  import com.android.systemui.coroutines.collectLastValue @@ -46,7 +45,6 @@ import org.junit.runner.RunWith  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @OptIn(ExperimentalCoroutinesApi::class)  @RunWith(AndroidJUnit4::class)  class LightRevealScrimRepositoryTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt index 7f784d88da6d..ee47c58f4002 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt @@ -21,7 +21,6 @@ import android.content.pm.UserInfo  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.keyguard.logging.TrustRepositoryLogger -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.FlowValue  import com.android.systemui.coroutines.collectLastValue @@ -46,7 +45,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class TrustRepositoryTest : SysuiTestCase() {      @Mock private lateinit var trustManager: TrustManager diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt index 181cc884c9f5..d6e19cbcb826 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.domain.interactor  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository @@ -43,7 +42,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class KeyguardDismissActionInteractorTest : SysuiTestCase() {      private lateinit var keyguardRepository: FakeKeyguardRepository diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt index c407b14dcf65..a5cfbbfda196 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt @@ -22,7 +22,6 @@ import android.service.trust.TrustAgentService  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.keyguard.TrustGrantFlags -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.keyguard.shared.model.DismissAction @@ -40,7 +39,6 @@ import org.junit.runner.RunWith  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class KeyguardDismissInteractorTest : SysuiTestCase() {      private lateinit var dispatcher: TestDispatcher diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt index b527510fc56f..06eb0dd364b5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt @@ -28,8 +28,10 @@ import com.android.keyguard.FaceWakeUpTriggersConfig  import com.android.keyguard.KeyguardSecurityModel  import com.android.keyguard.KeyguardUpdateMonitor  import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.data.repository.FaceSensorInfo  import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository  import com.android.systemui.biometrics.shared.model.LockoutMode +import com.android.systemui.biometrics.shared.model.SensorStrength  import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository  import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor  import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor @@ -156,7 +158,6 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {                  fakeDeviceEntryFingerprintAuthRepository,                  fakeUserRepository,                  facePropertyRepository, -                fakeKeyguardRepository,                  faceWakeUpTriggersConfig,                  powerInteractor,              ) @@ -440,6 +441,43 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {          }      @Test +    fun faceAuthIsRequestedWhenWalletIsLaunchedAndIfFaceAuthIsStrong() = +        testScope.runTest { +            underTest.start() +            facePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.STRONG)) + +            underTest.onWalletLaunched() + +            runCurrent() +            assertThat(faceAuthRepository.runningAuthRequest.value) +                .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_OCCLUDING_APP_REQUESTED, true)) +        } + +    @Test +    fun faceAuthIsNotTriggeredIfFaceAuthIsWeak() = +        testScope.runTest { +            underTest.start() +            facePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.WEAK)) + +            underTest.onWalletLaunched() + +            runCurrent() +            assertThat(faceAuthRepository.runningAuthRequest.value).isNull() +        } + +    @Test +    fun faceAuthIsNotTriggeredIfFaceAuthIsConvenience() = +        testScope.runTest { +            underTest.start() +            facePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.CONVENIENCE)) + +            underTest.onWalletLaunched() + +            runCurrent() +            assertThat(faceAuthRepository.runningAuthRequest.value).isNull() +        } + +    @Test      fun faceUnlockIsDisabledWhenFpIsLockedOut() =          testScope.runTest {              underTest.start() diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt index ca52cdb227e5..9ee22c89405d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt @@ -20,7 +20,6 @@ package com.android.systemui.keyguard.domain.interactor  import android.app.StatusBarManager  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository  import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository @@ -47,7 +46,6 @@ import org.junit.runner.RunWith  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class KeyguardInteractorTest : SysuiTestCase() { @@ -206,7 +204,8 @@ class KeyguardInteractorTest : SysuiTestCase() {                      fromScene = SceneKey.Gone,                      toScene = SceneKey.Lockscreen,                      progress = flowOf(0f), -                    isUserInputDriven = false, +                    isInitiatedByUserInput = false, +                    isUserInputOngoing = flowOf(false),                  )              runCurrent()              assertThat(isAnimate).isFalse() diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt index bbe68234f055..900413c14475 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt @@ -35,6 +35,7 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager  import com.android.systemui.util.mockito.any  import com.android.systemui.util.mockito.whenever  import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi  import org.junit.Before  import org.junit.Rule  import org.junit.Test @@ -46,6 +47,7 @@ import org.mockito.Mockito.never  import org.mockito.Mockito.verify  import org.mockito.junit.MockitoJUnit +@ExperimentalCoroutinesApi  @SmallTest  @RunWith(AndroidJUnit4::class)  class KeyguardKeyEventInteractorTest : SysuiTestCase() { @@ -132,58 +134,73 @@ class KeyguardKeyEventInteractorTest : SysuiTestCase() {      }      @Test -    fun dispatchKeyEvent_menuActionUp_interactiveKeyguard_collapsesShade() { +    fun dispatchKeyEvent_menuActionUp_awakeKeyguard_showsPrimaryBouncer() {          powerInteractor.setAwakeForTest()          whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)          whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true) -        val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU) -        assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue() -        verify(shadeController).animateCollapseShadeForced() +        verifyActionUpShowsPrimaryBouncer(KeyEvent.KEYCODE_MENU)      }      @Test -    fun dispatchKeyEvent_menuActionUp_interactiveShadeLocked_collapsesShade() { +    fun dispatchKeyEvent_menuActionUp_awakeShadeLocked_collapsesShade() {          powerInteractor.setAwakeForTest()          whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)          whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true) -        // action down: does NOT collapse the shade -        val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU) -        assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse() -        verify(shadeController, never()).animateCollapseShadeForced() - -        // action up: collapses the shade -        val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU) -        assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue() -        verify(shadeController).animateCollapseShadeForced() +        verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_MENU)      }      @Test -    fun dispatchKeyEvent_menuActionUp_nonInteractiveKeyguard_neverCollapsesShade() { +    fun dispatchKeyEvent_menuActionUp_asleepKeyguard_neverCollapsesShade() {          powerInteractor.setAsleepForTest()          whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)          whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true) -        val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU) -        assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isFalse() -        verify(shadeController, never()).animateCollapseShadeForced() +        verifyActionsDoNothing(KeyEvent.KEYCODE_MENU)      }      @Test -    fun dispatchKeyEvent_spaceActionUp_interactiveKeyguard_collapsesShade() { +    fun dispatchKeyEvent_spaceActionUp_awakeKeyguard_collapsesShade() {          powerInteractor.setAwakeForTest()          whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) +        whenever(statusBarKeyguardViewManager.primaryBouncerIsShowing()).thenReturn(false) -        // action down: does NOT collapse the shade -        val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE) -        assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse() -        verify(shadeController, never()).animateCollapseShadeForced() +        verifyActionUpShowsPrimaryBouncer(KeyEvent.KEYCODE_SPACE) +    } -        // action up: collapses the shade -        val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SPACE) -        assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue() -        verify(shadeController).animateCollapseShadeForced() +    @Test +    fun dispatchKeyEvent_spaceActionUp_shadeLocked_collapsesShade() { +        powerInteractor.setAwakeForTest() +        whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED) + +        verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_SPACE) +    } + +    @Test +    fun dispatchKeyEvent_enterActionUp_awakeKeyguard_showsPrimaryBouncer() { +        powerInteractor.setAwakeForTest() +        whenever(statusBarKeyguardViewManager.primaryBouncerIsShowing()).thenReturn(false) +        whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + +        verifyActionUpShowsPrimaryBouncer(KeyEvent.KEYCODE_ENTER) +    } + +    @Test +    fun dispatchKeyEvent_enterActionUp_awakeKeyguard_primaryBouncerAlreadyShowing() { +        powerInteractor.setAwakeForTest() +        whenever(statusBarKeyguardViewManager.primaryBouncerIsShowing()).thenReturn(true) +        whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + +        verifyActionsDoNothing(KeyEvent.KEYCODE_ENTER) +    } + +    @Test +    fun dispatchKeyEvent_enterActionUp_shadeLocked_collapsesShade() { +        powerInteractor.setAwakeForTest() +        whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED) + +        verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_ENTER)      }      @Test @@ -253,4 +270,42 @@ class KeyguardKeyEventInteractorTest : SysuiTestCase() {              .isFalse()          verify(statusBarKeyguardViewManager, never()).interceptMediaKey(any())      } + +    private fun verifyActionUpCollapsesTheShade(keycode: Int) { +        // action down: does NOT collapse the shade +        val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, keycode) +        assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse() +        verify(shadeController, never()).animateCollapseShadeForced() + +        // action up: collapses the shade +        val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, keycode) +        assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue() +        verify(shadeController).animateCollapseShadeForced() +    } + +    private fun verifyActionUpShowsPrimaryBouncer(keycode: Int) { +        // action down: does NOT collapse the shade +        val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, keycode) +        assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse() +        verify(statusBarKeyguardViewManager, never()).showPrimaryBouncer(any()) + +        // action up: collapses the shade +        val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, keycode) +        assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue() +        verify(statusBarKeyguardViewManager).showPrimaryBouncer(eq(true)) +    } + +    private fun verifyActionsDoNothing(keycode: Int) { +        // action down: does nothing +        val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, keycode) +        assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse() +        verify(shadeController, never()).animateCollapseShadeForced() +        verify(statusBarKeyguardViewManager, never()).showPrimaryBouncer(any()) + +        // action up: doesNothing +        val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, keycode) +        assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isFalse() +        verify(shadeController, never()).animateCollapseShadeForced() +        verify(statusBarKeyguardViewManager, never()).showPrimaryBouncer(any()) +    }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt index 13025a016eff..0c74a38fea04 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt @@ -22,7 +22,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.internal.logging.UiEventLogger  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.flags.FakeFeatureFlags @@ -51,7 +50,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class KeyguardLongPressInteractorTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt index 8c13bb465103..347d580abf5b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt @@ -23,7 +23,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.internal.widget.LockPatternUtils  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.animation.DialogLaunchAnimator  import com.android.systemui.common.shared.model.ContentDescription @@ -73,7 +72,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt index fdcc66b6c974..71fcf6f9955c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.domain.interactor  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectValues  import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepository @@ -41,7 +40,6 @@ import org.mockito.Mock  import org.mockito.MockitoAnnotations.initMocks  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @kotlinx.coroutines.ExperimentalCoroutinesApi  class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt index fa93253642e3..29b546bd49ad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.domain.interactor  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectValues  import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository @@ -42,7 +41,6 @@ import org.junit.Test  import org.junit.runner.RunWith  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @kotlinx.coroutines.ExperimentalCoroutinesApi  class KeyguardTransitionInteractorTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt index 906d94859140..c02add1d0ecb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.domain.interactor  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository  import com.android.systemui.keyguard.data.repository.FakeLightRevealScrimRepository @@ -45,7 +44,6 @@ import org.mockito.MockitoAnnotations  import org.mockito.Spy  @SmallTest -@RoboPilotTest  @OptIn(ExperimentalCoroutinesApi::class)  @RunWith(AndroidJUnit4::class)  class LightRevealScrimInteractorTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt index 73ecae5af9b3..16f2fa22d5fb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.domain.interactor  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectValues  import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository @@ -38,7 +37,6 @@ import org.mockito.Mock  import org.mockito.MockitoAnnotations.initMocks  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @kotlinx.coroutines.ExperimentalCoroutinesApi  class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt index a22f603ae92a..5b29a867ceaf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt @@ -20,7 +20,6 @@ import android.testing.TestableLooper.RunWithLooper  import android.view.RemoteAnimationTarget  import androidx.test.filters.SmallTest  import com.android.keyguard.KeyguardViewController -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.animation.AnimatorTestRule  import com.android.systemui.keyguard.domain.interactor.KeyguardSurfaceBehindInteractor @@ -41,7 +40,6 @@ import org.mockito.Mockito.doAnswer  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWithLooper(setAsMainLooper = true)  @kotlinx.coroutines.ExperimentalCoroutinesApi  class KeyguardSurfaceBehindParamsApplierTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt index 7a17435b9165..9b2db3e5316c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.binder  import android.app.IActivityTaskManager  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.keyguard.WindowManagerLockscreenVisibilityManager  import com.android.systemui.statusbar.policy.KeyguardStateController @@ -35,7 +34,6 @@ import org.mockito.Mockito.verifyNoMoreInteractions  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @kotlinx.coroutines.ExperimentalCoroutinesApi  class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt new file mode 100644 index 000000000000..1768f8c4385b --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.keyguard.ui.viewmodel + +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.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory +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.plugins.FalsingManager +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager +import com.google.common.collect.Range +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@ExperimentalCoroutinesApi +@RunWith(JUnit4::class) +@SmallTest +class AlternateBouncerViewModelTest : SysuiTestCase() { + +    private lateinit var testScope: TestScope + +    @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager +    @Mock private lateinit var falsingManager: FalsingManager + +    private lateinit var transitionRepository: FakeKeyguardTransitionRepository +    private lateinit var transitionInteractor: KeyguardTransitionInteractor +    private lateinit var underTest: AlternateBouncerViewModel + +    @Before +    fun setup() { +        MockitoAnnotations.initMocks(this) +        testScope = TestScope() + +        val transitionInteractorWithDependencies = +            KeyguardTransitionInteractorFactory.create(testScope.backgroundScope) +        transitionInteractor = transitionInteractorWithDependencies.keyguardTransitionInteractor +        transitionRepository = transitionInteractorWithDependencies.repository +        underTest = +            AlternateBouncerViewModel( +                statusBarKeyguardViewManager, +                transitionInteractor, +                falsingManager, +            ) +    } + +    @Test +    fun transitionToAlternateBouncer_scrimAlphaUpdate() = +        runTest(UnconfinedTestDispatcher()) { +            val scrimAlphas by collectValues(underTest.scrimAlpha) + +            transitionRepository.sendTransitionStep( +                stepToAlternateBouncer(0f, TransitionState.STARTED) +            ) +            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.4f)) +            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.6f)) +            transitionRepository.sendTransitionStep(stepToAlternateBouncer(1f)) + +            assertThat(scrimAlphas.size).isEqualTo(4) +            scrimAlphas.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } +        } + +    @Test +    fun transitionFromAlternateBouncer_scrimAlphaUpdate() = +        runTest(UnconfinedTestDispatcher()) { +            val scrimAlphas by collectValues(underTest.scrimAlpha) + +            transitionRepository.sendTransitionStep( +                stepFromAlternateBouncer(0f, TransitionState.STARTED) +            ) +            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.4f)) +            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.6f)) +            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(1f)) + +            assertThat(scrimAlphas.size).isEqualTo(4) +            scrimAlphas.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } +        } + +    @Test +    fun clickListenerUpdate() = +        runTest(UnconfinedTestDispatcher()) { +            val clickListener by collectLastValue(underTest.onClickListener) + +            // keyguard state => ALTERNATE_BOUNCER +            transitionRepository.sendTransitionStep( +                stepToAlternateBouncer(0f, TransitionState.STARTED) +            ) +            assertThat(clickListener).isNull() +            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.3f)) +            assertThat(clickListener).isNull() +            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.6f)) +            assertThat(clickListener).isNull() +            transitionRepository.sendTransitionStep(stepToAlternateBouncer(1f)) +            assertThat(clickListener).isNotNull() + +            // ALTERNATE_BOUNCER -> keyguard state +            transitionRepository.sendTransitionStep( +                stepFromAlternateBouncer(0f, TransitionState.STARTED) +            ) +            assertThat(clickListener).isNotNull() +            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.3f)) +            assertThat(clickListener).isNull() +            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.6f)) +            assertThat(clickListener).isNull() +            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(1f)) +            assertThat(clickListener).isNull() +        } + +    @Test +    fun forcePluginOpen() = +        runTest(UnconfinedTestDispatcher()) { +            val forcePluginOpen by collectLastValue(underTest.forcePluginOpen) +            transitionRepository.sendTransitionStep( +                stepToAlternateBouncer(0f, TransitionState.STARTED) +            ) +            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.3f)) +            transitionRepository.sendTransitionStep(stepToAlternateBouncer(.6f)) +            transitionRepository.sendTransitionStep(stepToAlternateBouncer(1f)) +            assertThat(forcePluginOpen).isTrue() + +            transitionRepository.sendTransitionStep( +                stepFromAlternateBouncer(0f, TransitionState.STARTED) +            ) +            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.3f)) +            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.6f)) +            transitionRepository.sendTransitionStep(stepFromAlternateBouncer(1f)) +            assertThat(forcePluginOpen).isFalse() +        } + +    private fun stepToAlternateBouncer( +        value: Float, +        state: TransitionState = TransitionState.RUNNING +    ): TransitionStep { +        return step( +            from = KeyguardState.LOCKSCREEN, +            to = KeyguardState.ALTERNATE_BOUNCER, +            value = value, +            transitionState = state, +        ) +    } + +    private fun stepFromAlternateBouncer( +        value: Float, +        state: TransitionState = TransitionState.RUNNING +    ): TransitionStep { +        return step( +            from = KeyguardState.ALTERNATE_BOUNCER, +            to = KeyguardState.LOCKSCREEN, +            value = value, +            transitionState = state, +        ) +    } + +    private fun step( +        from: KeyguardState, +        to: KeyguardState, +        value: Float, +        transitionState: TransitionState +    ): TransitionStep { +        return TransitionStep( +            from = from, +            to = to, +            value = value, +            transitionState = transitionState, +            ownerName = "AlternateBouncerViewModelTest" +        ) +    } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt index bfc6f31c57db..6d47aed58dac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory @@ -46,7 +45,6 @@ import org.junit.Test  import org.junit.runner.RunWith  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {      private lateinit var underTest: DreamingToLockscreenTransitionViewModel diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt index 75c8bff326b0..cf2012989624 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory @@ -37,7 +36,6 @@ import org.junit.Test  import org.junit.runner.RunWith  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class GoneToDreamingTransitionViewModelTest : SysuiTestCase() {      private lateinit var underTest: GoneToDreamingTransitionViewModel diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt index 6e94691d42a9..7de28de4d436 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt @@ -16,6 +16,7 @@  package com.android.systemui.keyguard.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.authentication.data.model.AuthenticationMethodModel @@ -28,10 +29,9 @@ import com.google.common.truth.Truth.assertThat  import kotlinx.coroutines.test.runTest  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class LockscreenSceneViewModelTest : SysuiTestCase() {      private val utils = SceneTestUtils(this) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt index 12fe07f0827e..89a1d2b3011d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory @@ -37,7 +36,6 @@ import org.junit.Test  import org.junit.runner.RunWith  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() {      private lateinit var underTest: LockscreenToDreamingTransitionViewModel diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt index 83ae631ed164..41f8856d5ca2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory @@ -37,7 +36,6 @@ import org.junit.Test  import org.junit.runner.RunWith  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() {      private lateinit var underTest: LockscreenToOccludedTransitionViewModel diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt index 88603999cdd7..ec95cb8c43f1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory @@ -37,7 +36,6 @@ import org.junit.Test  import org.junit.runner.RunWith  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() {      private lateinit var underTest: OccludedToLockscreenTransitionViewModel diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt index da372eaf158c..93640975901b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor  import com.android.systemui.coroutines.collectValues @@ -46,7 +45,6 @@ import org.mockito.Mock  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() {      private lateinit var underTest: PrimaryBouncerToGoneTransitionViewModel diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt index 9ab9b3d160d1..32acefebfa68 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository  import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository @@ -46,7 +45,6 @@ import org.mockito.MockitoAnnotations  @ExperimentalCoroutinesApi  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class UdfpsAodViewModelTest : SysuiTestCase() {      private val defaultPadding = 12 diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java index d57765c3ecf2..c8c134a9474a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java @@ -16,6 +16,8 @@  package com.android.systemui.qs; +import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS; +  import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;  import static com.android.systemui.statusbar.StatusBarState.SHADE; @@ -41,6 +43,7 @@ import android.graphics.Rect;  import android.os.Bundle;  import android.testing.AndroidTestingRunner;  import android.testing.TestableLooper.RunWithLooper; +import android.view.Display;  import android.view.LayoutInflater;  import android.view.View;  import android.view.ViewGroup; @@ -49,7 +52,6 @@ import androidx.lifecycle.Lifecycle;  import androidx.test.filters.SmallTest;  import com.android.keyguard.BouncerPanelExpansionCalculator; -import com.android.systemui.res.R;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.dump.DumpManager;  import com.android.systemui.flags.FeatureFlagsClassic; @@ -60,6 +62,7 @@ import com.android.systemui.qs.external.TileServiceRequestController;  import com.android.systemui.qs.footer.ui.binder.FooterActionsViewBinder;  import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel;  import com.android.systemui.qs.logging.QSLogger; +import com.android.systemui.res.R;  import com.android.systemui.settings.FakeDisplayTracker;  import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;  import com.android.systemui.statusbar.CommandQueue; @@ -110,6 +113,9 @@ public class QSImplTest extends SysuiTestCase {      @Mock private FeatureFlagsClassic mFeatureFlags;      private View mQsView; +    private final CommandQueue mCommandQueue = +            new CommandQueue(mContext, new FakeDisplayTracker(mContext)); +      private QSImpl mUnderTest; @@ -120,6 +126,16 @@ public class QSImplTest extends SysuiTestCase {          mUnderTest.onComponentCreated(mQsComponent, null);      } +    /* +     * Regression test for b/303180152. +     */ +    @Test +    public void testDisableCallbackOnDisabledQuickSettingsUponCreationDoesntCrash() { +        QSImpl other = instantiate(); +        mCommandQueue.disable(Display.DEFAULT_DISPLAY, 0, DISABLE2_QUICK_SETTINGS); + +        other.onComponentCreated(mQsComponent, null); +    }      @Test      public void testSaveState() { @@ -473,7 +489,6 @@ public class QSImplTest extends SysuiTestCase {      private QSImpl instantiate() {          MockitoAnnotations.initMocks(this); -        CommandQueue commandQueue = new CommandQueue(mContext, new FakeDisplayTracker(mContext));          setupQsComponent();          setUpViews(); @@ -484,11 +499,11 @@ public class QSImplTest extends SysuiTestCase {          return new QSImpl(                  new RemoteInputQuickSettingsDisabler(                          mContext, -                        commandQueue, +                        mCommandQueue,                          new ResourcesSplitShadeStateController(),                          mock(ConfigurationController.class)),                  mStatusBarStateController, -                commandQueue, +                mCommandQueue,                  mQSMediaHost,                  mQQSMediaHost,                  mBypassController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java index e2ac7bc4fc6e..b825c0840e01 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java @@ -23,6 +23,7 @@ import static org.mockito.ArgumentMatchers.any;  import static org.mockito.ArgumentMatchers.anyBoolean;  import static org.mockito.ArgumentMatchers.anyFloat;  import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations;  import static org.mockito.Mockito.doAnswer;  import static org.mockito.Mockito.never;  import static org.mockito.Mockito.reset; @@ -42,7 +43,6 @@ import com.android.internal.logging.MetricsLogger;  import com.android.internal.logging.UiEventLogger;  import com.android.internal.logging.nano.MetricsProto.MetricsEvent;  import com.android.internal.logging.testing.UiEventLoggerFake; -import com.android.systemui.res.R;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.dump.DumpManager;  import com.android.systemui.media.controls.ui.MediaHost; @@ -50,6 +50,7 @@ import com.android.systemui.plugins.qs.QSTile;  import com.android.systemui.qs.customize.QSCustomizerController;  import com.android.systemui.qs.logging.QSLogger;  import com.android.systemui.qs.tileimpl.QSTileImpl; +import com.android.systemui.res.R;  import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;  import com.android.systemui.util.animation.DisappearParameters; @@ -341,11 +342,92 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {      }      @Test -    public void onViewDetached_removesJustTheAssociatedCallback() { +    public void onDestroy_removesJustTheAssociatedCallback() {          QSPanelControllerBase.TileRecord record = mController.mRecords.get(0); -        mController.onViewDetached(); +        mController.destroy();          verify(mQSTile).removeCallback(record.callback);          verify(mQSTile, never()).removeCallbacks(); + +        assertThat(mController.mRecords).isEmpty(); +    } + +    @Test +    public void onViewDettached_callbackNotRemoved() { +        QSPanelControllerBase.TileRecord record = mController.mRecords.get(0); + +        mController.onViewDetached(); +        verify(mQSTile, never()).removeCallback(record.callback); +        verify(mQSTile, never()).removeCallbacks(); +    } + +    @Test +    public void onInit_qsHostCallbackAdded() { +        verify(mQSHost).addCallback(any()); +    } + +    @Test +    public void onViewDettached_qsHostCallbackNotRemoved() { +        mController.onViewDetached(); +        verify(mQSHost, never()).removeCallback(any()); +    } + +    @Test +    public void onDestroy_qsHostCallbackRemoved() { +        mController.destroy(); +        verify(mQSHost).removeCallback(any()); +    } + +    @Test +    public void setTiles_sameTiles_doesntRemoveAndReaddViews() { +        when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile)); +        mController.setTiles(); + +        clearInvocations(mQSPanel); + +        mController.setTiles(); +        verify(mQSPanel, never()).removeTile(any()); +        verify(mQSPanel, never()).addTile(any()); +    } + +    @Test +    public void setTiles_differentTiles_allTilesRemovedAndNewTilesAdded() { +        when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile)); +        mController.setTiles(); + +        clearInvocations(mQSPanel); + +        when(mQSHost.getTiles()).thenReturn(List.of(mQSTile)); +        mController.setTiles(); + +        verify(mQSPanel, times(2)).removeTile(any()); +        verify(mQSPanel).addTile(any()); +    } + +    @Test +    public void detachAndReattach_sameTiles_doesntRemoveAndReAddViews() { +        when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile)); +        mController.setTiles(); + +        clearInvocations(mQSPanel); + +        mController.onViewDetached(); +        mController.onViewAttached(); +        verify(mQSPanel, never()).removeTile(any()); +        verify(mQSPanel, never()).addTile(any()); +    } + +    @Test +    public void setTiles_sameTilesDifferentOrder_removesAndReadds() { +        when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile)); +        mController.setTiles(); + +        clearInvocations(mQSPanel); + +        when(mQSHost.getTiles()).thenReturn(List.of(mOtherTile, mQSTile)); +        mController.setTiles(); + +        verify(mQSPanel, times(2)).removeTile(any()); +        verify(mQSPanel, times(2)).addTile(any());      }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt index 9a55f722c13c..d277fcab3690 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.qs.pipeline.data.repository  import android.provider.Settings  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.qs.pipeline.shared.TileSpec @@ -39,7 +38,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class AutoAddSettingsRepositoryTest : SysuiTestCase() {      private val secureSettings = FakeSettings() diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt index 30f5811c3731..3db676d68f42 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt @@ -20,7 +20,6 @@ import android.content.ComponentName  import android.content.SharedPreferences  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.settings.UserFileManager  import com.android.systemui.util.FakeSharedPreferences @@ -30,7 +29,6 @@ import org.junit.Test  import org.junit.runner.RunWith  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class CustomTileAddedSharedPreferencesRepositoryTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt index 995de662aaf0..070e07a75d23 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt @@ -32,7 +32,6 @@ import android.service.quicksettings.TileService  import android.testing.TestableLooper  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.util.mockito.any @@ -62,7 +61,6 @@ import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @TestableLooper.RunWithLooper  @OptIn(ExperimentalCoroutinesApi::class) diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredBroadcastRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredBroadcastRepositoryTest.kt index dc09a33adc1c..ff8a9bd019fb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredBroadcastRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredBroadcastRepositoryTest.kt @@ -4,7 +4,6 @@ import android.content.Intent  import android.provider.Settings  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.broadcast.FakeBroadcastDispatcher  import com.android.systemui.coroutines.collectLastValue @@ -24,7 +23,6 @@ import org.mockito.MockitoAnnotations  @SmallTest  @OptIn(ExperimentalCoroutinesApi::class)  @RunWith(AndroidJUnit4::class) -@RoboPilotTest  class QSSettingsRestoredBroadcastRepositoryTest : SysuiTestCase() {      private val dispatcher = StandardTestDispatcher()      private val testScope = TestScope(dispatcher) diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt index 08adebb87b1b..f7c3b213730c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt @@ -20,7 +20,6 @@ import android.provider.Settings  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.qs.pipeline.shared.TileSpec @@ -40,7 +39,6 @@ import org.mockito.Mock  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @OptIn(ExperimentalCoroutinesApi::class)  class TileSpecSettingsRepositoryTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt index 20876237b476..9516c2181ac0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt @@ -2,14 +2,12 @@ package com.android.systemui.qs.pipeline.data.repository  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.qs.pipeline.shared.TileSpec  import com.google.common.truth.Truth.assertThat  import org.junit.Test  import org.junit.runner.RunWith -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4::class)  class TilesSettingConverterTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt index 81fd72b11227..36e860e37ffa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt @@ -3,7 +3,6 @@ package com.android.systemui.qs.pipeline.data.repository  import android.provider.Settings  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.qs.pipeline.data.model.RestoreData @@ -24,7 +23,6 @@ import org.mockito.Mock  import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class) -@RoboPilotTest  @SmallTest  @RunWith(AndroidJUnit4::class)  class UserAutoAddRepositoryTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt index 389580c1326b..d4a9fabd6806 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt @@ -3,7 +3,6 @@ package com.android.systemui.qs.pipeline.data.repository  import android.provider.Settings  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.qs.pipeline.data.model.RestoreData @@ -23,7 +22,6 @@ import org.junit.runner.RunWith  import org.mockito.Mock  import org.mockito.MockitoAnnotations -@RoboPilotTest  @SmallTest  @OptIn(ExperimentalCoroutinesApi::class)  @RunWith(AndroidJUnit4::class) diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt index 15e401d24b02..4454a3cb15fc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt @@ -20,7 +20,6 @@ import android.content.ComponentName  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.qs.pipeline.shared.TileSpec  import com.android.systemui.util.mockito.mock @@ -29,7 +28,6 @@ import org.junit.Test  import org.junit.runner.RunWith  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class AutoAddableSettingListTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt index 7c6dd242a569..d153e9d1d361 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.coroutines.collectValues @@ -36,7 +35,6 @@ import org.junit.runner.RunWith  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class AutoAddableSettingTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt index 469eee363889..ec139e4c515e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal @@ -36,7 +35,6 @@ import org.junit.runner.RunWith  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class CallbackControllerAutoAddableTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt index b6eaa3922278..4fae532d4174 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal @@ -42,7 +41,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class CastAutoAddableTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt index a755fbbdfd7f..9e2d1f885e2d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal @@ -41,7 +40,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class DataSaverAutoAddableTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt index daacca51a915..0116bd9575d8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal @@ -44,7 +43,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class DeviceControlsAutoAddableTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt index 4b5f7f6d07ef..e7ea9a66450c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal @@ -41,7 +40,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class HotspotAutoAddableTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddableTest.kt index 32d9db24a3b2..20fd3601f9ef 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddableTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable  import android.hardware.display.NightDisplayListener  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.dagger.NightDisplayListenerModule @@ -50,7 +49,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class NightDisplayAutoAddableTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt index fb513a6bd197..19ac63c36cab 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.qs.ReduceBrightColorsController @@ -44,7 +43,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class ReduceBrightColorsAutoAddableTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt index 5ce15fa57b1f..d645ee34619b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt @@ -21,7 +21,6 @@ import android.content.pm.PackageManager  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.res.R -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.coroutines.collectValues @@ -52,7 +51,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class SafetyCenterAutoAddableTest : SysuiTestCase() {      private val testDispatcher = StandardTestDispatcher() diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt index 1c8cb541e613..83ff35d8022d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.autoaddable  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal @@ -38,7 +37,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class WalletAutoAddableTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt index de1d29fdcbe5..adccc84e494b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt @@ -23,7 +23,6 @@ import android.content.pm.UserInfo.FLAG_PRIMARY  import android.content.pm.UserInfo.FLAG_PROFILE  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal @@ -41,7 +40,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class WorkTileAutoAddableTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt index bb18115c960c..41a7ec03408d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.qs.pipeline.domain.interactor  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.dump.DumpManager @@ -47,7 +46,6 @@ import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @OptIn(ExperimentalCoroutinesApi::class)  class AutoAddInteractorTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt index a7505240caeb..a89338a38e89 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt @@ -24,7 +24,6 @@ import android.os.UserHandle  import android.service.quicksettings.Tile  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.dump.nano.SystemUIProtoDump @@ -71,7 +70,6 @@ import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @OptIn(ExperimentalCoroutinesApi::class)  class CurrentTilesInteractorImplTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt index 151b256c4f5c..0d9711588a1f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt @@ -17,7 +17,6 @@ package com.android.systemui.qs.pipeline.domain.interactor  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.shade.ShadeController  import org.junit.Before @@ -27,7 +26,6 @@ import org.mockito.Mock  import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @SmallTest  class PanelInteractorImplTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt index 2e6b50b637dd..f73cab8a10a3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt @@ -2,7 +2,6 @@ package com.android.systemui.qs.pipeline.domain.interactor  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.qs.pipeline.data.model.RestoreData @@ -20,7 +19,6 @@ import org.junit.Test  import org.junit.runner.RunWith  import org.mockito.MockitoAnnotations -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @SmallTest  class RestoreReconciliationInteractorTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt index 34c4c9842986..558e7694b54c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt @@ -19,14 +19,12 @@ package com.android.systemui.qs.pipeline.shared  import android.content.ComponentName  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.google.common.truth.Truth.assertThat  import org.junit.Test  import org.junit.runner.RunWith  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class TileSpecTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandlerTest.kt index 06b7a9fde873..5659f0173860 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandlerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandlerTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.qs.tiles.base.actions  import android.content.Intent  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.plugins.ActivityStarter  import org.junit.Before @@ -32,7 +31,6 @@ import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class QSTileIntentUserActionHandlerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt index 2c4e10eadfc9..9861606fd1b1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt @@ -20,7 +20,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.internal.logging.InstanceId  import com.android.internal.logging.UiEventLogger -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.qs.QSEvent  import com.android.systemui.qs.tiles.viewmodel.QSTileConfigTestBuilder @@ -34,7 +33,6 @@ import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class QSTileAnalyticsTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt index 4f25d12aea49..a6199c25874b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt @@ -24,7 +24,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.settingslib.RestrictedLockUtils  import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.plugins.ActivityStarter  import com.android.systemui.util.mockito.any @@ -46,7 +45,6 @@ import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class DisabledByPolicyInteractorTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt index 4401e0d60da6..f1fcee318141 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.qs.tiles.base.logging  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.common.shared.model.ContentDescription  import com.android.systemui.common.shared.model.Icon @@ -39,7 +38,6 @@ import org.mockito.Mock  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class QSTileLoggerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt index 4760dfa3561d..2084aeb7fe83 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt @@ -20,7 +20,6 @@ import android.testing.TestableLooper  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.MediumTest  import com.android.internal.logging.InstanceId -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.classifier.FalsingManagerFake  import com.android.systemui.common.shared.model.ContentDescription @@ -49,7 +48,6 @@ import org.mockito.MockitoAnnotations  // TODO(b/299909368): Add more tests  @MediumTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @TestableLooper.RunWithLooper(setAsMainLooper = true)  class QSTileViewModelInterfaceComplianceTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt index f1c99d71b4e5..58e36be2b9fd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt @@ -16,6 +16,7 @@  package com.android.systemui.qs.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.authentication.data.model.AuthenticationMethodModel @@ -38,11 +39,10 @@ import kotlinx.coroutines.test.runTest  import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class QuickSettingsSceneViewModelTest : SysuiTestCase() {      private val utils = SceneTestUtils(this) diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt index 91f38656e02d..2e16577bb24f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt @@ -18,6 +18,7 @@  package com.android.systemui.scene +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository @@ -51,6 +52,7 @@ import com.google.common.truth.Truth.assertWithMessage  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.Job  import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flowOf  import kotlinx.coroutines.launch  import kotlinx.coroutines.test.TestScope  import kotlinx.coroutines.test.runCurrent @@ -58,7 +60,6 @@ import kotlinx.coroutines.test.runTest  import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  /**   * Integration test cases for the Scene Framework. @@ -80,7 +81,7 @@ import org.junit.runners.JUnit4   */  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class SceneFrameworkIntegrationTest : SysuiTestCase() {      private val utils = SceneTestUtils(this) @@ -462,7 +463,8 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {                  fromScene = getCurrentSceneInUi(),                  toScene = to.key,                  progress = progressFlow, -                isUserInputDriven = false, +                isInitiatedByUserInput = false, +                isUserInputOngoing = flowOf(false),              )          runCurrent() diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt index ff28d2dbccdd..740c6d9329df 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt @@ -18,6 +18,7 @@  package com.android.systemui.scene.data.repository +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue @@ -28,13 +29,13 @@ import com.android.systemui.scene.shared.model.SceneModel  import com.google.common.truth.Truth.assertThat  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flowOf  import kotlinx.coroutines.test.runTest  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class SceneContainerRepositoryTest : SysuiTestCase() {      private val utils = SceneTestUtils(this) @@ -119,7 +120,8 @@ class SceneContainerRepositoryTest : SysuiTestCase() {                      fromScene = SceneKey.Lockscreen,                      toScene = SceneKey.Shade,                      progress = progress, -                    isUserInputDriven = false, +                    isInitiatedByUserInput = false, +                    isUserInputOngoing = flowOf(false),                  )              assertThat(reflectedTransitionState).isEqualTo(transitionState.value) diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepositoryTest.kt index 2187f3657848..7ae501d05fcd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepositoryTest.kt @@ -16,6 +16,7 @@  package com.android.systemui.scene.data.repository +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.internal.statusbar.IStatusBarService  import com.android.systemui.SysuiTestCase @@ -24,9 +25,11 @@ import com.android.systemui.util.mockito.mock  import com.android.systemui.util.time.FakeSystemClock  import com.google.common.truth.Truth.assertThat  import org.junit.Test +import org.junit.runner.RunWith  import org.mockito.Mockito.verify  @SmallTest +@RunWith(AndroidJUnit4::class)  class WindowRootViewVisibilityRepositoryTest : SysuiTestCase() {      private val iStatusBarService = mock<IStatusBarService>()      private val executor = FakeExecutor(FakeSystemClock()) diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt index afc0e6944839..31d26c0d88f9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt @@ -14,10 +14,9 @@   * limitations under the License.   */ -@file:OptIn(ExperimentalCoroutinesApi::class, ExperimentalCoroutinesApi::class) -  package com.android.systemui.scene.domain.interactor +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue @@ -26,16 +25,14 @@ import com.android.systemui.scene.shared.model.ObservableTransitionState  import com.android.systemui.scene.shared.model.SceneKey  import com.android.systemui.scene.shared.model.SceneModel  import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.flow.MutableStateFlow  import kotlinx.coroutines.flow.flowOf  import kotlinx.coroutines.test.runTest  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class SceneInteractorTest : SysuiTestCase() {      private val utils = SceneTestUtils(this) @@ -86,7 +83,8 @@ class SceneInteractorTest : SysuiTestCase() {                      fromScene = SceneKey.Lockscreen,                      toScene = SceneKey.Shade,                      progress = progress, -                    isUserInputDriven = false, +                    isInitiatedByUserInput = false, +                    isUserInputOngoing = flowOf(false),                  )              assertThat(reflectedTransitionState).isEqualTo(transitionState.value) @@ -124,7 +122,8 @@ class SceneInteractorTest : SysuiTestCase() {                      fromScene = underTest.desiredScene.value.key,                      toScene = SceneKey.Shade,                      progress = progress, -                    isUserInputDriven = false, +                    isInitiatedByUserInput = false, +                    isUserInputOngoing = flowOf(false),                  )              assertThat(transitionTo).isEqualTo(SceneKey.Shade) @@ -161,7 +160,8 @@ class SceneInteractorTest : SysuiTestCase() {                          fromScene = SceneKey.Gone,                          toScene = SceneKey.Lockscreen,                          progress = flowOf(0.5f), -                        isUserInputDriven = false, +                        isInitiatedByUserInput = false, +                        isUserInputOngoing = flowOf(false),                      )                  )              val transitioning by @@ -180,7 +180,8 @@ class SceneInteractorTest : SysuiTestCase() {                          fromScene = SceneKey.Shade,                          toScene = SceneKey.QuickSettings,                          progress = flowOf(0.5f), -                        isUserInputDriven = false, +                        isInitiatedByUserInput = false, +                        isUserInputOngoing = flowOf(false),                      )                  )              underTest.setTransitionState(transitionState) @@ -197,7 +198,8 @@ class SceneInteractorTest : SysuiTestCase() {                          fromScene = SceneKey.Shade,                          toScene = SceneKey.Lockscreen,                          progress = flowOf(0.5f), -                        isUserInputDriven = false, +                        isInitiatedByUserInput = false, +                        isUserInputOngoing = flowOf(false),                      )                  )              val transitioning by @@ -225,7 +227,8 @@ class SceneInteractorTest : SysuiTestCase() {                      fromScene = SceneKey.Shade,                      toScene = SceneKey.Lockscreen,                      progress = flowOf(0.5f), -                    isUserInputDriven = false, +                    isInitiatedByUserInput = false, +                    isUserInputOngoing = flowOf(false),                  )              assertThat(transitioning).isTrue() diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt index 3785fd7436c1..8be4eeb7be7a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt @@ -16,6 +16,7 @@  package com.android.systemui.scene.domain.interactor +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.internal.statusbar.IStatusBarService  import com.android.systemui.SysuiTestCase @@ -36,16 +37,16 @@ import com.android.systemui.util.mockito.mock  import com.android.systemui.util.mockito.whenever  import com.android.systemui.util.time.FakeSystemClock  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.Test +import org.junit.runner.RunWith  import org.mockito.Mockito.reset  import org.mockito.Mockito.verify  @SmallTest -@OptIn(ExperimentalCoroutinesApi::class) +@RunWith(AndroidJUnit4::class)  class WindowRootViewVisibilityInteractorTest : SysuiTestCase() {      private val testScope = TestScope() diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt index 0216a0a98d84..3b9621e5c6e0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt @@ -20,6 +20,7 @@ package com.android.systemui.scene.domain.startable  import android.os.PowerManager  import android.view.Display +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.authentication.domain.model.AuthenticationMethodModel @@ -46,14 +47,13 @@ import kotlinx.coroutines.test.runTest  import org.junit.Assume.assumeTrue  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  import org.mockito.Mockito.clearInvocations  import org.mockito.Mockito.never  import org.mockito.Mockito.times  import org.mockito.Mockito.verify  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class SceneContainerStartableTest : SysuiTestCase() {      private val utils = SceneTestUtils(this) @@ -109,7 +109,8 @@ class SceneContainerStartableTest : SysuiTestCase() {                      fromScene = SceneKey.Gone,                      toScene = SceneKey.Shade,                      progress = flowOf(0.5f), -                    isUserInputDriven = false, +                    isInitiatedByUserInput = false, +                    isUserInputOngoing = flowOf(false),                  )              assertThat(isVisible).isTrue()              sceneInteractor.onSceneChanged(SceneModel(SceneKey.Shade), "reason") @@ -122,7 +123,8 @@ class SceneContainerStartableTest : SysuiTestCase() {                      fromScene = SceneKey.Shade,                      toScene = SceneKey.Gone,                      progress = flowOf(0.5f), -                    isUserInputDriven = false, +                    isInitiatedByUserInput = false, +                    isUserInputOngoing = flowOf(false),                  )              assertThat(isVisible).isTrue()              sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone), "reason") diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt index 0b56a59ca467..c89cd9e0c1f1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt @@ -18,6 +18,7 @@  package com.android.systemui.scene.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue @@ -29,10 +30,9 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.test.runTest  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class SceneContainerViewModelTest : SysuiTestCase() {      private val utils = SceneTestUtils(this) diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt index 1bb2ff825115..263b0017221a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt @@ -42,6 +42,7 @@ class UserTrackerImplReceiveTest : SysuiTestCase() {          @Parameterized.Parameters          fun data(): Iterable<String> =              listOf( +                Intent.ACTION_LOCALE_CHANGED,                  Intent.ACTION_USER_INFO_CHANGED,                  Intent.ACTION_MANAGED_PROFILE_AVAILABLE,                  Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE, diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt index 52b25f85b870..c32d2597bd61 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt @@ -177,7 +177,8 @@ class UserTrackerImplTest : SysuiTestCase() {          verify(context)                  .registerReceiverForAllUsers(eq(tracker), capture(captor), isNull(), eq(handler))          with(captor.value) { -            assertThat(countActions()).isEqualTo(6) +            assertThat(countActions()).isEqualTo(7) +            assertThat(hasAction(Intent.ACTION_LOCALE_CHANGED)).isTrue()              assertThat(hasAction(Intent.ACTION_USER_INFO_CHANGED)).isTrue()              assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)).isTrue()              assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)).isTrue() 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 7b12931b2b47..8d8c70e26ab2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -79,7 +79,6 @@ import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;  import com.android.keyguard.dagger.KeyguardStatusViewComponent;  import com.android.keyguard.dagger.KeyguardUserSwitcherComponent;  import com.android.keyguard.logging.KeyguardLogger; -import com.android.systemui.res.R;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.biometrics.AuthController;  import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor; @@ -120,6 +119,7 @@ import com.android.systemui.plugins.FalsingManager;  import com.android.systemui.plugins.qs.QS;  import com.android.systemui.power.domain.interactor.PowerInteractor;  import com.android.systemui.qs.QSFragmentLegacy; +import com.android.systemui.res.R;  import com.android.systemui.screenrecord.RecordingController;  import com.android.systemui.shade.data.repository.FakeShadeRepository;  import com.android.systemui.shade.data.repository.ShadeRepository; @@ -153,7 +153,6 @@ import com.android.systemui.statusbar.phone.CentralSurfaces;  import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;  import com.android.systemui.statusbar.phone.DozeParameters;  import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;  import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;  import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;  import com.android.systemui.statusbar.phone.KeyguardBottomAreaViewController; @@ -170,6 +169,7 @@ import com.android.systemui.statusbar.phone.TapAgainViewController;  import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;  import com.android.systemui.statusbar.policy.CastController;  import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;  import com.android.systemui.statusbar.policy.KeyguardStateController;  import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController; @@ -182,6 +182,8 @@ import com.android.systemui.util.time.FakeSystemClock;  import com.android.systemui.util.time.SystemClock;  import com.android.wm.shell.animation.FlingAnimationUtils; +import dagger.Lazy; +  import org.junit.After;  import org.junit.Before;  import org.mockito.ArgumentCaptor; @@ -193,7 +195,6 @@ import org.mockito.stubbing.Answer;  import java.util.List;  import java.util.Optional; -import dagger.Lazy;  import kotlinx.coroutines.CoroutineDispatcher;  public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { @@ -208,7 +209,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {      @Mock protected KeyguardBottomAreaViewController mKeyguardBottomAreaViewController;      @Mock protected ViewPropertyAnimator mViewPropertyAnimator;      @Mock protected KeyguardBottomAreaView mQsFrame; -    @Mock protected HeadsUpManagerPhone mHeadsUpManager; +    @Mock protected HeadsUpManager mHeadsUpManager;      @Mock protected NotificationShelfController mNotificationShelfController;      @Mock protected NotificationGutsManager mGutsManager;      @Mock protected KeyguardStatusBarView mKeyguardStatusBar; @@ -527,7 +528,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {          NotificationWakeUpCoordinator coordinator =                  new NotificationWakeUpCoordinator(                          mDumpManager, -                        mock(HeadsUpManagerPhone.class), +                        mock(HeadsUpManager.class),                          new StatusBarStateControllerImpl(new UiEventLoggerFake(), mDumpManager,                                  mInteractionJankMonitor, mShadeExpansionStateManager),                          mKeyguardBypassController, @@ -547,7 +548,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {                  mLockscreenShadeTransitionController,                  new FalsingCollectorFake(),                  mDumpManager); -        when(mKeyguardStatusViewComponentFactory.build(any())) +        when(mKeyguardStatusViewComponentFactory.build(any(), any()))                  .thenReturn(mKeyguardStatusViewComponent);          when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())                  .thenReturn(mKeyguardClockSwitchController); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java index 2ed20908ba2f..eb006100d535 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java @@ -47,18 +47,34 @@ import android.view.WindowManager;  import androidx.test.filters.SmallTest;  import com.android.internal.colorextraction.ColorExtractor; +import com.android.keyguard.KeyguardSecurityModel;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.biometrics.AuthController; +import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository; +import com.android.systemui.classifier.FalsingCollectorFake;  import com.android.systemui.colorextraction.SysuiColorExtractor;  import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository; +import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository;  import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FakeFeatureFlagsClassic;  import com.android.systemui.keyguard.KeyguardViewMediator; +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.domain.interactor.FromLockscreenTransitionInteractor; +import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor; +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;  import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.power.data.repository.FakePowerRepository; +import com.android.systemui.power.domain.interactor.PowerInteractor;  import com.android.systemui.res.R;  import com.android.systemui.scene.FakeWindowRootViewComponent;  import com.android.systemui.scene.SceneTestUtils; +import com.android.systemui.scene.data.repository.SceneContainerRepository; +import com.android.systemui.scene.domain.interactor.SceneInteractor;  import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags; +import com.android.systemui.scene.shared.logger.SceneLogger;  import com.android.systemui.shade.data.repository.FakeShadeRepository;  import com.android.systemui.shade.domain.interactor.ShadeInteractor;  import com.android.systemui.statusbar.StatusBarState; @@ -71,9 +87,9 @@ import com.android.systemui.statusbar.phone.ScreenOffAnimationController;  import com.android.systemui.statusbar.phone.ScrimController;  import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository;  import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.DeviceProvisionedController;  import com.android.systemui.statusbar.policy.KeyguardStateController;  import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController; +import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;  import com.android.systemui.user.domain.interactor.UserInteractor;  import com.google.common.util.concurrent.MoreExecutors; @@ -109,6 +125,7 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {      @Mock private SysuiColorExtractor mColorExtractor;      @Mock ColorExtractor.GradientColors mGradientColors;      @Mock private DumpManager mDumpManager; +    @Mock private KeyguardSecurityModel mKeyguardSecurityModel;      @Mock private KeyguardStateController mKeyguardStateController;      @Mock private ScreenOffAnimationController mScreenOffAnimationController;      @Mock private AuthController mAuthController; @@ -123,6 +140,8 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {      private NotificationShadeWindowControllerImpl mNotificationShadeWindowController;      private float mPreferredRefreshRate = -1; +    private FromLockscreenTransitionInteractor mFromLockscreenTransitionInteractor; +    private FromPrimaryBouncerTransitionInteractor mFromPrimaryBouncerTransitionInteractor;      @Before      public void setUp() { @@ -137,22 +156,86 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {          when(mDozeParameters.getAlwaysOn()).thenReturn(true);          when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors); +        FakeKeyguardRepository keyguardRepository = new FakeKeyguardRepository(); +        FakeFeatureFlagsClassic featureFlags = new FakeFeatureFlagsClassic(); +        FakeShadeRepository shadeRepository = new FakeShadeRepository(); +        FakePowerRepository powerRepository = new FakePowerRepository(); + +        PowerInteractor powerInteractor = new PowerInteractor( +                powerRepository, +                new FalsingCollectorFake(), +                mScreenOffAnimationController, +                mStatusBarStateController); + +        SceneInteractor sceneInteractor = new SceneInteractor( +                mTestScope.getBackgroundScope(), +                new SceneContainerRepository( +                        mTestScope.getBackgroundScope(), +                        mUtils.fakeSceneContainerConfig(mUtils.fakeSceneKeys())), +                powerRepository, +                mock(SceneLogger.class)); + +        FakeConfigurationRepository configurationRepository = new FakeConfigurationRepository(); +        FakeSceneContainerFlags sceneContainerFlags = new FakeSceneContainerFlags(); +        KeyguardInteractor keyguardInteractor = new KeyguardInteractor( +                keyguardRepository, +                new FakeCommandQueue(), +                powerInteractor, +                featureFlags, +                sceneContainerFlags, +                new FakeDeviceEntryRepository(), +                new FakeKeyguardBouncerRepository(), +                configurationRepository, +                shadeRepository, +                () -> sceneInteractor); + +        FakeKeyguardTransitionRepository keyguardTransitionRepository = +                new FakeKeyguardTransitionRepository(); + +        KeyguardTransitionInteractor keyguardTransitionInteractor = +                new KeyguardTransitionInteractor( +                        mTestScope.getBackgroundScope(), +                        keyguardTransitionRepository, +                        () -> keyguardInteractor, +                        () -> mFromLockscreenTransitionInteractor, +                        () -> mFromPrimaryBouncerTransitionInteractor); + +        mFromLockscreenTransitionInteractor = new FromLockscreenTransitionInteractor( +                keyguardTransitionRepository, +                keyguardTransitionInteractor, +                mTestScope.getBackgroundScope(), +                keyguardInteractor, +                featureFlags, +                shadeRepository, +                powerInteractor); + +        mFromPrimaryBouncerTransitionInteractor = new FromPrimaryBouncerTransitionInteractor( +                keyguardTransitionRepository, +                keyguardTransitionInteractor, +                mTestScope.getBackgroundScope(), +                keyguardInteractor, +                featureFlags, +                mKeyguardSecurityModel, +                powerInteractor); +          mShadeInteractor =                  new ShadeInteractor(                          mTestScope.getBackgroundScope(), +                        new FakeDeviceProvisioningRepository(),                          new FakeDisableFlagsRepository(), -                        new FakeSceneContainerFlags(), -                        mUtils::sceneInteractor, -                        new FakeKeyguardRepository(), +                        mock(DozeParameters.class), +                        sceneContainerFlags, +                        () -> sceneInteractor, +                        keyguardRepository, +                        keyguardTransitionInteractor, +                        powerInteractor,                          new FakeUserSetupRepository(), -                        mock(DeviceProvisionedController.class),                          mock(UserInteractor.class),                          new SharedNotificationContainerInteractor( -                                new FakeConfigurationRepository(), +                                configurationRepository,                                  mContext,                                  new ResourcesSplitShadeStateController()), -                        new FakeShadeRepository() -                ); +                        shadeRepository);          mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(                  mContext, diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt index 96510721baa5..b4f9e8dcfb39 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -34,6 +34,7 @@ import com.android.systemui.back.domain.interactor.BackActionInteractor  import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository  import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl  import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository +import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor  import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor  import com.android.systemui.bouncer.domain.interactor.CountDownTimerUtil  import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor @@ -83,7 +84,6 @@ import com.android.systemui.user.data.repository.FakeUserRepository  import com.android.systemui.util.mockito.any  import com.android.systemui.util.time.FakeSystemClock  import com.google.common.truth.Truth.assertThat -import java.util.Optional  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.flow.emptyFlow  import kotlinx.coroutines.test.TestScope @@ -97,8 +97,9 @@ import org.mockito.Mockito.anyFloat  import org.mockito.Mockito.mock  import org.mockito.Mockito.never  import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` as whenever  import org.mockito.MockitoAnnotations +import java.util.Optional +import org.mockito.Mockito.`when` as whenever  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest @@ -144,6 +145,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {      @Mock      lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel      @Mock lateinit var keyEventInteractor: KeyEventInteractor +    @Mock lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor +    @Mock lateinit var alternateBouncerInteractor: AlternateBouncerInteractor      private val notificationExpansionRepository = NotificationExpansionRepository()      private lateinit var fakeClock: FakeSystemClock @@ -176,6 +179,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {          featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)          featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false)          featureFlags.set(Flags.MIGRATE_NSSL, false) +        featureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, false)          testScope = TestScope()          fakeClock = FakeSystemClock() @@ -248,6 +252,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {                  ),                  BouncerLogger(logcatLogBuffer("BouncerLog")),                  keyEventInteractor, +                primaryBouncerInteractor, +                alternateBouncerInteractor,              )          underTest.setupExpandedStatusBar()          underTest.setDragDownHelper(dragDownHelper) @@ -425,29 +431,37 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {      }      @Test -    fun shouldInterceptTouchEvent_notificationPanelViewControllerShouldIntercept() { -        // GIVEN not dozing -        whenever(sysuiStatusBarStateController.isDozing()).thenReturn(false) +    fun shouldInterceptTouchEvent_dozing_touchInLockIconArea_touchNotIntercepted() { +        // GIVEN dozing +        whenever(sysuiStatusBarStateController.isDozing).thenReturn(true)          // AND alternate bouncer doesn't want the touch          whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(DOWN_EVENT))              .thenReturn(false) -        // AND the lock icon doesn't want the touch -        whenever(lockIconViewController.onInterceptTouchEvent(DOWN_EVENT)).thenReturn(false) -        // AND the notification panel can accept touches -        whenever(notificationPanelViewController.isFullyExpanded()).thenReturn(true) -        whenever(dragDownHelper.isDragDownEnabled).thenReturn(true) -        whenever(centralSurfaces.isBouncerShowing()).thenReturn(false) - -        // AND the drag down helper doesn't want the touch (to pull the shade down) -        whenever(dragDownHelper.onInterceptTouchEvent(DOWN_EVENT)).thenReturn(false) +        // AND the lock icon wants the touch +        whenever(lockIconViewController.willHandleTouchWhileDozing(DOWN_EVENT)) +                .thenReturn(true)          featureFlags.set(Flags.MIGRATE_NSSL, true) -        // WHEN asked if should intercept touch -        interactionEventHandler.shouldInterceptTouchEvent(DOWN_EVENT) +        // THEN touch should NOT be intercepted by NotificationShade +        assertThat(interactionEventHandler.shouldInterceptTouchEvent(DOWN_EVENT)).isFalse() +    } + +    @Test +    fun shouldInterceptTouchEvent_dozing_touchNotInLockIconArea_touchIntercepted() { +        // GIVEN dozing +        whenever(sysuiStatusBarStateController.isDozing).thenReturn(true) +        // AND alternate bouncer doesn't want the touch +        whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(DOWN_EVENT)) +                .thenReturn(false) +        // AND the lock icon does NOT want the touch +        whenever(lockIconViewController.willHandleTouchWhileDozing(DOWN_EVENT)) +                .thenReturn(false) + +        featureFlags.set(Flags.MIGRATE_NSSL, true) -        // Verify that NPVC gets a chance to use the touch -        verify(notificationPanelViewController).handleExternalInterceptTouch(DOWN_EVENT) +        // THEN touch should NOT be intercepted by NotificationShade +        assertThat(interactionEventHandler.shouldInterceptTouchEvent(DOWN_EVENT)).isTrue()      }      @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt index 00230202d941..189c9e25d9b0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt @@ -33,6 +33,7 @@ import com.android.systemui.back.domain.interactor.BackActionInteractor  import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository  import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl  import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository +import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor  import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor  import com.android.systemui.bouncer.domain.interactor.CountDownTimerUtil  import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor @@ -141,6 +142,8 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {          Optional<UnfoldTransitionProgressProvider>      @Mock private lateinit var notificationInsetsController: NotificationInsetsController      @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor +    @Mock lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor +    @Mock lateinit var alternateBouncerInteractor: AlternateBouncerInteractor      @Mock      private lateinit var primaryBouncerToGoneTransitionViewModel:          PrimaryBouncerToGoneTransitionViewModel @@ -180,6 +183,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {          featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)          featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false)          featureFlags.set(Flags.MIGRATE_NSSL, false) +        featureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, false)          testScope = TestScope()          controller =              NotificationShadeWindowViewController( @@ -250,6 +254,8 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {                  ),                  BouncerLogger(logcatLogBuffer("BouncerLog")),                  Mockito.mock(KeyEventInteractor::class.java), +                primaryBouncerInteractor, +                alternateBouncerInteractor,              )          controller.setupExpandedStatusBar() diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java index 8138b328a3c5..65174bab7f63 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java @@ -32,23 +32,39 @@ import android.view.accessibility.AccessibilityManager;  import com.android.internal.jank.InteractionJankMonitor;  import com.android.internal.logging.MetricsLogger;  import com.android.internal.logging.UiEventLogger; +import com.android.keyguard.KeyguardSecurityModel;  import com.android.keyguard.KeyguardStatusView;  import com.android.keyguard.KeyguardUpdateMonitor;  import com.android.systemui.SysuiTestCase; +import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository; +import com.android.systemui.classifier.FalsingCollectorFake;  import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository; +import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository;  import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FakeFeatureFlagsClassic;  import com.android.systemui.flags.FeatureFlags;  import com.android.systemui.fragments.FragmentHostManager; +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.domain.interactor.FromLockscreenTransitionInteractor; +import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor;  import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;  import com.android.systemui.media.controls.pipeline.MediaDataManager;  import com.android.systemui.media.controls.ui.MediaHierarchyManager;  import com.android.systemui.plugins.FalsingManager;  import com.android.systemui.plugins.qs.QS; +import com.android.systemui.power.data.repository.FakePowerRepository; +import com.android.systemui.power.domain.interactor.PowerInteractor;  import com.android.systemui.qs.QSFragmentLegacy;  import com.android.systemui.res.R;  import com.android.systemui.scene.SceneTestUtils; +import com.android.systemui.scene.data.repository.SceneContainerRepository; +import com.android.systemui.scene.domain.interactor.SceneInteractor;  import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags; +import com.android.systemui.scene.shared.logger.SceneLogger;  import com.android.systemui.screenrecord.RecordingController;  import com.android.systemui.shade.data.repository.FakeShadeRepository;  import com.android.systemui.shade.domain.interactor.ShadeInteractor; @@ -64,19 +80,21 @@ import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFl  import com.android.systemui.statusbar.notification.stack.AmbientState;  import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;  import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor; +import com.android.systemui.statusbar.phone.DozeParameters;  import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;  import com.android.systemui.statusbar.phone.KeyguardBypassController;  import com.android.systemui.statusbar.phone.KeyguardStatusBarView;  import com.android.systemui.statusbar.phone.LightBarController;  import com.android.systemui.statusbar.phone.LockscreenGestureLogger; +import com.android.systemui.statusbar.phone.ScreenOffAnimationController;  import com.android.systemui.statusbar.phone.ScrimController;  import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;  import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;  import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository;  import com.android.systemui.statusbar.policy.CastController; -import com.android.systemui.statusbar.policy.DeviceProvisionedController;  import com.android.systemui.statusbar.policy.KeyguardStateController;  import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController; +import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;  import com.android.systemui.user.domain.interactor.UserInteractor;  import com.android.systemui.util.kotlin.JavaAdapter; @@ -103,8 +121,7 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {      protected SceneTestUtils mUtils = new SceneTestUtils(this);      protected TestScope mTestScope = mUtils.getTestScope(); -    @Mock -    protected Resources mResources; +    @Mock protected Resources mResources;      @Mock protected KeyguardBottomAreaView mQsFrame;      @Mock protected KeyguardStatusBarView mKeyguardStatusBar;      @Mock protected QS mQs; @@ -126,6 +143,7 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {      @Mock protected NotificationShadeDepthController mNotificationShadeDepthController;      @Mock protected ShadeHeaderController mShadeHeaderController;      @Mock protected StatusBarTouchableRegionManager mStatusBarTouchableRegionManager; +    @Mock protected DozeParameters mDozeParameters;      @Mock protected KeyguardStateController mKeyguardStateController;      @Mock protected KeyguardBypassController mKeyguardBypassController;      @Mock protected KeyguardUpdateMonitor mKeyguardUpdateMonitor; @@ -144,7 +162,6 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {      @Mock protected DumpManager mDumpManager;      @Mock protected UiEventLogger mUiEventLogger;      @Mock protected CastController mCastController; -    @Mock protected DeviceProvisionedController mDeviceProvisionedController;      @Mock protected UserInteractor mUserInteractor;      protected FakeDisableFlagsRepository mDisableFlagsRepository =              new FakeDisableFlagsRepository(); @@ -161,6 +178,8 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {              new ShadeExpansionStateManager();      protected FragmentHostManager.FragmentListener mFragmentListener; +    private FromLockscreenTransitionInteractor mFromLockscreenTransitionInteractor; +    private FromPrimaryBouncerTransitionInteractor mFromPrimaryBouncerTransitionInteractor;      @Before      public void setup() { @@ -169,21 +188,89 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {          mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager,                  mInteractionJankMonitor, mShadeExpansionStateManager); -        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true); +        FakeDeviceProvisioningRepository deviceProvisioningRepository = +                new FakeDeviceProvisioningRepository(); +        deviceProvisioningRepository.setDeviceProvisioned(true); +        FakeFeatureFlagsClassic featureFlags = new FakeFeatureFlagsClassic(); +        FakePowerRepository powerRepository = new FakePowerRepository(); +        FakeConfigurationRepository configurationRepository = new FakeConfigurationRepository(); + +        PowerInteractor powerInteractor = new PowerInteractor( +                powerRepository, +                new FalsingCollectorFake(), +                mock(ScreenOffAnimationController.class), +                mStatusBarStateController); + +        SceneInteractor sceneInteractor = new SceneInteractor( +                mTestScope.getBackgroundScope(), +                new SceneContainerRepository( +                        mTestScope.getBackgroundScope(), +                        mUtils.fakeSceneContainerConfig(mUtils.fakeSceneKeys())), +                powerRepository, +                mock(SceneLogger.class)); + +        FakeSceneContainerFlags sceneContainerFlags = new FakeSceneContainerFlags(); +        KeyguardInteractor keyguardInteractor = new KeyguardInteractor( +                mKeyguardRepository, +                new FakeCommandQueue(), +                powerInteractor, +                featureFlags, +                sceneContainerFlags, +                new FakeDeviceEntryRepository(), +                new FakeKeyguardBouncerRepository(), +                configurationRepository, +                mShadeRepository, +                () -> sceneInteractor); + +        FakeKeyguardTransitionRepository keyguardTransitionRepository = +                new FakeKeyguardTransitionRepository(); + +        KeyguardTransitionInteractor keyguardTransitionInteractor = +                new KeyguardTransitionInteractor( +                        mTestScope.getBackgroundScope(), +                        keyguardTransitionRepository, +                        () -> keyguardInteractor, +                        () -> mFromLockscreenTransitionInteractor, +                        () -> mFromPrimaryBouncerTransitionInteractor); + +        mFromLockscreenTransitionInteractor = new FromLockscreenTransitionInteractor( +                keyguardTransitionRepository, +                keyguardTransitionInteractor, +                mTestScope.getBackgroundScope(), +                keyguardInteractor, +                featureFlags, +                mShadeRepository, +                powerInteractor); + +        mFromPrimaryBouncerTransitionInteractor = new FromPrimaryBouncerTransitionInteractor( +                keyguardTransitionRepository, +                keyguardTransitionInteractor, +                mTestScope.getBackgroundScope(), +                keyguardInteractor, +                featureFlags, +                mock(KeyguardSecurityModel.class), +                powerInteractor); + +        ResourcesSplitShadeStateController splitShadeStateController = +                new ResourcesSplitShadeStateController(); +          mShadeInteractor =                  new ShadeInteractor(                          mTestScope.getBackgroundScope(), +                        deviceProvisioningRepository,                          mDisableFlagsRepository, -                        new FakeSceneContainerFlags(), -                        () -> mUtils.sceneInteractor(), +                        mDozeParameters, +                        sceneContainerFlags, +                        () -> sceneInteractor,                          mKeyguardRepository, +                        keyguardTransitionInteractor, +                        powerInteractor,                          new FakeUserSetupRepository(), -                        mDeviceProvisionedController,                          mUserInteractor,                          new SharedNotificationContainerInteractor( -                                new FakeConfigurationRepository(), +                                configurationRepository,                                  mContext, -                                new ResourcesSplitShadeStateController()), +                                splitShadeStateController),                          mShadeRepository                  ); @@ -262,7 +349,7 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {                  mShadeInteractor,                  new JavaAdapter(mTestScope.getBackgroundScope()),                  mCastController, -                new ResourcesSplitShadeStateController() +                splitShadeStateController          );          mQsController.init(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt index b5841a9de150..215f8b1c462f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt @@ -17,6 +17,7 @@  package com.android.systemui.shade  import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper  import android.view.Display  import android.view.WindowManager  import androidx.test.filters.SmallTest @@ -54,6 +55,7 @@ import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations  @RunWith(AndroidTestingRunner::class) +@RunWithLooper(setAsMainLooper = true)  @SmallTest  class ShadeControllerImplTest : SysuiTestCase() {      private val executor = FakeExecutor(FakeSystemClock()) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt index 2be1c09843c1..bcb060ddb417 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt @@ -16,50 +16,53 @@  package com.android.systemui.shade.data.repository -import android.app.ActivityManager  import android.app.StatusBarManager.DISABLE2_NONE  import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE  import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS  import android.content.pm.UserInfo  import android.os.UserManager  import androidx.test.filters.SmallTest -import com.android.internal.logging.UiEventLogger -import com.android.keyguard.KeyguardUpdateMonitor +import com.android.SysUITestModule +import com.android.TestMocksModule  import com.android.systemui.SysuiTestCase  import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository  import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.flags.FakeFeatureFlags +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.flags.FakeFeatureFlagsClassicModule  import com.android.systemui.flags.Flags  import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +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.StatusBarState -import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.power.data.repository.FakePowerRepository +import com.android.systemui.power.shared.model.WakeSleepReason +import com.android.systemui.power.shared.model.WakefulnessState  import com.android.systemui.res.R -import com.android.systemui.scene.SceneTestUtils -import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags +import com.android.systemui.scene.domain.interactor.SceneInteractor  import com.android.systemui.scene.shared.model.ObservableTransitionState  import com.android.systemui.scene.shared.model.SceneKey  import com.android.systemui.shade.domain.interactor.ShadeInteractor  import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel  import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository -import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor +import com.android.systemui.statusbar.phone.DozeParameters  import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository -import com.android.systemui.statusbar.policy.DeviceProvisionedController -import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController -import com.android.systemui.telephony.data.repository.FakeTelephonyRepository -import com.android.systemui.telephony.domain.interactor.TelephonyInteractor +import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository  import com.android.systemui.user.data.model.UserSwitcherSettingsModel  import com.android.systemui.user.data.repository.FakeUserRepository -import com.android.systemui.user.domain.interactor.GuestUserInteractor -import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode -import com.android.systemui.user.domain.interactor.RefreshUsersScheduler -import com.android.systemui.user.domain.interactor.UserInteractor -import com.android.systemui.util.mockito.mock +import com.android.systemui.user.domain.UserDomainLayerModule  import com.android.systemui.util.mockito.whenever  import com.google.common.truth.Truth.assertThat +import dagger.BindsInstance +import dagger.Component  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flowOf  import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.TestScope  import kotlinx.coroutines.test.runCurrent  import kotlinx.coroutines.test.runTest  import org.junit.Before @@ -70,50 +73,55 @@ import org.mockito.MockitoAnnotations  @SmallTest  @OptIn(ExperimentalCoroutinesApi::class)  class ShadeInteractorTest : SysuiTestCase() { -    private lateinit var underTest: ShadeInteractor -    private val utils = SceneTestUtils(this) -    private val testScope = utils.testScope -    private val featureFlags = FakeFeatureFlags() -    private val sceneContainerFlags = FakeSceneContainerFlags() -    private val sceneInteractor = utils.sceneInteractor() -    private val userSetupRepository = FakeUserSetupRepository() -    private val userRepository = FakeUserRepository() -    private val disableFlagsRepository = FakeDisableFlagsRepository() -    private val keyguardRepository = FakeKeyguardRepository() -    private val shadeRepository = FakeShadeRepository() -    private val configurationRepository = FakeConfigurationRepository() -    private val sharedNotificationContainerInteractor = -        SharedNotificationContainerInteractor( -            configurationRepository, -            mContext, -            ResourcesSplitShadeStateController() -        ) - -    @Mock private lateinit var manager: UserManager -    @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode -    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController -    @Mock private lateinit var activityStarter: ActivityStarter -    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor -    @Mock private lateinit var activityManager: ActivityManager -    @Mock private lateinit var uiEventLogger: UiEventLogger -    @Mock private lateinit var guestInteractor: GuestUserInteractor - -    private lateinit var userInteractor: UserInteractor +    @Mock private lateinit var dozeParameters: DozeParameters + +    private lateinit var testComponent: TestComponent + +    private val configurationRepository +        get() = testComponent.configurationRepository +    private val deviceProvisioningRepository +        get() = testComponent.deviceProvisioningRepository +    private val disableFlagsRepository +        get() = testComponent.disableFlagsRepository +    private val keyguardRepository +        get() = testComponent.keyguardRepository +    private val keyguardTransitionRepository +        get() = testComponent.keygaurdTransitionRepository +    private val powerRepository +        get() = testComponent.powerRepository +    private val sceneInteractor +        get() = testComponent.sceneInteractor +    private val shadeRepository +        get() = testComponent.shadeRepository +    private val testScope +        get() = testComponent.testScope +    private val userRepository +        get() = testComponent.userRepository +    private val userSetupRepository +        get() = testComponent.userSetupRepository + +    private lateinit var underTest: ShadeInteractor      @Before      fun setUp() {          MockitoAnnotations.initMocks(this) -        featureFlags.set(Flags.FACE_AUTH_REFACTOR, false) -        featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true) - -        val refreshUsersScheduler = -            RefreshUsersScheduler( -                applicationScope = testScope.backgroundScope, -                mainDispatcher = utils.testDispatcher, -                repository = userRepository, -            ) +        testComponent = +            DaggerShadeInteractorTest_TestComponent.factory() +                .create( +                    test = this, +                    featureFlags = +                        FakeFeatureFlagsClassicModule { +                            set(Flags.FACE_AUTH_REFACTOR, false) +                            set(Flags.FULL_SCREEN_USER_SWITCHER, true) +                        }, +                    mocks = +                        TestMocksModule( +                            dozeParameters = dozeParameters, +                        ), +                ) +        underTest = testComponent.underTest          runBlocking {              val userInfos = @@ -131,44 +139,6 @@ class ShadeInteractorTest : SysuiTestCase() {              userRepository.setUserInfos(userInfos)              userRepository.setSelectedUserInfo(userInfos[0])          } -        userInteractor = -            UserInteractor( -                applicationContext = context, -                repository = userRepository, -                activityStarter = activityStarter, -                keyguardInteractor = -                    KeyguardInteractorFactory.create(featureFlags = featureFlags) -                        .keyguardInteractor, -                featureFlags = featureFlags, -                manager = manager, -                headlessSystemUserMode = headlessSystemUserMode, -                applicationScope = testScope.backgroundScope, -                telephonyInteractor = -                    TelephonyInteractor( -                        repository = FakeTelephonyRepository(), -                    ), -                broadcastDispatcher = fakeBroadcastDispatcher, -                keyguardUpdateMonitor = keyguardUpdateMonitor, -                backgroundDispatcher = utils.testDispatcher, -                activityManager = activityManager, -                refreshUsersScheduler = refreshUsersScheduler, -                guestUserInteractor = guestInteractor, -                uiEventLogger = uiEventLogger, -                userRestrictionChecker = mock(), -            ) -        underTest = -            ShadeInteractor( -                testScope.backgroundScope, -                disableFlagsRepository, -                sceneContainerFlags, -                { sceneInteractor }, -                keyguardRepository, -                userSetupRepository, -                deviceProvisionedController, -                userInteractor, -                sharedNotificationContainerInteractor, -                shadeRepository, -            )      }      @Test @@ -188,7 +158,7 @@ class ShadeInteractorTest : SysuiTestCase() {      @Test      fun isExpandToQsEnabled_deviceNotProvisioned_false() =          testScope.runTest { -            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(false) +            deviceProvisioningRepository.setDeviceProvisioned(false)              val actual by collectLastValue(underTest.isExpandToQsEnabled) @@ -198,7 +168,7 @@ class ShadeInteractorTest : SysuiTestCase() {      @Test      fun isExpandToQsEnabled_userNotSetupAndSimpleUserSwitcher_false() =          testScope.runTest { -            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) +            deviceProvisioningRepository.setDeviceProvisioned(true)              userSetupRepository.setUserSetup(false)              userRepository.setSettings(UserSwitcherSettingsModel(isSimpleUserSwitcher = true)) @@ -211,7 +181,7 @@ class ShadeInteractorTest : SysuiTestCase() {      @Test      fun isExpandToQsEnabled_shadeNotEnabled_false() =          testScope.runTest { -            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) +            deviceProvisioningRepository.setDeviceProvisioned(true)              userSetupRepository.setUserSetup(true)              disableFlagsRepository.disableFlags.value = @@ -227,7 +197,7 @@ class ShadeInteractorTest : SysuiTestCase() {      @Test      fun isExpandToQsEnabled_quickSettingsNotEnabled_false() =          testScope.runTest { -            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) +            deviceProvisioningRepository.setDeviceProvisioned(true)              userSetupRepository.setUserSetup(true)              disableFlagsRepository.disableFlags.value = @@ -242,7 +212,7 @@ class ShadeInteractorTest : SysuiTestCase() {      @Test      fun isExpandToQsEnabled_dozing_false() =          testScope.runTest { -            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) +            deviceProvisioningRepository.setDeviceProvisioned(true)              userSetupRepository.setUserSetup(true)              disableFlagsRepository.disableFlags.value =                  DisableFlagsModel( @@ -259,7 +229,7 @@ class ShadeInteractorTest : SysuiTestCase() {      @Test      fun isExpandToQsEnabled_userSetup_true() =          testScope.runTest { -            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) +            deviceProvisioningRepository.setDeviceProvisioned(true)              keyguardRepository.setIsDozing(false)              disableFlagsRepository.disableFlags.value =                  DisableFlagsModel( @@ -276,7 +246,7 @@ class ShadeInteractorTest : SysuiTestCase() {      @Test      fun isExpandToQsEnabled_notSimpleUserSwitcher_true() =          testScope.runTest { -            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) +            deviceProvisioningRepository.setDeviceProvisioned(true)              keyguardRepository.setIsDozing(false)              disableFlagsRepository.disableFlags.value =                  DisableFlagsModel( @@ -293,7 +263,7 @@ class ShadeInteractorTest : SysuiTestCase() {      @Test      fun isExpandToQsEnabled_respondsToDozingUpdates() =          testScope.runTest { -            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) +            deviceProvisioningRepository.setDeviceProvisioned(true)              keyguardRepository.setIsDozing(false)              disableFlagsRepository.disableFlags.value =                  DisableFlagsModel( @@ -321,7 +291,7 @@ class ShadeInteractorTest : SysuiTestCase() {      @Test      fun isExpandToQsEnabled_respondsToDisableUpdates() =          testScope.runTest { -            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) +            deviceProvisioningRepository.setDeviceProvisioned(true)              keyguardRepository.setIsDozing(false)              disableFlagsRepository.disableFlags.value =                  DisableFlagsModel( @@ -353,7 +323,7 @@ class ShadeInteractorTest : SysuiTestCase() {      @Test      fun isExpandToQsEnabled_respondsToUserUpdates() =          testScope.runTest { -            whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) +            deviceProvisioningRepository.setDeviceProvisioned(true)              keyguardRepository.setIsDozing(false)              disableFlagsRepository.disableFlags.value =                  DisableFlagsModel( @@ -625,7 +595,8 @@ class ShadeInteractorTest : SysuiTestCase() {                          fromScene = SceneKey.Lockscreen,                          toScene = key,                          progress = progress, -                        isUserInputDriven = false, +                        isInitiatedByUserInput = false, +                        isUserInputOngoing = flowOf(false),                      )                  )              sceneInteractor.setTransitionState(transitionState) @@ -662,7 +633,8 @@ class ShadeInteractorTest : SysuiTestCase() {                          fromScene = key,                          toScene = SceneKey.Lockscreen,                          progress = progress, -                        isUserInputDriven = false, +                        isInitiatedByUserInput = false, +                        isUserInputOngoing = flowOf(false),                      )                  )              sceneInteractor.setTransitionState(transitionState) @@ -698,7 +670,8 @@ class ShadeInteractorTest : SysuiTestCase() {                          fromScene = SceneKey.Lockscreen,                          toScene = SceneKey.Shade,                          progress = progress, -                        isUserInputDriven = false, +                        isInitiatedByUserInput = false, +                        isUserInputOngoing = flowOf(false),                      )                  )              sceneInteractor.setTransitionState(transitionState) @@ -974,7 +947,8 @@ class ShadeInteractorTest : SysuiTestCase() {                          fromScene = SceneKey.Lockscreen,                          toScene = key,                          progress = progress, -                        isUserInputDriven = false, +                        isInitiatedByUserInput = false, +                        isUserInputOngoing = flowOf(false),                      )                  )              sceneInteractor.setTransitionState(transitionState) @@ -1011,7 +985,8 @@ class ShadeInteractorTest : SysuiTestCase() {                          fromScene = SceneKey.Lockscreen,                          toScene = key,                          progress = progress, -                        isUserInputDriven = true, +                        isInitiatedByUserInput = true, +                        isUserInputOngoing = flowOf(false),                      )                  )              sceneInteractor.setTransitionState(transitionState) @@ -1048,7 +1023,8 @@ class ShadeInteractorTest : SysuiTestCase() {                          fromScene = key,                          toScene = SceneKey.Lockscreen,                          progress = progress, -                        isUserInputDriven = false, +                        isInitiatedByUserInput = false, +                        isUserInputOngoing = flowOf(false),                      )                  )              sceneInteractor.setTransitionState(transitionState) @@ -1085,7 +1061,8 @@ class ShadeInteractorTest : SysuiTestCase() {                          fromScene = key,                          toScene = SceneKey.Lockscreen,                          progress = progress, -                        isUserInputDriven = true, +                        isInitiatedByUserInput = true, +                        isUserInputOngoing = flowOf(false),                      )                  )              sceneInteractor.setTransitionState(transitionState) @@ -1120,8 +1097,9 @@ class ShadeInteractorTest : SysuiTestCase() {                      ObservableTransitionState.Transition(                          fromScene = SceneKey.Lockscreen,                          toScene = SceneKey.QuickSettings, -                        progress = progress, -                        isUserInputDriven = true, +                        progress = MutableStateFlow(0f), +                        isInitiatedByUserInput = true, +                        isUserInputOngoing = flowOf(false),                      )                  )              sceneInteractor.setTransitionState(transitionState) @@ -1129,4 +1107,168 @@ class ShadeInteractorTest : SysuiTestCase() {              // THEN interacting is false              assertThat(interacting).isFalse()          } + +    @Test +    fun isShadeTouchable_isFalse_whenFrpIsActive() = +        testScope.runTest { +            deviceProvisioningRepository.setFactoryResetProtectionActive(true) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    transitionState = TransitionState.STARTED, +                ) +            ) +            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable) +            runCurrent() +            assertThat(isShadeTouchable).isFalse() +        } + +    @Test +    fun isShadeTouchable_isFalse_whenDeviceAsleepAndNotPulsing() = +        testScope.runTest { +            powerRepository.updateWakefulness( +                rawState = WakefulnessState.ASLEEP, +                lastWakeReason = WakeSleepReason.POWER_BUTTON, +                lastSleepReason = WakeSleepReason.OTHER, +            ) +            // goingToSleep == false +            // TODO: remove? +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    from = KeyguardState.GONE, +                    to = KeyguardState.LOCKSCREEN, +                    transitionState = TransitionState.STARTED, +                ) +            ) +            keyguardRepository.setDozeTransitionModel( +                DozeTransitionModel( +                    to = DozeStateModel.DOZE_AOD, +                ) +            ) +            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable) +            runCurrent() +            assertThat(isShadeTouchable).isFalse() +        } + +    @Test +    fun isShadeTouchable_isTrue_whenDeviceAsleepAndPulsing() = +        testScope.runTest { +            powerRepository.updateWakefulness( +                rawState = WakefulnessState.ASLEEP, +                lastWakeReason = WakeSleepReason.POWER_BUTTON, +                lastSleepReason = WakeSleepReason.OTHER, +            ) +            // goingToSleep == false +            // TODO: remove? +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    from = KeyguardState.GONE, +                    to = KeyguardState.LOCKSCREEN, +                    transitionState = TransitionState.STARTED, +                ) +            ) +            keyguardRepository.setDozeTransitionModel( +                DozeTransitionModel( +                    to = DozeStateModel.DOZE_PULSING, +                ) +            ) +            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable) +            runCurrent() +            assertThat(isShadeTouchable).isTrue() +        } + +    @Test +    fun isShadeTouchable_isFalse_whenStartingToSleepAndNotControlScreenOff() = +        testScope.runTest { +            powerRepository.updateWakefulness( +                rawState = WakefulnessState.STARTING_TO_SLEEP, +                lastWakeReason = WakeSleepReason.POWER_BUTTON, +                lastSleepReason = WakeSleepReason.OTHER, +            ) +            // goingToSleep == true +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    from = KeyguardState.GONE, +                    to = KeyguardState.AOD, +                    transitionState = TransitionState.STARTED, +                ) +            ) +            whenever(dozeParameters.shouldControlScreenOff()).thenReturn(false) +            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable) +            runCurrent() +            assertThat(isShadeTouchable).isFalse() +        } + +    @Test +    fun isShadeTouchable_isTrue_whenStartingToSleepAndControlScreenOff() = +        testScope.runTest { +            powerRepository.updateWakefulness( +                rawState = WakefulnessState.STARTING_TO_SLEEP, +                lastWakeReason = WakeSleepReason.POWER_BUTTON, +                lastSleepReason = WakeSleepReason.OTHER, +            ) +            // goingToSleep == true +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    from = KeyguardState.GONE, +                    to = KeyguardState.AOD, +                    transitionState = TransitionState.STARTED, +                ) +            ) +            whenever(dozeParameters.shouldControlScreenOff()).thenReturn(true) +            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable) +            runCurrent() +            assertThat(isShadeTouchable).isTrue() +        } + +    @Test +    fun isShadeTouchable_isTrue_whenNotAsleep() = +        testScope.runTest { +            powerRepository.updateWakefulness( +                rawState = WakefulnessState.AWAKE, +                lastWakeReason = WakeSleepReason.POWER_BUTTON, +                lastSleepReason = WakeSleepReason.OTHER, +            ) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    transitionState = TransitionState.STARTED, +                ) +            ) +            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable) +            runCurrent() +            assertThat(isShadeTouchable).isTrue() +        } + +    @SysUISingleton +    @Component( +        modules = +            [ +                SysUITestModule::class, +                UserDomainLayerModule::class, +            ] +    ) +    interface TestComponent { + +        val underTest: ShadeInteractor + +        val configurationRepository: FakeConfigurationRepository +        val deviceProvisioningRepository: FakeDeviceProvisioningRepository +        val disableFlagsRepository: FakeDisableFlagsRepository +        val keyguardRepository: FakeKeyguardRepository +        val keygaurdTransitionRepository: FakeKeyguardTransitionRepository +        val powerRepository: FakePowerRepository +        val sceneInteractor: SceneInteractor +        val shadeRepository: FakeShadeRepository +        val testScope: TestScope +        val userRepository: FakeUserRepository +        val userSetupRepository: FakeUserSetupRepository + +        @Component.Factory +        interface Factory { +            fun create( +                @BindsInstance test: SysuiTestCase, +                featureFlags: FakeFeatureFlagsClassicModule, +                mocks: TestMocksModule, +            ): TestComponent +        } +    }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt index 7463e65d1d6f..6eeafefd0ac1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.shade.data.repository  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.shade.ShadeExpansionChangeEvent  import com.android.systemui.shade.ShadeExpansionStateManager @@ -43,7 +42,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class ShadeRepositoryImplTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt index 0925858d740d..bb20d94e7d39 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt @@ -1,5 +1,6 @@  package com.android.systemui.shade.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue @@ -16,15 +17,15 @@ import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnec  import com.android.systemui.util.mockito.mock  import com.google.common.truth.Truth.assertThat  import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flowOf  import kotlinx.coroutines.test.runTest  import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  import org.mockito.MockitoAnnotations  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class ShadeHeaderViewModelTest : SysuiTestCase() {      private val utils = SceneTestUtils(this)      private val testScope = utils.testScope @@ -84,7 +85,8 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {                          fromScene = SceneKey.Shade,                          toScene = SceneKey.QuickSettings,                          progress = MutableStateFlow(0.5f), -                        isUserInputDriven = false, +                        isInitiatedByUserInput = false, +                        isUserInputOngoing = flowOf(false),                      )                  )              ) @@ -102,7 +104,8 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {                          fromScene = SceneKey.QuickSettings,                          toScene = SceneKey.Shade,                          progress = MutableStateFlow(0.5f), -                        isUserInputDriven = false, +                        isInitiatedByUserInput = false, +                        isUserInputOngoing = flowOf(false),                      )                  )              ) @@ -120,7 +123,8 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {                          fromScene = SceneKey.Gone,                          toScene = SceneKey.Shade,                          progress = MutableStateFlow(0.5f), -                        isUserInputDriven = false, +                        isInitiatedByUserInput = false, +                        isUserInputOngoing = flowOf(false),                      )                  )              ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt index 602bd5fded3d..c4237827c3ea 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt @@ -16,6 +16,7 @@  package com.android.systemui.shade.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.authentication.data.model.AuthenticationMethodModel @@ -37,11 +38,10 @@ import kotlinx.coroutines.test.runTest  import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class ShadeSceneViewModelTest : SysuiTestCase() {      private val utils = SceneTestUtils(this) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt index e71473681211..ae659f4d2676 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt @@ -131,11 +131,10 @@ class ClockRegistryTest : SysuiTestCase() {          fun addClock(              id: ClockId, -            name: String,              create: (ClockId) -> ClockController = ::failFactory,              getThumbnail: (ClockId) -> Drawable? = ::failThumbnail          ): FakeClockPlugin { -            metadata.add(ClockMetadata(id, name)) +            metadata.add(ClockMetadata(id))              createCallbacks[id] = create              thumbnailCallbacks[id] = getThumbnail              return this @@ -149,7 +148,7 @@ class ClockRegistryTest : SysuiTestCase() {          scope = TestScope(dispatcher)          fakeDefaultProvider = FakeClockPlugin() -            .addClock(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME, { mockDefaultClock }, { mockThumbnail }) +            .addClock(DEFAULT_CLOCK_ID, { mockDefaultClock }, { mockThumbnail })          whenever(mockContext.contentResolver).thenReturn(mockContentResolver)          val captor = argumentCaptor<PluginListener<ClockProviderPlugin>>() @@ -183,13 +182,13 @@ class ClockRegistryTest : SysuiTestCase() {      @Test      fun pluginRegistration_CorrectState() {          val plugin1 = FakeClockPlugin() -            .addClock("clock_1", "clock 1") -            .addClock("clock_2", "clock 2") +            .addClock("clock_1") +            .addClock("clock_2")          val lifecycle1 = FakeLifecycle("1", plugin1)          val plugin2 = FakeClockPlugin() -            .addClock("clock_3", "clock 3") -            .addClock("clock_4", "clock 4") +            .addClock("clock_3") +            .addClock("clock_4")          val lifecycle2 = FakeLifecycle("2", plugin2)          pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1) @@ -198,11 +197,11 @@ class ClockRegistryTest : SysuiTestCase() {          assertEquals(              list.toSet(),              setOf( -                ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME), -                ClockMetadata("clock_1", "clock 1"), -                ClockMetadata("clock_2", "clock 2"), -                ClockMetadata("clock_3", "clock 3"), -                ClockMetadata("clock_4", "clock 4") +                ClockMetadata(DEFAULT_CLOCK_ID), +                ClockMetadata("clock_1"), +                ClockMetadata("clock_2"), +                ClockMetadata("clock_3"), +                ClockMetadata("clock_4")              )          )      } @@ -216,13 +215,13 @@ class ClockRegistryTest : SysuiTestCase() {      @Test      fun clockIdConflict_ErrorWithoutCrash_unloadDuplicate() {          val plugin1 = FakeClockPlugin() -            .addClock("clock_1", "clock 1", { mockClock }, { mockThumbnail }) -            .addClock("clock_2", "clock 2", { mockClock }, { mockThumbnail }) +            .addClock("clock_1", { mockClock }, { mockThumbnail }) +            .addClock("clock_2", { mockClock }, { mockThumbnail })          val lifecycle1 = spy(FakeLifecycle("1", plugin1))          val plugin2 = FakeClockPlugin() -            .addClock("clock_1", "clock 1") -            .addClock("clock_2", "clock 2") +            .addClock("clock_1") +            .addClock("clock_2")          val lifecycle2 = spy(FakeLifecycle("2", plugin2))          pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1) @@ -231,9 +230,9 @@ class ClockRegistryTest : SysuiTestCase() {          assertEquals(              list.toSet(),              setOf( -                ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME), -                ClockMetadata("clock_1", "clock 1"), -                ClockMetadata("clock_2", "clock 2") +                ClockMetadata(DEFAULT_CLOCK_ID), +                ClockMetadata("clock_1"), +                ClockMetadata("clock_2")              )          ) @@ -248,13 +247,13 @@ class ClockRegistryTest : SysuiTestCase() {      @Test      fun createCurrentClock_pluginConnected() {          val plugin1 = FakeClockPlugin() -            .addClock("clock_1", "clock 1") -            .addClock("clock_2", "clock 2") +            .addClock("clock_1") +            .addClock("clock_2")          val lifecycle1 = spy(FakeLifecycle("1", plugin1))          val plugin2 = FakeClockPlugin() -            .addClock("clock_3", "clock 3", { mockClock }) -            .addClock("clock_4", "clock 4") +            .addClock("clock_3", { mockClock }) +            .addClock("clock_4")          val lifecycle2 = spy(FakeLifecycle("2", plugin2))          registry.applySettings(ClockSettings("clock_3", null)) @@ -268,13 +267,13 @@ class ClockRegistryTest : SysuiTestCase() {      @Test      fun activeClockId_changeAfterPluginConnected() {          val plugin1 = FakeClockPlugin() -            .addClock("clock_1", "clock 1") -            .addClock("clock_2", "clock 2") +            .addClock("clock_1") +            .addClock("clock_2")          val lifecycle1 = spy(FakeLifecycle("1", plugin1))          val plugin2 = FakeClockPlugin() -            .addClock("clock_3", "clock 3", { mockClock }) -            .addClock("clock_4", "clock 4") +            .addClock("clock_3", { mockClock }) +            .addClock("clock_4")          val lifecycle2 = spy(FakeLifecycle("2", plugin2))          registry.applySettings(ClockSettings("clock_3", null)) @@ -289,13 +288,13 @@ class ClockRegistryTest : SysuiTestCase() {      @Test      fun createDefaultClock_pluginDisconnected() {          val plugin1 = FakeClockPlugin() -            .addClock("clock_1", "clock 1") -            .addClock("clock_2", "clock 2") +            .addClock("clock_1") +            .addClock("clock_2")          val lifecycle1 = spy(FakeLifecycle("1", plugin1))          val plugin2 = FakeClockPlugin() -            .addClock("clock_3", "clock 3") -            .addClock("clock_4", "clock 4") +            .addClock("clock_3") +            .addClock("clock_4")          val lifecycle2 = spy(FakeLifecycle("2", plugin2))          registry.applySettings(ClockSettings("clock_3", null)) @@ -310,13 +309,13 @@ class ClockRegistryTest : SysuiTestCase() {      @Test      fun pluginRemoved_clockAndListChanged() {          val plugin1 = FakeClockPlugin() -            .addClock("clock_1", "clock 1") -            .addClock("clock_2", "clock 2") +            .addClock("clock_1") +            .addClock("clock_2")          val lifecycle1 = spy(FakeLifecycle("1", plugin1))          val plugin2 = FakeClockPlugin() -            .addClock("clock_3", "clock 3", { mockClock }) -            .addClock("clock_4", "clock 4") +            .addClock("clock_3", { mockClock }) +            .addClock("clock_4")          val lifecycle2 = spy(FakeLifecycle("2", plugin2))          var changeCallCount = 0 @@ -415,13 +414,13 @@ class ClockRegistryTest : SysuiTestCase() {      @Test      fun pluginAddRemove_concurrentModification() { -        val plugin1 = FakeClockPlugin().addClock("clock_1", "clock 1") +        val plugin1 = FakeClockPlugin().addClock("clock_1")          val lifecycle1 = FakeLifecycle("1", plugin1) -        val plugin2 = FakeClockPlugin().addClock("clock_2", "clock 2") +        val plugin2 = FakeClockPlugin().addClock("clock_2")          val lifecycle2 = FakeLifecycle("2", plugin2) -        val plugin3 = FakeClockPlugin().addClock("clock_3", "clock 3") +        val plugin3 = FakeClockPlugin().addClock("clock_3")          val lifecycle3 = FakeLifecycle("3", plugin3) -        val plugin4 = FakeClockPlugin().addClock("clock_4", "clock 4") +        val plugin4 = FakeClockPlugin().addClock("clock_4")          val lifecycle4 = FakeLifecycle("4", plugin4)          // Set the current clock to the final clock to load @@ -450,10 +449,10 @@ class ClockRegistryTest : SysuiTestCase() {          // Verify all plugins were correctly loaded into the registry          assertEquals(registry.getClocks().toSet(), setOf( -            ClockMetadata("DEFAULT", "Default Clock"), -            ClockMetadata("clock_2", "clock 2"), -            ClockMetadata("clock_3", "clock 3"), -            ClockMetadata("clock_4", "clock 4") +            ClockMetadata("DEFAULT"), +            ClockMetadata("clock_2"), +            ClockMetadata("clock_3"), +            ClockMetadata("clock_4")          ))      } @@ -527,8 +526,8 @@ class ClockRegistryTest : SysuiTestCase() {          featureFlags.set(TRANSIT_CLOCK, flag)          registry.isTransitClockEnabled = featureFlags.isEnabled(TRANSIT_CLOCK)          val plugin = FakeClockPlugin() -                .addClock("clock_1", "clock 1") -                .addClock("DIGITAL_CLOCK_METRO", "metro clock") +                .addClock("clock_1") +                .addClock("DIGITAL_CLOCK_METRO")          val lifecycle = FakeLifecycle("metro", plugin)          pluginListener.onPluginLoaded(plugin, mockContext, lifecycle) @@ -536,17 +535,17 @@ class ClockRegistryTest : SysuiTestCase() {          if (flag) {              assertEquals(                      setOf( -                            ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME), -                            ClockMetadata("clock_1", "clock 1"), -                            ClockMetadata("DIGITAL_CLOCK_METRO", "metro clock") +                            ClockMetadata(DEFAULT_CLOCK_ID), +                            ClockMetadata("clock_1"), +                            ClockMetadata("DIGITAL_CLOCK_METRO")                      ),                      list.toSet()              )          } else {              assertEquals(                      setOf( -                            ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME), -                            ClockMetadata("clock_1", "clock 1") +                            ClockMetadata(DEFAULT_CLOCK_ID), +                            ClockMetadata("clock_1")                      ),                      list.toSet()              ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/BcSmartspaceConfigProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/BcSmartspaceConfigProviderTest.kt index 7a2d12269885..b8fe2f911b50 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/smartspace/BcSmartspaceConfigProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/BcSmartspaceConfigProviderTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.smartspace  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.flags.FeatureFlags  import com.android.systemui.flags.Flags @@ -33,7 +32,6 @@ import org.mockito.Mock  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class BcSmartspaceConfigProviderTest : SysuiTestCase() {      @Mock private lateinit var featureFlags: FeatureFlags diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt index f1c181fb2235..e09385934991 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt @@ -26,7 +26,6 @@ import android.view.ViewGroup  import android.widget.FrameLayout  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.dreams.smartspace.DreamSmartspaceController  import com.android.systemui.plugins.BcSmartspaceConfigPlugin @@ -53,7 +52,6 @@ import org.mockito.MockitoAnnotations  import org.mockito.Spy  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @TestableLooper.RunWithLooper  class DreamSmartspaceControllerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt index 7af29ba28df1..886c61ae29dd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt @@ -25,7 +25,6 @@ import android.provider.Settings  import android.testing.TestableLooper  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.settings.UserTracker  import com.android.systemui.smartspace.filters.LockscreenAndDreamTargetFilter @@ -52,7 +51,6 @@ import org.mockito.MockitoAnnotations  @SmallTest  @TestableLooper.RunWithLooper -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class LockscreenAndDreamTargetFilterTest : SysuiTestCase() {      @Mock diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt index a7c223dc4b8a..0b5aea7d8683 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.smartspace  import android.testing.TestableLooper  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.smartspace.preconditions.LockscreenPrecondition  import com.android.systemui.statusbar.policy.DeviceProvisionedController @@ -36,7 +35,6 @@ import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  @TestableLooper.RunWithLooper  class LockscreenPreconditionTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt index 14e58e5f570a..e8923a5baca8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt @@ -5,41 +5,32 @@ import android.testing.AndroidTestingRunner  import android.testing.TestableLooper  import android.testing.TestableLooper.RunWithLooper  import androidx.test.filters.SmallTest +import com.android.SysUITestModule +import com.android.TestMocksModule  import com.android.systemui.ExpandHelper -import com.android.systemui.res.R  import com.android.systemui.SysuiTestCase -import com.android.systemui.classifier.FalsingCollector -import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository -import com.android.systemui.dump.DumpManager -import com.android.systemui.keyguard.WakefulnessLifecycle -import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.flags.FakeFeatureFlagsClassicModule +import com.android.systemui.flags.Flags  import com.android.systemui.media.controls.ui.MediaHierarchyManager -import com.android.systemui.plugins.ActivityStarter -import com.android.systemui.plugins.FalsingManager  import com.android.systemui.plugins.qs.QS -import com.android.systemui.power.domain.interactor.PowerInteractorFactory -import com.android.systemui.scene.SceneTestUtils -import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags +import com.android.systemui.res.R  import com.android.systemui.shade.ShadeViewController -import com.android.systemui.shade.data.repository.FakeShadeRepository -import com.android.systemui.shade.domain.interactor.ShadeInteractor  import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel  import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository  import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow  import com.android.systemui.statusbar.notification.row.NotificationTestHelper -import com.android.systemui.statusbar.notification.stack.AmbientState  import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout  import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController -import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor  import com.android.systemui.statusbar.phone.CentralSurfaces  import com.android.systemui.statusbar.phone.KeyguardBypassController -import com.android.systemui.statusbar.phone.LSShadeTransitionLogger  import com.android.systemui.statusbar.phone.ScrimController -import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository  import com.android.systemui.statusbar.policy.FakeConfigurationController -import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController -import com.android.systemui.util.mockito.mock +import com.android.systemui.user.domain.UserDomainLayerModule +import dagger.BindsInstance +import dagger.Component  import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope  import kotlinx.coroutines.test.runCurrent  import org.junit.After  import org.junit.Assert.assertFalse @@ -60,9 +51,8 @@ import org.mockito.Mockito  import org.mockito.Mockito.clearInvocations  import org.mockito.Mockito.never  import org.mockito.Mockito.verify -import org.mockito.Mockito.verifyZeroInteractions -import org.mockito.junit.MockitoJUnit  import org.mockito.Mockito.`when` as whenever +import org.mockito.junit.MockitoJUnit  private fun <T> anyObject(): T {      return Mockito.anyObject<T>() @@ -73,68 +63,38 @@ private fun <T> anyObject(): T {  @RunWith(AndroidTestingRunner::class)  @OptIn(ExperimentalCoroutinesApi::class)  class LockscreenShadeTransitionControllerTest : SysuiTestCase() { -    private val utils = SceneTestUtils(this) -    private val testScope = utils.testScope -    lateinit var transitionController: LockscreenShadeTransitionController +    private lateinit var testComponent: TestComponent + +    private val transitionController +        get() = testComponent.transitionController +    private val configurationController +        get() = testComponent.configurationController +    private val disableFlagsRepository +        get() = testComponent.disableFlagsRepository +    private val testScope +        get() = testComponent.testScope +      lateinit var row: ExpandableNotificationRow -    @Mock lateinit var statusbarStateController: SysuiStatusBarStateController -    @Mock lateinit var logger: LSShadeTransitionLogger -    @Mock lateinit var dumpManager: DumpManager + +    @Mock lateinit var centralSurfaces: CentralSurfaces +    @Mock lateinit var depthController: NotificationShadeDepthController +    @Mock lateinit var expandHelperCallback: ExpandHelper.Callback      @Mock lateinit var keyguardBypassController: KeyguardBypassController      @Mock lateinit var lockScreenUserManager: NotificationLockscreenUserManager -    @Mock lateinit var falsingCollector: FalsingCollector -    @Mock lateinit var ambientState: AmbientState -    @Mock lateinit var wakefulnessLifecycle: WakefulnessLifecycle      @Mock lateinit var mediaHierarchyManager: MediaHierarchyManager +    @Mock lateinit var nsslController: NotificationStackScrollLayoutController +    @Mock lateinit var qS: QS      @Mock lateinit var scrimController: ScrimController -    @Mock lateinit var falsingManager: FalsingManager      @Mock lateinit var shadeViewController: ShadeViewController -    @Mock lateinit var nsslController: NotificationStackScrollLayoutController -    @Mock lateinit var depthController: NotificationShadeDepthController      @Mock lateinit var stackscroller: NotificationStackScrollLayout -    @Mock lateinit var expandHelperCallback: ExpandHelper.Callback -    @Mock lateinit var mCentralSurfaces: CentralSurfaces -    @Mock lateinit var qS: QS -    @Mock lateinit var singleShadeOverScroller: SingleShadeLockScreenOverScroller -    @Mock lateinit var splitShadeOverScroller: SplitShadeLockScreenOverScroller -    @Mock lateinit var qsTransitionController: LockscreenShadeQsTransitionController -    @Mock lateinit var activityStarter: ActivityStarter +    @Mock lateinit var statusbarStateController: SysuiStatusBarStateController      @Mock lateinit var transitionControllerCallback: LockscreenShadeTransitionController.Callback -    private val sceneContainerFlags = FakeSceneContainerFlags() -    private val sceneInteractor = utils.sceneInteractor() -    private val disableFlagsRepository = FakeDisableFlagsRepository() -    private val keyguardRepository = FakeKeyguardRepository() -    private val configurationRepository = FakeConfigurationRepository() -    private val sharedNotificationContainerInteractor = SharedNotificationContainerInteractor( -        configurationRepository, -        mContext, -            ResourcesSplitShadeStateController() -    ) -    private val shadeInteractor = -        ShadeInteractor( -            testScope.backgroundScope, -            disableFlagsRepository, -            sceneContainerFlags, -            { sceneInteractor }, -            keyguardRepository, -            userSetupRepository = FakeUserSetupRepository(), -            deviceProvisionedController = mock(), -            userInteractor = mock(), -            sharedNotificationContainerInteractor, -            repository = FakeShadeRepository(), -        ) -    private val powerInteractor = PowerInteractorFactory.create().powerInteractor -    @JvmField @Rule val mockito = MockitoJUnit.rule() -    private val configurationController = FakeConfigurationController() +    @JvmField @Rule val mockito = MockitoJUnit.rule()      @Before      fun setup() { -        // By default, have the shade enabled -        disableFlagsRepository.disableFlags.value = DisableFlagsModel() -        testScope.runCurrent() -          val helper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))          row = helper.createRow()          context @@ -143,55 +103,9 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {          context              .getOrCreateTestableResources()              .addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 100) -        transitionController = -            LockscreenShadeTransitionController( -                statusBarStateController = statusbarStateController, -                logger = logger, -                keyguardBypassController = keyguardBypassController, -                lockScreenUserManager = lockScreenUserManager, -                falsingCollector = falsingCollector, -                ambientState = ambientState, -                mediaHierarchyManager = mediaHierarchyManager, -                depthController = depthController, -                wakefulnessLifecycle = wakefulnessLifecycle, -                context = context, -                configurationController = configurationController, -                falsingManager = falsingManager, -                dumpManager = dumpManager, -                splitShadeOverScrollerFactory = { _, _ -> splitShadeOverScroller }, -                singleShadeOverScrollerFactory = { singleShadeOverScroller }, -                scrimTransitionController = -                    LockscreenShadeScrimTransitionController( -                        scrimController, -                        context, -                        configurationController, -                        dumpManager, -                            ResourcesSplitShadeStateController() -                    ), -                keyguardTransitionControllerFactory = { notificationPanelController -> -                    LockscreenShadeKeyguardTransitionController( -                        mediaHierarchyManager, -                        notificationPanelController, -                        context, -                        configurationController, -                        dumpManager, -                            ResourcesSplitShadeStateController() -                    ) -                }, -                qsTransitionControllerFactory = { qsTransitionController }, -                activityStarter = activityStarter, -                shadeRepository = FakeShadeRepository(), -                shadeInteractor = shadeInteractor, -                powerInteractor = powerInteractor, -                splitShadeStateController = ResourcesSplitShadeStateController() -            ) -        transitionController.addCallback(transitionControllerCallback) +          whenever(nsslController.view).thenReturn(stackscroller)          whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback) -        transitionController.shadeViewController = shadeViewController -        transitionController.centralSurfaces = mCentralSurfaces -        transitionController.qS = qS -        transitionController.setStackScroller(nsslController)          whenever(statusbarStateController.state).thenReturn(StatusBarState.KEYGUARD)          whenever(nsslController.isInLockedDownShade).thenReturn(false)          whenever(qS.isFullyCollapsed).thenReturn(true) @@ -199,9 +113,36 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {              .thenReturn(true)          whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true)          whenever(lockScreenUserManager.isLockscreenPublicMode(anyInt())).thenReturn(true) -        whenever(falsingCollector.shouldEnforceBouncer()).thenReturn(false)          whenever(keyguardBypassController.bypassEnabled).thenReturn(false) -        clearInvocations(mCentralSurfaces) + +        testComponent = +            DaggerLockscreenShadeTransitionControllerTest_TestComponent.factory() +                .create( +                    test = this, +                    featureFlags = +                        FakeFeatureFlagsClassicModule { +                            set(Flags.FULL_SCREEN_USER_SWITCHER, false) +                        }, +                    mocks = +                        TestMocksModule( +                            notificationShadeDepthController = depthController, +                            keyguardBypassController = keyguardBypassController, +                            mediaHierarchyManager = mediaHierarchyManager, +                            notificationLockscreenUserManager = lockScreenUserManager, +                            notificationStackScrollLayoutController = nsslController, +                            scrimController = scrimController, +                            statusBarStateController = statusbarStateController, +                        ) +                ) + +        transitionController.addCallback(transitionControllerCallback) +        transitionController.shadeViewController = shadeViewController +        transitionController.centralSurfaces = centralSurfaces +        transitionController.qS = qS +        transitionController.setStackScroller(nsslController) +        clearInvocations(centralSurfaces) + +        testScope.runCurrent()      }      @After @@ -282,7 +223,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {          transitionController.goToLockedShade(null)          verify(statusbarStateController, never()).setState(anyInt())          verify(statusbarStateController).setLeaveOpenOnKeyguardHide(true) -        verify(mCentralSurfaces).showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject()) +        verify(centralSurfaces).showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject())      }      @Test @@ -318,7 +259,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {          verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat())          verify(transitionControllerCallback, never())              .setTransitionToFullShadeAmount(anyFloat(), anyBoolean(), anyLong()) -        verify(qsTransitionController, never()).dragDownAmount = anyFloat() +        verify(qS, never()).setTransitionToFullShadeProgress(anyBoolean(), anyFloat(), anyFloat())      }      @Test @@ -329,7 +270,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {          verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat())          verify(transitionControllerCallback)              .setTransitionToFullShadeAmount(anyFloat(), anyBoolean(), anyLong()) -        verify(qsTransitionController).dragDownAmount = 10f +        verify(qS).setTransitionToFullShadeProgress(eq(true), anyFloat(), anyFloat())          verify(depthController).transitionToFullShadeProgress = anyFloat()      } @@ -532,8 +473,8 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {          transitionController.dragDownAmount = 10f -        verify(singleShadeOverScroller).expansionDragDownAmount = 10f -        verifyZeroInteractions(splitShadeOverScroller) +        verify(nsslController).setOverScrollAmount(0) +        verify(scrimController, never()).setNotificationsOverScrollAmount(anyInt())      }      @Test @@ -542,8 +483,8 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {          transitionController.dragDownAmount = 10f -        verify(splitShadeOverScroller).expansionDragDownAmount = 10f -        verifyZeroInteractions(singleShadeOverScroller) +        verify(nsslController).setOverScrollAmount(0) +        verify(scrimController).setNotificationsOverScrollAmount(0)      }      @Test @@ -591,6 +532,32 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {          progress: Float,          lockScreenNotificationsProgress: Float      ) { -        scrimController.setTransitionToFullShadeProgress(progress, lockScreenNotificationsProgress) +        setTransitionToFullShadeProgress(progress, lockScreenNotificationsProgress) +    } + +    @SysUISingleton +    @Component( +        modules = +            [ +                SysUITestModule::class, +                UserDomainLayerModule::class, +            ] +    ) +    interface TestComponent { + +        val transitionController: LockscreenShadeTransitionController + +        val configurationController: FakeConfigurationController +        val disableFlagsRepository: FakeDisableFlagsRepository +        val testScope: TestScope + +        @Component.Factory +        interface Factory { +            fun create( +                @BindsInstance test: SysuiTestCase, +                featureFlags: FakeFeatureFlagsClassicModule, +                mocks: TestMocksModule, +            ): TestComponent +        }      }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt index fbb8ebfb3e3b..20e5c43cba19 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt @@ -29,9 +29,9 @@ import com.android.systemui.shade.ShadeExpansionStateManager  import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator  import com.android.systemui.statusbar.notification.row.ExpandableView  import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone  import com.android.systemui.statusbar.phone.KeyguardBypassController  import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.policy.HeadsUpManager  import com.android.systemui.util.mockito.mock  import org.junit.Before  import org.junit.Test @@ -52,7 +52,7 @@ class PulseExpansionHandlerTest : SysuiTestCase() {      private val collapsedHeight = 300      private val wakeUpCoordinator: NotificationWakeUpCoordinator = mock()      private val bypassController: KeyguardBypassController = mock() -    private val headsUpManager: HeadsUpManagerPhone = mock() +    private val headsUpManager: HeadsUpManager = mock()      private val roundnessManager: NotificationRoundnessManager = mock()      private val configurationController: ConfigurationController = mock()      private val statusBarStateController: StatusBarStateController = mock() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt index d86f8bbbeb15..235ac5c2e9cc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt @@ -8,15 +8,15 @@ import androidx.test.filters.SmallTest  import com.android.internal.jank.InteractionJankMonitor  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.res.R  import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder  import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder  import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository  import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow  import com.android.systemui.statusbar.notification.row.NotificationTestHelper  import com.android.systemui.statusbar.notification.stack.NotificationListContainer -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone +import com.android.systemui.statusbar.policy.HeadsUpManager  import com.android.systemui.statusbar.policy.HeadsUpUtil -import com.android.systemui.res.R  import junit.framework.Assert.assertFalse  import junit.framework.Assert.assertTrue  import kotlinx.coroutines.test.TestScope @@ -37,7 +37,7 @@ import org.mockito.junit.MockitoJUnit  @RunWithLooper  class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {      @Mock lateinit var notificationListContainer: NotificationListContainer -    @Mock lateinit var headsUpManager: HeadsUpManagerPhone +    @Mock lateinit var headsUpManager: HeadsUpManager      @Mock lateinit var jankMonitor: InteractionJankMonitor      @Mock lateinit var onFinishAnimationCallback: Runnable diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt index 257cc5b1b85c..4f1581cced91 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt @@ -43,8 +43,8 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte  import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper.FullScreenIntentDecisionImpl  import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider  import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback +import com.android.systemui.statusbar.phone.HeadsUpManagerPhone  import com.android.systemui.statusbar.phone.NotificationGroupTestHelper -import com.android.systemui.statusbar.policy.HeadsUpManager  import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener  import com.android.systemui.util.concurrency.FakeExecutor  import com.android.systemui.util.mockito.any @@ -87,7 +87,7 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {      private val notifPipeline: NotifPipeline = mock()      private val logger = HeadsUpCoordinatorLogger(logcatLogBuffer(), verbose = true) -    private val headsUpManager: HeadsUpManager = mock() +    private val headsUpManager: HeadsUpManagerPhone = mock()      private val headsUpViewBinder: HeadsUpViewBinder = mock()      private val visualInterruptionDecisionProvider: VisualInterruptionDecisionProvider = mock()      private val remoteInputManager: NotificationRemoteInputManager = mock() @@ -435,7 +435,7 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {      private fun addHUN(entry: NotificationEntry) {          huns.add(entry) -        whenever(headsUpManager.topEntry).thenReturn(entry) +        whenever(headsUpManager.getTopEntry()).thenReturn(entry)          onHeadsUpChangedListener.onHeadsUpStateChanged(entry, true)          notifLifetimeExtender.cancelLifetimeExtension(entry)      } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt index fbd61f4fe3bd..546abd4ec79a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt @@ -23,7 +23,6 @@ import android.provider.Settings  import android.testing.AndroidTestingRunner  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase -import com.android.systemui.coroutines.advanceTimeBy  import com.android.systemui.dump.DumpManager  import com.android.systemui.dump.logcatLogBuffer  import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository @@ -40,10 +39,10 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga  import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable  import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener  import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider -import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProvider -import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderImpl  import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider  import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow +import com.android.systemui.statusbar.notification.stack.data.repository.NotificationListRepository +import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationListInteractor  import com.android.systemui.statusbar.policy.HeadsUpManager  import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener  import com.android.systemui.util.mockito.any @@ -247,7 +246,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() {              unseenFilter.onCleanup()              // THEN: The SeenNotificationProvider has been updated to reflect the suppression -            assertThat(seenNotificationsProvider.hasFilteredOutSeenNotifications).isTrue() +            assertThat(notificationListInteractor.hasFilteredOutSeenNotifications.value).isTrue()          }      } @@ -598,7 +597,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() {              FakeSettings().apply {                  putInt(Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, 1)              } -        val seenNotificationsProvider = SeenNotificationsProviderImpl() +        val notificationListInteractor = NotificationListInteractor(NotificationListRepository())          val keyguardCoordinator =              KeyguardCoordinator(                  testDispatcher, @@ -611,7 +610,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() {                  testScope.backgroundScope,                  sectionHeaderVisibilityProvider,                  fakeSettings, -                seenNotificationsProvider, +                notificationListInteractor,                  statusBarStateController,              )          keyguardCoordinator.attach(notifPipeline) @@ -619,7 +618,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() {              KeyguardCoordinatorTestScope(                      keyguardCoordinator,                      testScope, -                    seenNotificationsProvider, +                    notificationListInteractor,                      fakeSettings,                  )                  .testBlock() @@ -629,7 +628,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() {      private inner class KeyguardCoordinatorTestScope(          private val keyguardCoordinator: KeyguardCoordinator,          private val scope: TestScope, -        val seenNotificationsProvider: SeenNotificationsProvider, +        val notificationListInteractor: NotificationListInteractor,          private val fakeSettings: FakeSettings,      ) : CoroutineScope by scope {          val testScheduler: TestCoroutineScheduler diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt new file mode 100644 index 000000000000..2f8f3bb14ee5 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.statusbar.notification.data.repository + +import androidx.test.filters.SmallTest +import com.android.SysUITestModule +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator +import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.mockito.withArgCaptor +import com.google.common.truth.Truth.assertThat +import dagger.BindsInstance +import dagger.Component +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.mockito.Mockito.verify + +@SmallTest +class NotificationsKeyguardViewStateRepositoryTest : SysuiTestCase() { + +    private val testComponent: TestComponent = +        DaggerNotificationsKeyguardViewStateRepositoryTest_TestComponent.factory() +            .create(test = this) + +    @Test +    fun areNotifsFullyHidden_reflectsWakeUpCoordinator() = +        with(testComponent) { +            testScope.runTest { +                whenever(mockWakeUpCoordinator.notificationsFullyHidden).thenReturn(false) +                val notifsFullyHidden by collectLastValue(underTest.areNotificationsFullyHidden) +                runCurrent() + +                assertThat(notifsFullyHidden).isFalse() + +                withArgCaptor { verify(mockWakeUpCoordinator).addListener(capture()) } +                    .onFullyHiddenChanged(true) +                runCurrent() + +                assertThat(notifsFullyHidden).isTrue() +            } +        } + +    @Test +    fun isPulseExpanding_reflectsWakeUpCoordinator() = +        with(testComponent) { +            testScope.runTest { +                whenever(mockWakeUpCoordinator.isPulseExpanding()).thenReturn(false) +                val isPulseExpanding by collectLastValue(underTest.isPulseExpanding) +                runCurrent() + +                assertThat(isPulseExpanding).isFalse() + +                withArgCaptor { verify(mockWakeUpCoordinator).addListener(capture()) } +                    .onPulseExpansionChanged(true) +                runCurrent() + +                assertThat(isPulseExpanding).isTrue() +            } +        } + +    @SysUISingleton +    @Component( +        modules = +            [ +                SysUITestModule::class, +            ] +    ) +    interface TestComponent { + +        val underTest: NotificationsKeyguardViewStateRepositoryImpl + +        val mockWakeUpCoordinator: NotificationWakeUpCoordinator +        val testScope: TestScope + +        @Component.Factory +        interface Factory { +            fun create( +                @BindsInstance test: SysuiTestCase, +            ): TestComponent +        } +    } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt new file mode 100644 index 000000000000..705a5a3f9792 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package com.android.systemui.statusbar.notification.domain.interactor + +import androidx.test.filters.SmallTest +import com.android.SysUITestModule +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.data.repository.FakeNotificationsKeyguardViewStateRepository +import com.google.common.truth.Truth.assertThat +import dagger.BindsInstance +import dagger.Component +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test + +@SmallTest +class NotificationsKeyguardInteractorTest : SysuiTestCase() { + +    private val testComponent: TestComponent = +        DaggerNotificationsKeyguardInteractorTest_TestComponent.factory().create(test = this) + +    @Test +    fun areNotifsFullyHidden_reflectsRepository() = +        with(testComponent) { +            testScope.runTest { +                repository.setNotificationsFullyHidden(false) +                val notifsFullyHidden by collectLastValue(underTest.areNotificationsFullyHidden) +                runCurrent() + +                assertThat(notifsFullyHidden).isFalse() + +                repository.setNotificationsFullyHidden(true) +                runCurrent() + +                assertThat(notifsFullyHidden).isTrue() +            } +        } + +    @Test +    fun isPulseExpanding_reflectsRepository() = +        with(testComponent) { +            testScope.runTest { +                repository.setPulseExpanding(false) +                val isPulseExpanding by collectLastValue(underTest.isPulseExpanding) +                runCurrent() + +                assertThat(isPulseExpanding).isFalse() + +                repository.setPulseExpanding(true) +                runCurrent() + +                assertThat(isPulseExpanding).isTrue() +            } +        } + +    @SysUISingleton +    @Component( +        modules = +            [ +                SysUITestModule::class, +            ] +    ) +    interface TestComponent { + +        val underTest: NotificationsKeyguardInteractor + +        val repository: FakeNotificationsKeyguardViewStateRepository +        val testScope: TestScope + +        @Component.Factory +        interface Factory { +            fun create(@BindsInstance test: SysuiTestCase): TestComponent +        } +    } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt index 7caa5ccc5837..e57986ddfa18 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt @@ -26,9 +26,7 @@ import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.flags.FakeFeatureFlagsClassicModule  import com.android.systemui.flags.Flags  import com.android.systemui.statusbar.phone.DozeParameters -import com.android.systemui.statusbar.phone.NotificationIconContainer  import com.android.systemui.user.domain.UserDomainLayerModule -import com.android.systemui.util.mockito.whenever  import dagger.BindsInstance  import dagger.Component  import org.junit.Assert.assertFalse @@ -37,7 +35,6 @@ import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith  import org.mockito.Mock -import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations  @SmallTest @@ -46,7 +43,6 @@ import org.mockito.MockitoAnnotations  class NotificationIconAreaControllerViewBinderWrapperImplTest : SysuiTestCase() {      @Mock private lateinit var dozeParams: DozeParameters -    @Mock private lateinit var aodIcons: NotificationIconContainer      private lateinit var testComponent: TestComponent      private val underTest @@ -85,15 +81,6 @@ class NotificationIconAreaControllerViewBinderWrapperImplTest : SysuiTestCase()          assertTrue(underTest.shouldShowLowPriorityIcons())      } -    @Test -    fun testAppearResetsTranslation() { -        underTest.setupAodIcons(aodIcons) -        whenever(dozeParams.shouldControlScreenOff()).thenReturn(false) -        underTest.appearAodIcons() -        verify(aodIcons).translationY = 0f -        verify(aodIcons).alpha = 1.0f -    } -      @SysUISingleton      @Component(          modules = 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 new file mode 100644 index 000000000000..31efebbc5b60 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt @@ -0,0 +1,493 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.statusbar.notification.icon.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.SysUITestModule +import com.android.TestMocksModule +import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository +import com.android.systemui.flags.FakeFeatureFlagsClassicModule +import com.android.systemui.flags.Flags +import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +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.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.power.data.repository.FakePowerRepository +import com.android.systemui.power.shared.model.WakeSleepReason +import com.android.systemui.power.shared.model.WakefulnessState +import com.android.systemui.statusbar.notification.data.repository.FakeNotificationsKeyguardViewStateRepository +import com.android.systemui.statusbar.phone.DozeParameters +import com.android.systemui.statusbar.phone.ScreenOffAnimationController +import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository +import com.android.systemui.user.domain.UserDomainLayerModule +import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.ui.AnimatedValue +import com.google.common.truth.Truth.assertThat +import dagger.BindsInstance +import dagger.Component +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidJUnit4::class) +class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() { + +    @Mock private lateinit var dozeParams: DozeParameters +    @Mock private lateinit var screenOffAnimController: ScreenOffAnimationController + +    private lateinit var testComponent: TestComponent +    private val underTest: NotificationIconContainerAlwaysOnDisplayViewModel +        get() = testComponent.underTest +    private val deviceEntryRepository: FakeDeviceEntryRepository +        get() = testComponent.deviceEntryRepository +    private val deviceProvisioningRepository: FakeDeviceProvisioningRepository +        get() = testComponent.deviceProvisioningRepository +    private val keyguardRepository: FakeKeyguardRepository +        get() = testComponent.keyguardRepository +    private val keyguardTransitionRepository: FakeKeyguardTransitionRepository +        get() = testComponent.keyguardTransitionRepository +    private val notifsKeyguardRepository: FakeNotificationsKeyguardViewStateRepository +        get() = testComponent.notifsKeyguardRepository +    private val powerRepository: FakePowerRepository +        get() = testComponent.powerRepository +    private val scope: TestScope +        get() = testComponent.scope + +    @Before +    fun setup() { +        MockitoAnnotations.initMocks(this) + +        testComponent = +            DaggerNotificationIconContainerAlwaysOnDisplayViewModelTest_TestComponent.factory() +                .create( +                    test = this, +                    featureFlags = +                        FakeFeatureFlagsClassicModule { +                            setDefault(Flags.FACE_AUTH_REFACTOR) +                            set(Flags.FULL_SCREEN_USER_SWITCHER, value = false) +                            setDefault(Flags.NEW_AOD_TRANSITION) +                        }, +                    mocks = +                        TestMocksModule( +                            dozeParameters = dozeParams, +                            screenOffAnimationController = screenOffAnimController, +                        ), +                ) + +        keyguardRepository.setKeyguardShowing(true) +        keyguardRepository.setKeyguardOccluded(false) +        deviceProvisioningRepository.setFactoryResetProtectionActive(false) +        powerRepository.updateWakefulness( +            rawState = WakefulnessState.AWAKE, +            lastWakeReason = WakeSleepReason.OTHER, +            lastSleepReason = WakeSleepReason.OTHER, +        ) +    } + +    @Test +    fun animationsEnabled_isFalse_whenFrpIsActive() = +        scope.runTest { +            deviceProvisioningRepository.setFactoryResetProtectionActive(true) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    transitionState = TransitionState.STARTED, +                ) +            ) +            val animationsEnabled by collectLastValue(underTest.animationsEnabled) +            runCurrent() +            assertThat(animationsEnabled).isFalse() +        } + +    @Test +    fun animationsEnabled_isFalse_whenDeviceAsleepAndNotPulsing() = +        scope.runTest { +            powerRepository.updateWakefulness( +                rawState = WakefulnessState.ASLEEP, +                lastWakeReason = WakeSleepReason.POWER_BUTTON, +                lastSleepReason = WakeSleepReason.OTHER, +            ) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    transitionState = TransitionState.STARTED, +                ) +            ) +            keyguardRepository.setDozeTransitionModel( +                DozeTransitionModel( +                    to = DozeStateModel.DOZE_AOD, +                ) +            ) +            val animationsEnabled by collectLastValue(underTest.animationsEnabled) +            runCurrent() +            assertThat(animationsEnabled).isFalse() +        } + +    @Test +    fun animationsEnabled_isTrue_whenDeviceAsleepAndPulsing() = +        scope.runTest { +            powerRepository.updateWakefulness( +                rawState = WakefulnessState.ASLEEP, +                lastWakeReason = WakeSleepReason.POWER_BUTTON, +                lastSleepReason = WakeSleepReason.OTHER, +            ) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    transitionState = TransitionState.STARTED, +                ) +            ) +            keyguardRepository.setDozeTransitionModel( +                DozeTransitionModel( +                    to = DozeStateModel.DOZE_PULSING, +                ) +            ) +            val animationsEnabled by collectLastValue(underTest.animationsEnabled) +            runCurrent() +            assertThat(animationsEnabled).isTrue() +        } + +    @Test +    fun animationsEnabled_isFalse_whenStartingToSleepAndNotControlScreenOff() = +        scope.runTest { +            powerRepository.updateWakefulness( +                rawState = WakefulnessState.STARTING_TO_SLEEP, +                lastWakeReason = WakeSleepReason.POWER_BUTTON, +                lastSleepReason = WakeSleepReason.OTHER, +            ) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    from = KeyguardState.GONE, +                    to = KeyguardState.AOD, +                    transitionState = TransitionState.STARTED, +                ) +            ) +            whenever(dozeParams.shouldControlScreenOff()).thenReturn(false) +            val animationsEnabled by collectLastValue(underTest.animationsEnabled) +            runCurrent() +            assertThat(animationsEnabled).isFalse() +        } + +    @Test +    fun animationsEnabled_isTrue_whenStartingToSleepAndControlScreenOff() = +        scope.runTest { +            powerRepository.updateWakefulness( +                rawState = WakefulnessState.STARTING_TO_SLEEP, +                lastWakeReason = WakeSleepReason.POWER_BUTTON, +                lastSleepReason = WakeSleepReason.OTHER, +            ) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    from = KeyguardState.GONE, +                    to = KeyguardState.AOD, +                    transitionState = TransitionState.STARTED, +                ) +            ) +            whenever(dozeParams.shouldControlScreenOff()).thenReturn(true) +            val animationsEnabled by collectLastValue(underTest.animationsEnabled) +            runCurrent() +            assertThat(animationsEnabled).isTrue() +        } + +    @Test +    fun animationsEnabled_isTrue_whenNotAsleep() = +        scope.runTest { +            powerRepository.updateWakefulness( +                rawState = WakefulnessState.AWAKE, +                lastWakeReason = WakeSleepReason.POWER_BUTTON, +                lastSleepReason = WakeSleepReason.OTHER, +            ) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    transitionState = TransitionState.STARTED, +                ) +            ) +            val animationsEnabled by collectLastValue(underTest.animationsEnabled) +            runCurrent() +            assertThat(animationsEnabled).isTrue() +        } + +    @Test +    fun animationsEnabled_isTrue_whenKeyguardIsShowing() = +        scope.runTest { +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    transitionState = TransitionState.STARTED, +                ) +            ) +            val animationsEnabled by collectLastValue(underTest.animationsEnabled) + +            keyguardRepository.setKeyguardShowing(true) +            keyguardRepository.setKeyguardOccluded(false) +            runCurrent() + +            assertThat(animationsEnabled).isTrue() + +            keyguardRepository.setKeyguardOccluded(true) +            runCurrent() + +            assertThat(animationsEnabled).isFalse() + +            keyguardRepository.setKeyguardShowing(false) +            keyguardRepository.setKeyguardOccluded(true) +            runCurrent() + +            assertThat(animationsEnabled).isFalse() +        } + +    @Test +    fun isDozing_startAodTransition() = +        scope.runTest { +            val isDozing by collectLastValue(underTest.isDozing) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    from = KeyguardState.GONE, +                    to = KeyguardState.AOD, +                    transitionState = TransitionState.STARTED, +                ) +            ) +            runCurrent() +            assertThat(isDozing).isEqualTo(AnimatedValue(true, isAnimating = true)) +        } + +    @Test +    fun isDozing_startDozeTransition() = +        scope.runTest { +            val isDozing by collectLastValue(underTest.isDozing) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    from = KeyguardState.GONE, +                    to = KeyguardState.DOZING, +                    transitionState = TransitionState.STARTED, +                ) +            ) +            runCurrent() +            assertThat(isDozing).isEqualTo(AnimatedValue(true, isAnimating = false)) +        } + +    @Test +    fun isDozing_startDozeToAodTransition() = +        scope.runTest { +            val isDozing by collectLastValue(underTest.isDozing) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    from = KeyguardState.DOZING, +                    to = KeyguardState.AOD, +                    transitionState = TransitionState.STARTED, +                ) +            ) +            runCurrent() +            assertThat(isDozing).isEqualTo(AnimatedValue(true, isAnimating = true)) +        } + +    @Test +    fun isNotDozing_startAodToGoneTransition() = +        scope.runTest { +            val isDozing by collectLastValue(underTest.isDozing) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    from = KeyguardState.AOD, +                    to = KeyguardState.GONE, +                    transitionState = TransitionState.STARTED, +                ) +            ) +            runCurrent() +            assertThat(isDozing).isEqualTo(AnimatedValue(false, isAnimating = true)) +        } + +    @Test +    fun isDozing_stopAnimation() = +        scope.runTest { +            val isDozing by collectLastValue(underTest.isDozing) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    from = KeyguardState.AOD, +                    to = KeyguardState.GONE, +                    transitionState = TransitionState.STARTED, +                ) +            ) +            runCurrent() + +            underTest.completeDozeAnimation() +            runCurrent() + +            assertThat(isDozing?.isAnimating).isEqualTo(false) +        } + +    @Test +    fun isNotVisible_pulseExpanding() = +        scope.runTest { +            val isVisible by collectLastValue(underTest.isVisible) +            notifsKeyguardRepository.setPulseExpanding(true) +            runCurrent() + +            assertThat(isVisible?.value).isFalse() +        } + +    @Test +    fun isNotVisible_notOnKeyguard_dontShowAodIconsWhenShade() = +        scope.runTest { +            val isVisible by collectLastValue(underTest.isVisible) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    to = KeyguardState.GONE, +                    transitionState = TransitionState.FINISHED, +                ) +            ) +            whenever(screenOffAnimController.shouldShowAodIconsWhenShade()).thenReturn(false) +            runCurrent() + +            assertThat(isVisible).isEqualTo(AnimatedValue(false, isAnimating = false)) +        } + +    @Test +    fun isVisible_bypassEnabled() = +        scope.runTest { +            val isVisible by collectLastValue(underTest.isVisible) +            deviceEntryRepository.setBypassEnabled(true) +            runCurrent() + +            assertThat(isVisible?.value).isTrue() +        } + +    @Test +    fun isNotVisible_pulseExpanding_notBypassing() = +        scope.runTest { +            val isVisible by collectLastValue(underTest.isVisible) +            notifsKeyguardRepository.setPulseExpanding(true) +            deviceEntryRepository.setBypassEnabled(false) +            runCurrent() + +            assertThat(isVisible?.value).isEqualTo(false) +        } + +    @Test +    fun isVisible_notifsFullyHidden_bypassEnabled() = +        scope.runTest { +            val isVisible by collectLastValue(underTest.isVisible) +            runCurrent() +            notifsKeyguardRepository.setPulseExpanding(false) +            deviceEntryRepository.setBypassEnabled(true) +            notifsKeyguardRepository.setNotificationsFullyHidden(true) +            runCurrent() + +            assertThat(isVisible).isEqualTo(AnimatedValue(true, isAnimating = true)) +        } + +    @Test +    fun isVisible_notifsFullyHidden_bypassDisabled_aodDisabled() = +        scope.runTest { +            val isVisible by collectLastValue(underTest.isVisible) +            notifsKeyguardRepository.setPulseExpanding(false) +            deviceEntryRepository.setBypassEnabled(false) +            whenever(dozeParams.alwaysOn).thenReturn(false) +            notifsKeyguardRepository.setNotificationsFullyHidden(true) +            runCurrent() + +            assertThat(isVisible).isEqualTo(AnimatedValue(true, isAnimating = false)) +        } + +    @Test +    fun isVisible_notifsFullyHidden_bypassDisabled_displayNeedsBlanking() = +        scope.runTest { +            val isVisible by collectLastValue(underTest.isVisible) +            notifsKeyguardRepository.setPulseExpanding(false) +            deviceEntryRepository.setBypassEnabled(false) +            whenever(dozeParams.alwaysOn).thenReturn(true) +            whenever(dozeParams.displayNeedsBlanking).thenReturn(true) +            notifsKeyguardRepository.setNotificationsFullyHidden(true) +            runCurrent() + +            assertThat(isVisible).isEqualTo(AnimatedValue(true, isAnimating = false)) +        } + +    @Test +    fun isVisible_notifsFullyHidden_bypassDisabled() = +        scope.runTest { +            val isVisible by collectLastValue(underTest.isVisible) +            runCurrent() +            notifsKeyguardRepository.setPulseExpanding(false) +            deviceEntryRepository.setBypassEnabled(false) +            whenever(dozeParams.alwaysOn).thenReturn(true) +            whenever(dozeParams.displayNeedsBlanking).thenReturn(false) +            notifsKeyguardRepository.setNotificationsFullyHidden(true) +            runCurrent() + +            assertThat(isVisible).isEqualTo(AnimatedValue(true, isAnimating = true)) +        } + +    @Test +    fun isVisible_stopAnimation() = +        scope.runTest { +            val isVisible by collectLastValue(underTest.isVisible) +            notifsKeyguardRepository.setPulseExpanding(false) +            deviceEntryRepository.setBypassEnabled(false) +            whenever(dozeParams.alwaysOn).thenReturn(true) +            whenever(dozeParams.displayNeedsBlanking).thenReturn(false) +            notifsKeyguardRepository.setNotificationsFullyHidden(true) +            runCurrent() + +            underTest.completeVisibilityAnimation() +            runCurrent() + +            assertThat(isVisible?.isAnimating).isEqualTo(false) +        } + +    @SysUISingleton +    @Component( +        modules = +            [ +                SysUITestModule::class, +                BiometricsDomainLayerModule::class, +                UserDomainLayerModule::class, +            ] +    ) +    interface TestComponent { + +        val underTest: NotificationIconContainerAlwaysOnDisplayViewModel + +        val deviceEntryRepository: FakeDeviceEntryRepository +        val deviceProvisioningRepository: FakeDeviceProvisioningRepository +        val keyguardRepository: FakeKeyguardRepository +        val keyguardTransitionRepository: FakeKeyguardTransitionRepository +        val notifsKeyguardRepository: FakeNotificationsKeyguardViewStateRepository +        val powerRepository: FakePowerRepository +        val scope: TestScope + +        @Component.Factory +        interface Factory { +            fun create( +                @BindsInstance test: SysuiTestCase, +                mocks: TestMocksModule, +                featureFlags: FakeFeatureFlagsClassicModule, +            ): TestComponent +        } +    } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt new file mode 100644 index 000000000000..e1e7f92265f0 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.statusbar.notification.icon.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.SysUITestModule +import com.android.TestMocksModule +import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.flags.FakeFeatureFlagsClassicModule +import com.android.systemui.flags.Flags +import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +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.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.power.data.repository.FakePowerRepository +import com.android.systemui.power.shared.model.WakeSleepReason +import com.android.systemui.power.shared.model.WakefulnessState +import com.android.systemui.statusbar.phone.DozeParameters +import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository +import com.android.systemui.user.domain.UserDomainLayerModule +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import dagger.BindsInstance +import dagger.Component +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidJUnit4::class) +class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() { + +    @Mock lateinit var dozeParams: DozeParameters + +    private lateinit var testComponent: TestComponent +    private val underTest: NotificationIconContainerStatusBarViewModel +        get() = testComponent.underTest +    private val deviceProvisioningRepository +        get() = testComponent.deviceProvisioningRepository +    private val keyguardTransitionRepository +        get() = testComponent.keyguardTransitionRepository +    private val keyguardRepository +        get() = testComponent.keyguardRepository +    private val powerRepository +        get() = testComponent.powerRepository +    private val scope +        get() = testComponent.scope + +    @Before +    fun setup() { +        MockitoAnnotations.initMocks(this) + +        testComponent = +            DaggerNotificationIconContainerStatusBarViewModelTest_TestComponent.factory() +                .create( +                    test = this, +                    // Configurable bindings +                    featureFlags = +                        FakeFeatureFlagsClassicModule { +                            set(Flags.FACE_AUTH_REFACTOR, value = false) +                            set(Flags.FULL_SCREEN_USER_SWITCHER, value = false) +                        }, +                    mocks = +                        TestMocksModule( +                            dozeParameters = dozeParams, +                        ), +                ) + +        keyguardRepository.setKeyguardShowing(false) +        deviceProvisioningRepository.setFactoryResetProtectionActive(false) +        powerRepository.updateWakefulness( +            rawState = WakefulnessState.AWAKE, +            lastWakeReason = WakeSleepReason.OTHER, +            lastSleepReason = WakeSleepReason.OTHER, +        ) +    } + +    @Test +    fun animationsEnabled_isFalse_whenFrpIsActive() = +        scope.runTest { +            deviceProvisioningRepository.setFactoryResetProtectionActive(true) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    transitionState = TransitionState.STARTED, +                ) +            ) +            val animationsEnabled by collectLastValue(underTest.animationsEnabled) +            runCurrent() +            assertThat(animationsEnabled).isFalse() +        } + +    @Test +    fun animationsEnabled_isFalse_whenDeviceAsleepAndNotPulsing() = +        scope.runTest { +            powerRepository.updateWakefulness( +                rawState = WakefulnessState.ASLEEP, +                lastWakeReason = WakeSleepReason.POWER_BUTTON, +                lastSleepReason = WakeSleepReason.OTHER, +            ) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    transitionState = TransitionState.STARTED, +                ) +            ) +            keyguardRepository.setDozeTransitionModel( +                DozeTransitionModel( +                    to = DozeStateModel.DOZE_AOD, +                ) +            ) +            val animationsEnabled by collectLastValue(underTest.animationsEnabled) +            runCurrent() +            assertThat(animationsEnabled).isFalse() +        } + +    @Test +    fun animationsEnabled_isTrue_whenDeviceAsleepAndPulsing() = +        scope.runTest { +            powerRepository.updateWakefulness( +                rawState = WakefulnessState.ASLEEP, +                lastWakeReason = WakeSleepReason.POWER_BUTTON, +                lastSleepReason = WakeSleepReason.OTHER, +            ) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    transitionState = TransitionState.STARTED, +                ) +            ) +            keyguardRepository.setDozeTransitionModel( +                DozeTransitionModel( +                    to = DozeStateModel.DOZE_PULSING, +                ) +            ) +            val animationsEnabled by collectLastValue(underTest.animationsEnabled) +            runCurrent() +            assertThat(animationsEnabled).isTrue() +        } + +    @Test +    fun animationsEnabled_isFalse_whenStartingToSleepAndNotControlScreenOff() = +        scope.runTest { +            powerRepository.updateWakefulness( +                rawState = WakefulnessState.STARTING_TO_SLEEP, +                lastWakeReason = WakeSleepReason.POWER_BUTTON, +                lastSleepReason = WakeSleepReason.OTHER, +            ) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    from = KeyguardState.GONE, +                    to = KeyguardState.AOD, +                    transitionState = TransitionState.STARTED, +                ) +            ) +            whenever(dozeParams.shouldControlScreenOff()).thenReturn(false) +            val animationsEnabled by collectLastValue(underTest.animationsEnabled) +            runCurrent() +            assertThat(animationsEnabled).isFalse() +        } + +    @Test +    fun animationsEnabled_isTrue_whenStartingToSleepAndControlScreenOff() = +        scope.runTest { +            powerRepository.updateWakefulness( +                rawState = WakefulnessState.STARTING_TO_SLEEP, +                lastWakeReason = WakeSleepReason.POWER_BUTTON, +                lastSleepReason = WakeSleepReason.OTHER, +            ) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    from = KeyguardState.GONE, +                    to = KeyguardState.AOD, +                    transitionState = TransitionState.STARTED, +                ) +            ) +            whenever(dozeParams.shouldControlScreenOff()).thenReturn(true) +            val animationsEnabled by collectLastValue(underTest.animationsEnabled) +            runCurrent() +            assertThat(animationsEnabled).isTrue() +        } + +    @Test +    fun animationsEnabled_isTrue_whenNotAsleep() = +        scope.runTest { +            powerRepository.updateWakefulness( +                rawState = WakefulnessState.AWAKE, +                lastWakeReason = WakeSleepReason.POWER_BUTTON, +                lastSleepReason = WakeSleepReason.OTHER, +            ) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    transitionState = TransitionState.STARTED, +                ) +            ) +            val animationsEnabled by collectLastValue(underTest.animationsEnabled) +            runCurrent() +            assertThat(animationsEnabled).isTrue() +        } + +    @Test +    fun animationsEnabled_isTrue_whenKeyguardIsNotShowing() = +        scope.runTest { +            val animationsEnabled by collectLastValue(underTest.animationsEnabled) + +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    transitionState = TransitionState.STARTED, +                ) +            ) +            keyguardRepository.setKeyguardShowing(true) +            runCurrent() + +            assertThat(animationsEnabled).isFalse() + +            keyguardRepository.setKeyguardShowing(false) +            runCurrent() + +            assertThat(animationsEnabled).isTrue() +        } + +    @SysUISingleton +    @Component( +        modules = +            [ +                SysUITestModule::class, +                // Real impls +                BiometricsDomainLayerModule::class, +                UserDomainLayerModule::class, +            ] +    ) +    interface TestComponent { + +        val underTest: NotificationIconContainerStatusBarViewModel + +        val deviceProvisioningRepository: FakeDeviceProvisioningRepository +        val keyguardTransitionRepository: FakeKeyguardTransitionRepository +        val keyguardRepository: FakeKeyguardRepository +        val powerRepository: FakePowerRepository +        val scope: TestScope + +        @Component.Factory +        interface Factory { +            fun create( +                @BindsInstance test: SysuiTestCase, +                mocks: TestMocksModule, +                featureFlags: FakeFeatureFlagsClassicModule, +            ): TestComponent +        } +    } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java index c9b77c5372df..9c20e541e35f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java @@ -54,9 +54,9 @@ import android.widget.ImageView;  import android.widget.TextView;  import com.android.internal.statusbar.IStatusBarService; -import com.android.systemui.res.R;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; +import com.android.systemui.res.R;  import com.android.systemui.statusbar.notification.AssistantFeedbackController;  import com.android.systemui.statusbar.notification.collection.NotificationEntry;  import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; @@ -132,7 +132,8 @@ public class FeedbackInfoTest extends SysuiTestCase {      public void testBindNotification_SetsTextApplicationName() {          when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");          mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), -                mMockNotificationRow, mAssistantFeedbackController); +                mMockNotificationRow, mAssistantFeedbackController, mStatusBarService, +                mNotificationGutsManager);          final TextView textView = mFeedbackInfo.findViewById(R.id.pkg_name);          assertTrue(textView.getText().toString().contains("App Name"));      } @@ -143,7 +144,8 @@ public class FeedbackInfoTest extends SysuiTestCase {          when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class)))                  .thenReturn(iconDrawable);          mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), -                mMockNotificationRow, mAssistantFeedbackController); +                mMockNotificationRow, mAssistantFeedbackController, mStatusBarService, +                mNotificationGutsManager);          final ImageView iconView = mFeedbackInfo.findViewById(R.id.pkg_icon);          assertEquals(iconDrawable, iconView.getDrawable());      } @@ -153,7 +155,7 @@ public class FeedbackInfoTest extends SysuiTestCase {          when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class)))                  .thenReturn(STATUS_SILENCED);          mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow, -                mAssistantFeedbackController); +                mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);          TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);          assertEquals("This notification was automatically demoted to Silent by the system. "                          + "Let the developer know your feedback. Was this correct?", @@ -165,7 +167,7 @@ public class FeedbackInfoTest extends SysuiTestCase {          when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class)))                  .thenReturn(STATUS_PROMOTED);          mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow, -                mAssistantFeedbackController); +                mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);          TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);          assertEquals("This notification was automatically ranked higher in your shade. "                          + "Let the developer know your feedback. Was this correct?", @@ -177,7 +179,7 @@ public class FeedbackInfoTest extends SysuiTestCase {          when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class)))                  .thenReturn(STATUS_ALERTED);          mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow, -                mAssistantFeedbackController); +                mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);          TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);          assertEquals("This notification was automatically promoted to Default by the system. "                          + "Let the developer know your feedback. Was this correct?", @@ -189,7 +191,7 @@ public class FeedbackInfoTest extends SysuiTestCase {          when(mAssistantFeedbackController.getFeedbackStatus(any(NotificationEntry.class)))                  .thenReturn(STATUS_DEMOTED);          mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow, -                mAssistantFeedbackController); +                mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);          TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);          assertEquals("This notification was automatically ranked lower in your shade. "                          + "Let the developer know your feedback. Was this correct?", @@ -199,7 +201,7 @@ public class FeedbackInfoTest extends SysuiTestCase {      @Test      public void testPositiveFeedback() {          mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow, -                mAssistantFeedbackController); +                mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);          final View yes = mFeedbackInfo.findViewById(R.id.yes);          yes.performClick(); @@ -216,7 +218,7 @@ public class FeedbackInfoTest extends SysuiTestCase {                  .thenReturn(true);          mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow, -                mAssistantFeedbackController); +                mAssistantFeedbackController, mStatusBarService, mNotificationGutsManager);          final View no = mFeedbackInfo.findViewById(R.id.no);          no.performClick(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index 9f2afdf1b168..8a730cfd7ddd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -33,7 +33,6 @@ import static org.junit.Assert.fail;  import static org.mockito.ArgumentMatchers.any;  import static org.mockito.ArgumentMatchers.anyBoolean;  import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anySet;  import static org.mockito.ArgumentMatchers.eq;  import static org.mockito.Mockito.doNothing;  import static org.mockito.Mockito.mock; @@ -89,8 +88,8 @@ import com.android.systemui.statusbar.notification.collection.provider.HighPrior  import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;  import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;  import com.android.systemui.statusbar.notification.stack.NotificationListContainer; -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;  import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.util.concurrency.FakeExecutor;  import com.android.systemui.util.kotlin.JavaAdapter;  import com.android.systemui.util.time.FakeSystemClock; @@ -152,7 +151,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {      @Mock private AssistantFeedbackController mAssistantFeedbackController;      @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;      @Mock private StatusBarStateController mStatusBarStateController; -    @Mock private HeadsUpManagerPhone mHeadsUpManagerPhone; +    @Mock private HeadsUpManager mHeadsUpManager;      @Mock private ActivityStarter mActivityStarter;      @Mock private UserManager mUserManager; @@ -171,7 +170,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {                  mTestScope.getBackgroundScope(),                  new WindowRootViewVisibilityRepository(mBarService, mExecutor),                  new FakeKeyguardRepository(), -                mHeadsUpManagerPhone, +                mHeadsUpManager,                  PowerInteractorFactory.create().getPowerInteractor());          mGutsManager = new NotificationGutsManager( @@ -196,9 +195,10 @@ public class NotificationGutsManagerTest extends SysuiTestCase {                  mWindowRootViewVisibilityInteractor,                  mNotificationLockscreenUserManager,                  mStatusBarStateController, +                mBarService,                  mDeviceProvisionedController,                  mMetricsLogger, -                mHeadsUpManagerPhone, +                mHeadsUpManager,                  mActivityStarter);          mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer,                  mOnSettingsClickListener); @@ -239,7 +239,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {                  anyInt(),                  anyBoolean(),                  any(Runnable.class)); -        verify(mHeadsUpManagerPhone).setGutsShown(realRow.getEntry(), true); +        verify(mHeadsUpManager).setGutsShown(realRow.getEntry(), true);          assertEquals(View.VISIBLE, guts.getVisibility());          mGutsManager.closeAndSaveGuts(false, false, true, 0, 0, false); @@ -247,7 +247,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {          verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean());          verify(row, times(1)).setGutsView(any());          mTestableLooper.processAllMessages(); -        verify(mHeadsUpManagerPhone).setGutsShown(realRow.getEntry(), false); +        verify(mHeadsUpManager).setGutsShown(realRow.getEntry(), false);      }      @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java index ac680e6c902e..cb731082b89b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java @@ -61,6 +61,7 @@ import com.android.systemui.flags.Flags;  import com.android.systemui.media.controls.util.MediaFeatureFlag;  import com.android.systemui.media.dialog.MediaOutputDialogFactory;  import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.res.R;  import com.android.systemui.statusbar.NotificationMediaManager;  import com.android.systemui.statusbar.NotificationRemoteInputManager;  import com.android.systemui.statusbar.NotificationShadeWindowController; @@ -81,14 +82,13 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow  import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener;  import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;  import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger; -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;  import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.InflatedSmartReplyState;  import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder;  import com.android.systemui.statusbar.policy.SmartReplyConstants;  import com.android.systemui.statusbar.policy.SmartReplyStateInflater;  import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent; -import com.android.systemui.res.R;  import com.android.systemui.wmshell.BubblesManager;  import com.android.systemui.wmshell.BubblesTestActivity; @@ -123,7 +123,7 @@ public class NotificationTestHelper {      private final GroupMembershipManager mGroupMembershipManager;      private final GroupExpansionManager mGroupExpansionManager;      private ExpandableNotificationRow mRow; -    private final HeadsUpManagerPhone mHeadsUpManager; +    private final HeadsUpManager mHeadsUpManager;      private final NotifBindPipeline mBindPipeline;      private final NotifCollectionListener mBindPipelineEntryListener;      private final RowContentBindStage mBindStage; @@ -161,7 +161,7 @@ public class NotificationTestHelper {          mKeyguardBypassController = mock(KeyguardBypassController.class);          mGroupMembershipManager = mock(GroupMembershipManager.class);          mGroupExpansionManager = mock(GroupExpansionManager.class); -        mHeadsUpManager = mock(HeadsUpManagerPhone.class); +        mHeadsUpManager = mock(HeadsUpManager.class);          mIconManager = new IconManager(                  mock(CommonNotifCollection.class),                  mock(LauncherApps.class), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java index ffe312be8fae..20197e3ed547 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java @@ -77,7 +77,6 @@ import com.android.systemui.statusbar.notification.NotifPipelineFlags;  import com.android.systemui.statusbar.notification.collection.NotifCollection;  import com.android.systemui.statusbar.notification.collection.NotifPipeline;  import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider; -import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderImpl;  import com.android.systemui.statusbar.notification.collection.provider.VisibilityLocationProviderDelegator;  import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;  import com.android.systemui.statusbar.notification.collection.render.NotifStats; @@ -88,13 +87,15 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow  import com.android.systemui.statusbar.notification.row.NotificationGutsManager;  import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController.NotificationPanelEvent;  import com.android.systemui.statusbar.notification.stack.NotificationSwipeHelper.NotificationCallback; +import com.android.systemui.statusbar.notification.stack.data.repository.NotificationListRepository; +import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationListInteractor;  import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel; -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;  import com.android.systemui.statusbar.phone.KeyguardBypassController;  import com.android.systemui.statusbar.phone.NotificationIconAreaController;  import com.android.systemui.statusbar.phone.ScrimController;  import com.android.systemui.statusbar.policy.ConfigurationController;  import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;  import com.android.systemui.statusbar.policy.ZenModeController;  import com.android.systemui.tuner.TunerService; @@ -124,7 +125,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {      @Mock private NotificationGutsManager mNotificationGutsManager;      @Mock private NotificationsController mNotificationsController;      @Mock private NotificationVisibilityProvider mVisibilityProvider; -    @Mock private HeadsUpManagerPhone mHeadsUpManager; +    @Mock private HeadsUpManager mHeadsUpManager;      @Mock private NotificationRoundnessManager mNotificationRoundnessManager;      @Mock private TunerService mTunerService;      @Mock private DeviceProvisionedController mDeviceProvisionedController; @@ -170,8 +171,8 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {      @Captor      private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor; -    private final SeenNotificationsProviderImpl mSeenNotificationsProvider = -            new SeenNotificationsProviderImpl(); +    private final NotificationListInteractor mNotificationListInteractor = +            new NotificationListInteractor(new NotificationListRepository());      private NotificationStackScrollLayoutController mController; @@ -503,7 +504,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {      @Test      public void testSetNotifStats_updatesHasFilteredOutSeenNotifications() {          initController(/* viewIsAttached= */ true); -        mSeenNotificationsProvider.setHasFilteredOutSeenNotifications(true); +        mNotificationListInteractor.setHasFilteredOutSeenNotifications(true);          mController.getNotifStackController().setNotifStats(NotifStats.getEmpty());          verify(mNotificationStackScrollLayout).setHasFilteredOutSeenNotifications(true);          verify(mNotificationStackScrollLayout).updateFooter(); @@ -703,7 +704,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {                  mUiEventLogger,                  mRemoteInputManager,                  mVisibilityLocationProviderDelegator, -                mSeenNotificationsProvider, +                mNotificationListInteractor,                  mShadeController,                  mJankMonitor,                  mStackLogger, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt index e254dd085b2e..ac11ff29b83a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt @@ -19,36 +19,35 @@ package com.android.systemui.statusbar.notification.stack.ui.viewmodel  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.res.R +import com.android.SysUITestModule +import com.android.TestMocksModule  import com.android.systemui.SysuiTestCase  import com.android.systemui.common.shared.model.SharedNotificationContainerPosition  import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository  import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.flags.FakeFeatureFlagsClassicModule +import com.android.systemui.flags.Flags  import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository  import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository  import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory  import com.android.systemui.keyguard.shared.model.KeyguardState  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.scene.SceneTestUtils -import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags +import com.android.systemui.res.R  import com.android.systemui.shade.data.repository.FakeShadeRepository -import com.android.systemui.shade.domain.interactor.ShadeInteractor -import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository  import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController  import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator  import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor -import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository -import com.android.systemui.statusbar.policy.DeviceProvisionedController -import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController -import com.android.systemui.user.domain.interactor.UserInteractor +import com.android.systemui.user.domain.UserDomainLayerModule  import com.android.systemui.util.mockito.any  import com.android.systemui.util.mockito.mock  import com.android.systemui.util.mockito.whenever  import com.google.common.truth.Truth.assertThat +import dagger.BindsInstance +import dagger.Component +import kotlinx.coroutines.test.TestScope  import kotlinx.coroutines.test.runCurrent  import kotlinx.coroutines.test.runTest  import org.junit.Before @@ -60,29 +59,27 @@ import org.mockito.MockitoAnnotations  @SmallTest  @RunWith(AndroidJUnit4::class)  class SharedNotificationContainerViewModelTest : SysuiTestCase() { -    private val utils = SceneTestUtils(this) - -    private val testScope = utils.testScope - -    private val disableFlagsRepository = FakeDisableFlagsRepository() -    private val userSetupRepository = FakeUserSetupRepository() -    private val shadeRepository = FakeShadeRepository() -    private val keyguardRepository = FakeKeyguardRepository() -    private val sceneContainerFlags = FakeSceneContainerFlags() -    private val sceneInteractor = utils.sceneInteractor() - -    private lateinit var configurationRepository: FakeConfigurationRepository -    private lateinit var sharedNotificationContainerInteractor: -        SharedNotificationContainerInteractor -    private lateinit var underTest: SharedNotificationContainerViewModel -    private lateinit var keyguardInteractor: KeyguardInteractor -    private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor -    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository -    private lateinit var shadeInteractor: ShadeInteractor + +    private lateinit var testComponent: TestComponent + +    private val shadeRepository +        get() = testComponent.shadeRepository +    private val keyguardRepository +        get() = testComponent.keyguardRepository +    private val configurationRepository +        get() = testComponent.configurationRepository +    private val sharedNotificationContainerInteractor: SharedNotificationContainerInteractor +        get() = testComponent.sharedNotificationContainerInteractor +    private val underTest: SharedNotificationContainerViewModel +        get() = testComponent.underTest +    private val keyguardInteractor: KeyguardInteractor +        get() = testComponent.keyguardInteractor +    private val keyguardTransitionRepository +        get() = testComponent.keyguardTransitionRepository +    private val testScope +        get() = testComponent.testScope      @Mock private lateinit var notificationStackSizeCalculator: NotificationStackSizeCalculator -    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController -    @Mock private lateinit var userInteractor: UserInteractor      @Mock      private lateinit var notificationStackScrollLayoutController:          NotificationStackScrollLayoutController @@ -94,43 +91,21 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          whenever(notificationStackScrollLayoutController.getView()).thenReturn(mock())          whenever(notificationStackScrollLayoutController.getShelfHeight()).thenReturn(0) -        configurationRepository = FakeConfigurationRepository() -        KeyguardTransitionInteractorFactory.create( -                scope = testScope.backgroundScope, -            ) -            .also { -                keyguardInteractor = it.keyguardInteractor -                keyguardTransitionInteractor = it.keyguardTransitionInteractor -                keyguardTransitionRepository = it.repository -            } -        sharedNotificationContainerInteractor = -            SharedNotificationContainerInteractor( -                configurationRepository, -                mContext, -                ResourcesSplitShadeStateController() -            ) -        shadeInteractor = -            ShadeInteractor( -                testScope.backgroundScope, -                disableFlagsRepository, -                sceneContainerFlags, -                { sceneInteractor }, -                keyguardRepository, -                userSetupRepository, -                deviceProvisionedController, -                userInteractor, -                sharedNotificationContainerInteractor, -                shadeRepository, -            ) -        underTest = -            SharedNotificationContainerViewModel( -                sharedNotificationContainerInteractor, -                keyguardInteractor, -                keyguardTransitionInteractor, -                notificationStackSizeCalculator, -                notificationStackScrollLayoutController, -                shadeInteractor -            ) +        testComponent = +            DaggerSharedNotificationContainerViewModelTest_TestComponent.factory() +                .create( +                    test = this, +                    featureFlags = +                        FakeFeatureFlagsClassicModule { +                            set(Flags.FULL_SCREEN_USER_SWITCHER, true) +                        }, +                    mocks = +                        TestMocksModule( +                            notificationStackSizeCalculator = notificationStackSizeCalculator, +                            notificationStackScrollLayoutController = +                                notificationStackScrollLayoutController, +                        ) +                )      }      @Test @@ -404,4 +379,34 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {              )          )      } + +    @SysUISingleton +    @Component( +        modules = +            [ +                SysUITestModule::class, +                UserDomainLayerModule::class, +            ] +    ) +    interface TestComponent { + +        val underTest: SharedNotificationContainerViewModel + +        val configurationRepository: FakeConfigurationRepository +        val keyguardRepository: FakeKeyguardRepository +        val keyguardInteractor: KeyguardInteractor +        val keyguardTransitionRepository: FakeKeyguardTransitionRepository +        val shadeRepository: FakeShadeRepository +        val sharedNotificationContainerInteractor: SharedNotificationContainerInteractor +        val testScope: TestScope + +        @Component.Factory +        interface Factory { +            fun create( +                @BindsInstance test: SysuiTestCase, +                featureFlags: FakeFeatureFlagsClassicModule, +                mocks: TestMocksModule, +            ): TestComponent +        } +    }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java index a5d348404240..e7dad6a2908f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java @@ -57,6 +57,7 @@ import com.android.systemui.statusbar.VibratorHelper;  import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;  import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;  import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.KeyguardStateController;  import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; @@ -85,7 +86,7 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase {      private final MetricsLogger mMetricsLogger = new FakeMetricsLogger();      @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;      @Mock private KeyguardStateController mKeyguardStateController; -    @Mock private HeadsUpManagerPhone mHeadsUpManager; +    @Mock private HeadsUpManager mHeadsUpManager;      @Mock private WakefulnessLifecycle mWakefulnessLifecycle;      @Mock private DeviceProvisionedController mDeviceProvisionedController;      @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index e33fa22bfc0c..f18af61dd314 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -85,7 +85,6 @@ import com.android.keyguard.KeyguardUpdateMonitor;  import com.android.keyguard.TestScopeProvider;  import com.android.keyguard.ViewMediatorCallback;  import com.android.systemui.InitController; -import com.android.systemui.res.R;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;  import com.android.systemui.animation.ActivityLaunchAnimator; @@ -117,6 +116,7 @@ import com.android.systemui.plugins.PluginDependencyProvider;  import com.android.systemui.plugins.PluginManager;  import com.android.systemui.plugins.statusbar.StatusBarStateController;  import com.android.systemui.power.domain.interactor.PowerInteractor; +import com.android.systemui.res.R;  import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;  import com.android.systemui.settings.UserTracker;  import com.android.systemui.settings.brightness.BrightnessSliderController; @@ -219,7 +219,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {      @Mock private KeyguardIndicationController mKeyguardIndicationController;      @Mock private NotificationStackScrollLayout mStackScroller;      @Mock private NotificationStackScrollLayoutController mStackScrollerController; -    @Mock private HeadsUpManagerPhone mHeadsUpManager; +    @Mock private HeadsUpManager mHeadsUpManager;      @Mock private NotificationPanelViewController mNotificationPanelViewController;      @Mock private ShadeLogger mShadeLogger;      @Mock private NotificationPanelView mNotificationPanelView; @@ -336,6 +336,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {          mFeatureFlags.set(Flags.WM_ENABLE_PREDICTIVE_BACK_SYSUI, false);          // Set default value to avoid IllegalStateException.          mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, false); +        mFeatureFlags.setDefault(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR);          // For the Shade to respond to Back gesture, we must enable the event routing          mFeatureFlags.set(Flags.WM_SHADE_ALLOW_BACK_GESTURE, true);          // For the Shade to animate during the Back gesture, we must enable the animation flag. @@ -343,6 +344,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {          mFeatureFlags.set(Flags.LIGHT_REVEAL_MIGRATION, true);          // Turn AOD on and toggle feature flag for jank fixes          mFeatureFlags.set(Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD, true); +        mFeatureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, false);          when(mDozeParameters.getAlwaysOn()).thenReturn(true);          IThermalService thermalService = mock(IThermalService.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java index ff6f40d539fc..593c587c0f51 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java @@ -53,6 +53,7 @@ import com.android.systemui.statusbar.StatusBarStateControllerImpl;  import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;  import com.android.systemui.statusbar.policy.BatteryController;  import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import org.junit.Before;  import org.junit.Test; @@ -72,7 +73,7 @@ public class DozeServiceHostTest extends SysuiTestCase {      private DozeServiceHost mDozeServiceHost; -    @Mock private HeadsUpManagerPhone mHeadsUpManager; +    @Mock private HeadsUpManager mHeadsUpManager;      @Mock private ScrimController mScrimController;      @Mock private DozeScrimController mDozeScrimController;      @Mock private StatusBarStateControllerImpl mStatusBarStateController; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java index ec6286b66ed2..d84bb728a856 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java @@ -47,6 +47,7 @@ import com.android.systemui.statusbar.notification.row.NotificationTestHelper;  import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;  import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;  import com.android.systemui.statusbar.policy.Clock; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.KeyguardStateController;  import org.junit.Assert; @@ -72,7 +73,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {      private ExpandableNotificationRow mRow;      private NotificationEntry mEntry;      private HeadsUpStatusBarView mHeadsUpStatusBarView; -    private HeadsUpManagerPhone mHeadsUpManager; +    private HeadsUpManager mHeadsUpManager;      private View mOperatorNameView;      private StatusBarStateController mStatusbarStateController;      private PhoneStatusBarTransitions mPhoneStatusBarTransitions; @@ -93,7 +94,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {          mEntry = mRow.getEntry();          mHeadsUpStatusBarView = new HeadsUpStatusBarView(mContext, mock(View.class),                  mock(TextView.class)); -        mHeadsUpManager = mock(HeadsUpManagerPhone.class); +        mHeadsUpManager = mock(HeadsUpManager.class);          mOperatorNameView = new View(mContext);          mStatusbarStateController = mock(StatusBarStateController.class);          mPhoneStatusBarTransitions = mock(PhoneStatusBarTransitions.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java index 1bc522d72213..cda2a74609bd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java @@ -32,8 +32,8 @@ import android.testing.TestableLooper;  import androidx.test.filters.SmallTest;  import com.android.internal.logging.UiEventLogger; -import com.android.systemui.res.R;  import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.res.R;  import com.android.systemui.shade.ShadeExpansionStateManager;  import com.android.systemui.statusbar.AlertingNotificationManager;  import com.android.systemui.statusbar.AlertingNotificationManagerTest; @@ -43,6 +43,7 @@ import com.android.systemui.statusbar.notification.collection.provider.VisualSta  import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;  import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;  import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;  import org.junit.After; @@ -71,7 +72,6 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {      @Mock private AccessibilityManagerWrapper mAccessibilityManagerWrapper;      @Mock private ShadeExpansionStateManager mShadeExpansionStateManager;      @Mock private UiEventLogger mUiEventLogger; -    private boolean mLivesPastNormalTime;      private static final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone {          TestableHeadsUpManagerPhone( @@ -149,7 +149,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {      @Test      public void testSnooze() { -        final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone(); +        final HeadsUpManager hmp = createHeadsUpManagerPhone();          final NotificationEntry entry = createEntry(/* id = */ 0);          hmp.showNotification(entry); @@ -160,7 +160,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {      @Test      public void testSwipedOutNotification() { -        final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone(); +        final HeadsUpManager hmp = createHeadsUpManagerPhone();          final NotificationEntry entry = createEntry(/* id = */ 0);          hmp.showNotification(entry); @@ -176,7 +176,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {      @Test      public void testCanRemoveImmediately_swipedOut() { -        final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone(); +        final HeadsUpManager hmp = createHeadsUpManagerPhone();          final NotificationEntry entry = createEntry(/* id = */ 0);          hmp.showNotification(entry); @@ -189,7 +189,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {      @Ignore("b/141538055")      @Test      public void testCanRemoveImmediately_notTopEntry() { -        final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone(); +        final HeadsUpManager hmp = createHeadsUpManagerPhone();          final NotificationEntry earlierEntry = createEntry(/* id = */ 0);          final NotificationEntry laterEntry = createEntry(/* id = */ 1);          laterEntry.setRow(mRow); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index bac857910329..b36d09df5929 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -18,6 +18,9 @@ package com.android.systemui.statusbar.phone;  import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;  import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE; + +import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher; +  import static org.junit.Assert.assertFalse;  import static org.junit.Assert.assertTrue;  import static org.mockito.ArgumentMatchers.any; @@ -33,7 +36,6 @@ import static org.mockito.Mockito.spy;  import static org.mockito.Mockito.times;  import static org.mockito.Mockito.verify;  import static org.mockito.Mockito.when; -import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;  import android.service.trust.TrustAgentService;  import android.testing.AndroidTestingRunner; @@ -175,6 +177,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {          mFeatureFlags.set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false);          mFeatureFlags.set(Flags.UDFPS_NEW_TOUCH_DETECTION, true);          mFeatureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false); +        mFeatureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, false);          when(mNotificationShadeWindowController.getWindowRootView())                  .thenReturn(mNotificationShadeWindowView); @@ -761,6 +764,30 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {      }      @Test +    public void handleDispatchTouchEvent_alternateBouncerViewFlagEnabled() { +        mStatusBarKeyguardViewManager.addCallback(mCallback); + +        // GIVEN alternate bouncer view flag enabled & the alternate bouncer is visible +        mFeatureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, true); +        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true); + +        // THEN the touch is not acted upon +        verify(mCallback, never()).onTouch(any()); +    } + +    @Test +    public void onInterceptTouch_alternateBouncerViewFlagEnabled() { +        // GIVEN alternate bouncer view flag enabled & the alternate bouncer is visible +        mFeatureFlags.set(Flags.ALTERNATE_BOUNCER_VIEW, true); +        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true); + +        // THEN the touch is not intercepted +        assertFalse(mStatusBarKeyguardViewManager.shouldInterceptTouchEvent( +                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0) +        )); +    } + +    @Test      public void handleDispatchTouchEvent_alternateBouncerNotVisible() {          mStatusBarKeyguardViewManager.addCallback(mCallback); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index 8013e5eef44b..beac995c893b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -92,6 +92,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow  import com.android.systemui.statusbar.notification.row.NotificationTestHelper;  import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;  import com.android.systemui.statusbar.notification.stack.NotificationListContainer; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.KeyguardStateController;  import com.android.systemui.util.concurrency.FakeExecutor;  import com.android.systemui.util.time.FakeSystemClock; @@ -218,7 +219,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {                  mScreenOffAnimationController,                  mStatusBarStateController).getPowerInteractor(); -        HeadsUpManagerPhone headsUpManager = mock(HeadsUpManagerPhone.class); +        HeadsUpManager headsUpManager = mock(HeadsUpManager.class);          NotificationLaunchAnimatorControllerProvider notificationAnimationProvider =                  new NotificationLaunchAnimatorControllerProvider(                          new NotificationExpansionRepository(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java index 233f407813b2..ee4f2089c05c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java @@ -15,6 +15,7 @@  package com.android.systemui.statusbar.phone;  import static android.view.Display.DEFAULT_DISPLAY; +  import static org.junit.Assert.assertFalse;  import static org.junit.Assert.assertTrue;  import static org.mockito.Mockito.mock; @@ -59,6 +60,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager;  import com.android.systemui.statusbar.notification.stack.NotificationListContainer;  import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;  import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; +import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.KeyguardStateController;  import org.junit.Before; @@ -106,7 +108,7 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {                  mContext,                  shadeViewController,                  mock(QuickSettingsController.class), -                mock(HeadsUpManagerPhone.class), +                mock(HeadsUpManager.class),                  notificationShadeWindowView,                  mock(ActivityStarter.class),                  stackScrollLayoutController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt index dbaa29bb3688..d06a6e26b4ce 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt @@ -20,7 +20,6 @@ import android.net.ConnectivityManager  import android.net.wifi.WifiManager  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.demomode.DemoMode  import com.android.systemui.demomode.DemoModeController @@ -53,7 +52,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @Suppress("EXPERIMENTAL_IS_NOT_ENABLED")  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class WifiRepositorySwitcherTest : SysuiTestCase() {      private lateinit var underTest: WifiRepositorySwitcher diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepositoryTest.kt index 206ac1d37074..ce00250467f6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepositoryTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel  import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel @@ -28,7 +27,6 @@ import org.junit.Test  import org.junit.runner.RunWith  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class DisabledWifiRepositoryTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt index c2e75aa85fcb..cf20ba87e8c2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt @@ -35,7 +35,6 @@ import android.net.wifi.WifiManager.UNKNOWN_SSID  import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.log.table.TableLogBuffer @@ -73,7 +72,6 @@ import org.mockito.MockitoAnnotations  @Suppress("EXPERIMENTAL_IS_NOT_ENABLED")  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class WifiRepositoryImplTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt index 1db80651bf9b..7fbbfc77300e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.pipeline.wifi.domain.interactor  import android.net.wifi.WifiManager  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot @@ -43,7 +42,6 @@ import org.junit.runner.RunWith  @OptIn(ExperimentalCoroutinesApi::class)  @Suppress("EXPERIMENTAL_IS_NOT_ENABLED")  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class WifiInteractorImplTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt index 49a2648a7cac..2d1a27f1b133 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.settingslib.AccessibilityContentDescriptions.WIFI_OTHER_DEVICE_CONNECTION -import com.android.systemui.RoboPilotTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription  import com.android.systemui.coroutines.collectLastValue @@ -53,7 +52,6 @@ import org.mockito.Mockito.`when` as whenever  import org.mockito.MockitoAnnotations  @SmallTest -@RoboPilotTest  @RunWith(AndroidJUnit4::class)  class WifiViewModelTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java index 64ebcd9e3abf..4f3f56423eb0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java @@ -41,10 +41,13 @@ import android.app.PendingIntent;  import android.app.Person;  import android.content.Context;  import android.content.Intent; +import android.graphics.Region;  import android.os.Handler;  import android.testing.AndroidTestingRunner;  import android.testing.TestableLooper; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable;  import androidx.test.filters.SmallTest;  import com.android.internal.logging.UiEventLogger; @@ -73,7 +76,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      private final HeadsUpManagerLogger mLogger = spy(new HeadsUpManagerLogger(logcatLogBuffer()));      @Mock private AccessibilityManagerWrapper mAccessibilityMgr; -    private final class TestableHeadsUpManager extends HeadsUpManager { +    private final class TestableHeadsUpManager extends BaseHeadsUpManager {          TestableHeadsUpManager(Context context,                  HeadsUpManagerLogger logger,                  Handler handler, @@ -85,9 +88,78 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {              mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;              mStickyDisplayTime = TEST_STICKY_AUTO_DISMISS_TIME;          } + +        // The following are only implemented by HeadsUpManagerPhone. If you need them, use that. +        @Override +        public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) { +            throw new UnsupportedOperationException(); +        } + +        @Override +        public void addSwipedOutNotification(@NonNull String key) { +            throw new UnsupportedOperationException(); +        } + +        @Override +        public void extendHeadsUp() { +            throw new UnsupportedOperationException(); +        } + +        @Nullable +        @Override +        public Region getTouchableRegion() { +            throw new UnsupportedOperationException(); +        } + +        @Override +        public boolean isHeadsUpGoingAway() { +            throw new UnsupportedOperationException(); +        } + +        @Override +        public void onExpandingFinished() { +            throw new UnsupportedOperationException(); +        } + +        @Override +        public boolean removeNotification(@NonNull String key, boolean releaseImmediately, +                boolean animate) { +            throw new UnsupportedOperationException(); +        } + +        @Override +        public void setAnimationStateHandler(@NonNull AnimationStateHandler handler) { +            throw new UnsupportedOperationException(); +        } + +        @Override +        public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) { +            throw new UnsupportedOperationException(); +        } + +        @Override +        public void setHeadsUpGoingAway(boolean headsUpGoingAway) { +            throw new UnsupportedOperationException(); +        } + +        @Override +        public void setRemoteInputActive(@NonNull NotificationEntry entry, +                boolean remoteInputActive) { +            throw new UnsupportedOperationException(); +        } + +        @Override +        public void setTrackingHeadsUp(boolean tracking) { +            throw new UnsupportedOperationException(); +        } + +        @Override +        public boolean shouldSwallowClick(@NonNull String key) { +            throw new UnsupportedOperationException(); +        }      } -    private HeadsUpManager createHeadsUpManager() { +    private BaseHeadsUpManager createHeadsUpManager() {          return new TestableHeadsUpManager(mContext, mLogger, mTestHandler, mAccessibilityMgr,                  mUiEventLoggerFake);      } @@ -165,9 +237,10 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testHunRemovedLogging() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry notifEntry = createEntry(/* id = */ 0); -        final HeadsUpManager.HeadsUpEntry headsUpEntry = mock(HeadsUpManager.HeadsUpEntry.class); +        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = mock( +                BaseHeadsUpManager.HeadsUpEntry.class);          headsUpEntry.mEntry = notifEntry;          hum.onAlertEntryRemoved(headsUpEntry); @@ -177,35 +250,37 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testShouldHeadsUpBecomePinned_hasFSI_notUnpinned_true() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry notifEntry = createFullScreenIntentEntry(/* id = */ 0);          // Add notifEntry to ANM mAlertEntries map and make it NOT unpinned          hum.showNotification(notifEntry); -        final HeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(notifEntry.getKey()); -        headsUpEntry.wasUnpinned = false; +        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry( +                notifEntry.getKey()); +        headsUpEntry.mWasUnpinned = false;          assertTrue(hum.shouldHeadsUpBecomePinned(notifEntry));      }      @Test      public void testShouldHeadsUpBecomePinned_wasUnpinned_false() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry notifEntry = createFullScreenIntentEntry(/* id = */ 0);          // Add notifEntry to ANM mAlertEntries map and make it unpinned          hum.showNotification(notifEntry); -        final HeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(notifEntry.getKey()); -        headsUpEntry.wasUnpinned = true; +        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry( +                notifEntry.getKey()); +        headsUpEntry.mWasUnpinned = true;          assertFalse(hum.shouldHeadsUpBecomePinned(notifEntry));      }      @Test      public void testShouldHeadsUpBecomePinned_noFSI_false() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry entry = createEntry(/* id = */ 0);          assertFalse(hum.shouldHeadsUpBecomePinned(entry)); @@ -214,7 +289,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testShowNotification_autoDismissesIncludingTouchAcceptanceDelay() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry entry = createEntry(/* id = */ 0);          useAccessibilityTimeout(false); @@ -228,7 +303,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testShowNotification_autoDismissesWithDefaultTimeout() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry entry = createEntry(/* id = */ 0);          useAccessibilityTimeout(false); @@ -242,7 +317,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testShowNotification_stickyForSomeTime_autoDismissesWithStickyTimeout() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry entry = createStickyForSomeTimeEntry(/* id = */ 0);          useAccessibilityTimeout(false); @@ -256,7 +331,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testShowNotification_sticky_neverAutoDismisses() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry entry = createStickyEntry(/* id = */ 0);          useAccessibilityTimeout(false); @@ -278,7 +353,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testShowNotification_autoDismissesWithAccessibilityTimeout() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry entry = createEntry(/* id = */ 0);          useAccessibilityTimeout(true); @@ -292,7 +367,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testShowNotification_stickyForSomeTime_autoDismissesWithAccessibilityTimeout() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry entry = createStickyForSomeTimeEntry(/* id = */ 0);          useAccessibilityTimeout(true); @@ -306,7 +381,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testRemoveNotification_beforeMinimumDisplayTime() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry entry = createEntry(/* id = */ 0);          useAccessibilityTimeout(false); @@ -329,7 +404,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testRemoveNotification_afterMinimumDisplayTime() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry entry = createEntry(/* id = */ 0);          useAccessibilityTimeout(false); @@ -366,7 +441,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testRemoveNotification_releaseImmediately() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry entry = createEntry(/* id = */ 0);          hum.showNotification(entry); @@ -382,14 +457,15 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testIsSticky_rowPinnedAndExpanded_true() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry notifEntry = createEntry(/* id = */ 0);          when(mRow.isPinned()).thenReturn(true);          notifEntry.setRow(mRow);          hum.showNotification(notifEntry); -        final HeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(notifEntry.getKey()); +        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry( +                notifEntry.getKey());          headsUpEntry.setExpanded(true);          assertTrue(hum.isSticky(notifEntry.getKey())); @@ -397,20 +473,21 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testIsSticky_remoteInputActive_true() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry notifEntry = createEntry(/* id = */ 0);          hum.showNotification(notifEntry); -        final HeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(notifEntry.getKey()); -        headsUpEntry.remoteInputActive = true; +        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry( +                notifEntry.getKey()); +        headsUpEntry.mRemoteInputActive = true;          assertTrue(hum.isSticky(notifEntry.getKey()));      }      @Test      public void testIsSticky_hasFullScreenIntent_true() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry notifEntry = createFullScreenIntentEntry(/* id = */ 0);          hum.showNotification(notifEntry); @@ -421,7 +498,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testIsSticky_stickyForSomeTime_false() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry entry = createStickyForSomeTimeEntry(/* id = */ 0);          hum.showNotification(entry); @@ -432,21 +509,22 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testIsSticky_false() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry notifEntry = createEntry(/* id = */ 0);          hum.showNotification(notifEntry); -        final HeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(notifEntry.getKey()); +        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry( +                notifEntry.getKey());          headsUpEntry.setExpanded(false); -        headsUpEntry.remoteInputActive = false; +        headsUpEntry.mRemoteInputActive = false;          assertFalse(hum.isSticky(notifEntry.getKey()));      }      @Test      public void testCompareTo_withNullEntries() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry alertEntry = new NotificationEntryBuilder().setTag("alert").build();          hum.showNotification(alertEntry); @@ -458,7 +536,7 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testCompareTo_withNonAlertEntries() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry nonAlertEntry1 = new NotificationEntryBuilder().setTag(                  "nae1").build(); @@ -474,9 +552,9 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testAlertEntryCompareTo_ongoingCallLessThanActiveRemoteInput() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager(); -        final HeadsUpManager.HeadsUpEntry ongoingCall = hum.new HeadsUpEntry(); +        final BaseHeadsUpManager.HeadsUpEntry ongoingCall = hum.new HeadsUpEntry();          ongoingCall.setEntry(new NotificationEntryBuilder()                  .setSbn(createSbn(/* id = */ 0,                          new Notification.Builder(mContext, "") @@ -484,9 +562,9 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {                                  .setOngoing(true)))                  .build()); -        final HeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry(); +        final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();          activeRemoteInput.setEntry(createEntry(/* id = */ 1)); -        activeRemoteInput.remoteInputActive = true; +        activeRemoteInput.mRemoteInputActive = true;          assertThat(ongoingCall.compareTo(activeRemoteInput)).isLessThan(0);          assertThat(activeRemoteInput.compareTo(ongoingCall)).isGreaterThan(0); @@ -494,9 +572,9 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testAlertEntryCompareTo_incomingCallLessThanActiveRemoteInput() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager(); -        final HeadsUpManager.HeadsUpEntry incomingCall = hum.new HeadsUpEntry(); +        final BaseHeadsUpManager.HeadsUpEntry incomingCall = hum.new HeadsUpEntry();          final Person person = new Person.Builder().setName("person").build();          final PendingIntent intent = mock(PendingIntent.class);          incomingCall.setEntry(new NotificationEntryBuilder() @@ -506,9 +584,9 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {                                          .forIncomingCall(person, intent, intent))))                  .build()); -        final HeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry(); +        final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();          activeRemoteInput.setEntry(createEntry(/* id = */ 1)); -        activeRemoteInput.remoteInputActive = true; +        activeRemoteInput.mRemoteInputActive = true;          assertThat(incomingCall.compareTo(activeRemoteInput)).isLessThan(0);          assertThat(activeRemoteInput.compareTo(incomingCall)).isGreaterThan(0); @@ -516,10 +594,10 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {      @Test      public void testPinEntry_logsPeek() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          // Needs full screen intent in order to be pinned -        final HeadsUpManager.HeadsUpEntry entryToPin = hum.new HeadsUpEntry(); +        final BaseHeadsUpManager.HeadsUpEntry entryToPin = hum.new HeadsUpEntry();          entryToPin.setEntry(createFullScreenIntentEntry(/* id = */ 0));          // Note: the standard way to show a notification would be calling showNotification rather @@ -530,13 +608,13 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {          hum.onAlertEntryAdded(entryToPin);          assertEquals(1, mUiEventLoggerFake.numLogs()); -        assertEquals(HeadsUpManager.NotificationPeekEvent.NOTIFICATION_PEEK.getId(), +        assertEquals(BaseHeadsUpManager.NotificationPeekEvent.NOTIFICATION_PEEK.getId(),                  mUiEventLoggerFake.eventId(0));      }      @Test      public void testSetUserActionMayIndirectlyRemove() { -        final HeadsUpManager hum = createHeadsUpManager(); +        final BaseHeadsUpManager hum = createHeadsUpManager();          final NotificationEntry notifEntry = createEntry(/* id = */ 0);          hum.showNotification(notifEntry); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt new file mode 100644 index 000000000000..12694ae998c1 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.statusbar.policy.data.repository + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.statusbar.policy.DeviceProvisionedController +import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.mockito.withArgCaptor +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidJUnit4::class) +class DeviceProvisioningRepositoryImplTest : SysuiTestCase() { + +    @Mock lateinit var deviceProvisionedController: DeviceProvisionedController + +    lateinit var underTest: DeviceProvisioningRepositoryImpl + +    @Before +    fun setup() { +        MockitoAnnotations.initMocks(this) +        underTest = +            DeviceProvisioningRepositoryImpl( +                deviceProvisionedController, +            ) +    } + +    @Test +    fun isDeviceProvisioned_reflectsCurrentControllerState() = runTest { +        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) +        val deviceProvisioned by collectLastValue(underTest.isDeviceProvisioned) +        assertThat(deviceProvisioned).isTrue() +    } + +    @Test +    fun isDeviceProvisioned_updatesWhenControllerStateChanges_toTrue() = runTest { +        val deviceProvisioned by collectLastValue(underTest.isDeviceProvisioned) +        runCurrent() +        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) +        withArgCaptor { verify(deviceProvisionedController).addCallback(capture()) } +            .onDeviceProvisionedChanged() +        assertThat(deviceProvisioned).isTrue() +    } + +    @Test +    fun isDeviceProvisioned_updatesWhenControllerStateChanges_toFalse() = runTest { +        val deviceProvisioned by collectLastValue(underTest.isDeviceProvisioned) +        runCurrent() +        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(false) +        withArgCaptor { verify(deviceProvisionedController).addCallback(capture()) } +            .onDeviceProvisionedChanged() +        assertThat(deviceProvisioned).isFalse() +    } + +    @Test +    fun isFrpActive_reflectsCurrentControllerState() = runTest { +        whenever(deviceProvisionedController.isFrpActive).thenReturn(true) +        val frpActive by collectLastValue(underTest.isFactoryResetProtectionActive) +        assertThat(frpActive).isTrue() +    } + +    @Test +    fun isFrpActive_updatesWhenControllerStateChanges_toTrue() = runTest { +        val frpActive by collectLastValue(underTest.isFactoryResetProtectionActive) +        runCurrent() +        whenever(deviceProvisionedController.isFrpActive).thenReturn(true) +        withArgCaptor { verify(deviceProvisionedController).addCallback(capture()) } +            .onFrpActiveChanged() +        assertThat(frpActive).isTrue() +    } + +    @Test +    fun isFrpActive_updatesWhenControllerStateChanges_toFalse() = runTest { +        val frpActive by collectLastValue(underTest.isFactoryResetProtectionActive) +        runCurrent() +        whenever(deviceProvisionedController.isFrpActive).thenReturn(false) +        withArgCaptor { verify(deviceProvisionedController).addCallback(capture()) } +            .onFrpActiveChanged() +        assertThat(frpActive).isFalse() +    } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt index af941d03f191..c56266dde752 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt @@ -155,6 +155,9 @@ class UserInteractorTest : SysuiTestCase() {      @Test      fun createUserInteractor_nonProcessUser_startsSecondaryService() { +        val userId = Process.myUserHandle().identifier + 1 +        whenever(manager.aliveUsers).thenReturn(listOf(createUserInfo(userId, "abc"))) +          createUserInteractor(false /* startAsProcessUser */)          verify(spyContext).startServiceAsUser(any(), any())      } @@ -655,9 +658,10 @@ class UserInteractorTest : SysuiTestCase() {      @Test      fun userSwitchedBroadcast() { -        createUserInteractor()          testScope.runTest {              val userInfos = createUserInfos(count = 2, includeGuest = false) +            whenever(manager.aliveUsers).thenReturn(userInfos) +            createUserInteractor()              userRepository.setUserInfos(userInfos)              userRepository.setSelectedUserInfo(userInfos[0])              userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) @@ -728,6 +732,26 @@ class UserInteractorTest : SysuiTestCase() {      }      @Test +    fun localeChanged_refreshUsers() { +        createUserInteractor() +        testScope.runTest { +            val userInfos = createUserInfos(count = 2, includeGuest = false) +            userRepository.setUserInfos(userInfos) +            userRepository.setSelectedUserInfo(userInfos[0]) +            runCurrent() +            val refreshUsersCallCount = userRepository.refreshUsersCallCount + +            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( +                spyContext, +                Intent(Intent.ACTION_LOCALE_CHANGED) +            ) +            runCurrent() + +            assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1) +        } +    } + +    @Test      fun nonSystemUserUnlockedBroadcast_doNotRefreshUsers() {          createUserInteractor()          testScope.runTest { @@ -985,6 +1009,13 @@ class UserInteractorTest : SysuiTestCase() {          }      } +    @Test +    fun initWithNoAliveUsers() { +        whenever(manager.aliveUsers).thenReturn(listOf()) +        createUserInteractor() +        verify(spyContext, never()).startServiceAsUser(any(), any()) +    } +      private fun assertUsers(          models: List<UserModel>?,          count: Int, diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt index 6932f5ed4b30..c236b12d723f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt @@ -28,6 +28,7 @@ import com.android.systemui.GuestResetOrExitSessionReceiver  import com.android.systemui.GuestResumeSessionReceiver  import com.android.systemui.SysuiTestCase  import com.android.systemui.common.shared.model.Text +import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.flags.FakeFeatureFlags  import com.android.systemui.flags.Flags  import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository @@ -347,6 +348,24 @@ class UserSwitcherViewModelTest : SysuiTestCase() {          }      @Test +    fun isFinishRequested_finishesWhenUserButtonIsClicked() = +        testScope.runTest { +            setUsers(count = 2) +            val isFinishRequested = mutableListOf<Boolean>() +            val job = +                launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) } + +            val userViewModels = collectLastValue(underTest.users) +            assertThat(isFinishRequested.last()).isFalse() + +            userViewModels.invoke()?.firstOrNull()?.onClicked?.invoke() + +            assertThat(isFinishRequested.last()).isTrue() + +            job.cancel() +        } + +    @Test      fun guestSelected_nameIsExitGuest() =          testScope.runTest {              val userInfos = diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt new file mode 100644 index 000000000000..aaf8d0761dce --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.util.ui + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class AnimatedValueTest : SysuiTestCase() { + +    @Test +    fun animatableEvent_updatesValue() = runTest { +        val events = MutableSharedFlow<AnimatableEvent<Int>>() +        val values = events.toAnimatedValueFlow(completionEvents = emptyFlow()) +        val value by collectLastValue(values) +        runCurrent() + +        events.emit(AnimatableEvent(value = 1, startAnimating = false)) + +        assertThat(value).isEqualTo(AnimatedValue(value = 1, isAnimating = false)) +    } + +    @Test +    fun animatableEvent_startAnimation() = runTest { +        val events = MutableSharedFlow<AnimatableEvent<Int>>() +        val values = events.toAnimatedValueFlow(completionEvents = emptyFlow()) +        val value by collectLastValue(values) +        runCurrent() + +        events.emit(AnimatableEvent(value = 1, startAnimating = true)) + +        assertThat(value).isEqualTo(AnimatedValue(value = 1, isAnimating = true)) +    } + +    @Test +    fun animatableEvent_startAnimation_alreadyAnimating() = runTest { +        val events = MutableSharedFlow<AnimatableEvent<Int>>() +        val values = events.toAnimatedValueFlow(completionEvents = emptyFlow()) +        val value by collectLastValue(values) +        runCurrent() + +        events.emit(AnimatableEvent(value = 1, startAnimating = true)) +        events.emit(AnimatableEvent(value = 2, startAnimating = true)) + +        assertThat(value).isEqualTo(AnimatedValue(value = 2, isAnimating = true)) +    } + +    @Test +    fun animatedValue_stopAnimating() = runTest { +        val events = MutableSharedFlow<AnimatableEvent<Int>>() +        val stopEvent = MutableSharedFlow<Unit>() +        val values = events.toAnimatedValueFlow(completionEvents = stopEvent) +        val value by collectLastValue(values) +        runCurrent() + +        events.emit(AnimatableEvent(value = 1, startAnimating = true)) +        stopEvent.emit(Unit) + +        assertThat(value).isEqualTo(AnimatedValue(value = 1, isAnimating = false)) +    } + +    @Test +    fun animatedValue_stopAnimating_notAnimating() = runTest { +        val events = MutableSharedFlow<AnimatableEvent<Int>>() +        val stopEvent = MutableSharedFlow<Unit>() +        val values = events.toAnimatedValueFlow(completionEvents = stopEvent) +        values.launchIn(backgroundScope) +        runCurrent() + +        events.emit(AnimatableEvent(value = 1, startAnimating = false)) + +        assertThat(stopEvent.subscriptionCount.value).isEqualTo(0) +    } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index 409ba4801d0d..c8327029026d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -86,20 +86,36 @@ import androidx.test.filters.SmallTest;  import com.android.internal.colorextraction.ColorExtractor;  import com.android.internal.logging.UiEventLogger;  import com.android.internal.statusbar.IStatusBarService; +import com.android.keyguard.KeyguardSecurityModel;  import com.android.launcher3.icons.BubbleIconFactory;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.biometrics.AuthController; +import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository; +import com.android.systemui.classifier.FalsingCollectorFake;  import com.android.systemui.colorextraction.SysuiColorExtractor;  import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository; +import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository;  import com.android.systemui.dump.DumpManager;  import com.android.systemui.flags.FakeFeatureFlags; +import com.android.systemui.flags.FakeFeatureFlagsClassic;  import com.android.systemui.keyguard.KeyguardViewMediator; +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.domain.interactor.FromLockscreenTransitionInteractor; +import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor; +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;  import com.android.systemui.model.SysUiState;  import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.power.data.repository.FakePowerRepository; +import com.android.systemui.power.domain.interactor.PowerInteractor;  import com.android.systemui.scene.FakeWindowRootViewComponent;  import com.android.systemui.scene.SceneTestUtils; +import com.android.systemui.scene.data.repository.SceneContainerRepository; +import com.android.systemui.scene.domain.interactor.SceneInteractor;  import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags; +import com.android.systemui.scene.shared.logger.SceneLogger;  import com.android.systemui.settings.FakeDisplayTracker;  import com.android.systemui.settings.UserTracker;  import com.android.systemui.shade.NotificationShadeWindowControllerImpl; @@ -139,6 +155,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.statusbar.policy.KeyguardStateController;  import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;  import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;  import com.android.systemui.user.domain.interactor.UserInteractor;  import com.android.wm.shell.ShellTaskOrganizer;  import com.android.wm.shell.WindowManagerShellWrapper; @@ -329,6 +346,8 @@ public class BubblesTest extends SysuiTestCase {      private UserHandle mUser0;      private FakeBubbleProperties mBubbleProperties; +    private FromLockscreenTransitionInteractor mFromLockscreenTransitionInteractor; +    private FromPrimaryBouncerTransitionInteractor mFromPrimaryBouncerTransitionInteractor;      @Before      public void setUp() throws Exception { @@ -350,21 +369,94 @@ public class BubblesTest extends SysuiTestCase {          when(mNotificationShadeWindowView.getViewTreeObserver())                  .thenReturn(mock(ViewTreeObserver.class)); -        mShadeInteractor = new ShadeInteractor( + +        FakeDeviceProvisioningRepository deviceProvisioningRepository = +                new FakeDeviceProvisioningRepository(); +        deviceProvisioningRepository.setDeviceProvisioned(true); +        FakeKeyguardRepository keyguardRepository = new FakeKeyguardRepository(); +        FakeFeatureFlagsClassic featureFlags = new FakeFeatureFlagsClassic(); +        FakeShadeRepository shadeRepository = new FakeShadeRepository(); +        FakePowerRepository powerRepository = new FakePowerRepository(); +        FakeConfigurationRepository configurationRepository = new FakeConfigurationRepository(); + +        PowerInteractor powerInteractor = new PowerInteractor( +                powerRepository, +                new FalsingCollectorFake(), +                mock(ScreenOffAnimationController.class), +                mStatusBarStateController); + +        SceneInteractor sceneInteractor = new SceneInteractor(                  mTestScope.getBackgroundScope(), -                new FakeDisableFlagsRepository(), -                new FakeSceneContainerFlags(), -                mUtils::sceneInteractor, -                new FakeKeyguardRepository(), -                new FakeUserSetupRepository(), -                mock(DeviceProvisionedController.class), -                mock(UserInteractor.class), -                new SharedNotificationContainerInteractor( -                        new FakeConfigurationRepository(), -                        mContext, -                        new ResourcesSplitShadeStateController()), -                new FakeShadeRepository() -        ); +                new SceneContainerRepository( +                        mTestScope.getBackgroundScope(), +                        mUtils.fakeSceneContainerConfig(mUtils.fakeSceneKeys())), +                powerRepository, +                mock(SceneLogger.class)); + +        FakeSceneContainerFlags sceneContainerFlags = new FakeSceneContainerFlags(); +        KeyguardInteractor keyguardInteractor = new KeyguardInteractor( +                keyguardRepository, +                new FakeCommandQueue(), +                powerInteractor, +                featureFlags, +                sceneContainerFlags, +                new FakeDeviceEntryRepository(), +                new FakeKeyguardBouncerRepository(), +                configurationRepository, +                shadeRepository, +                () -> sceneInteractor); + +        FakeKeyguardTransitionRepository keyguardTransitionRepository = +                new FakeKeyguardTransitionRepository(); + +        KeyguardTransitionInteractor keyguardTransitionInteractor = +                new KeyguardTransitionInteractor( +                        mTestScope.getBackgroundScope(), +                        keyguardTransitionRepository, +                        () -> keyguardInteractor, +                        () -> mFromLockscreenTransitionInteractor, +                        () -> mFromPrimaryBouncerTransitionInteractor); + +        mFromLockscreenTransitionInteractor = new FromLockscreenTransitionInteractor( +                keyguardTransitionRepository, +                keyguardTransitionInteractor, +                mTestScope.getBackgroundScope(), +                keyguardInteractor, +                featureFlags, +                shadeRepository, +                powerInteractor); + +        mFromPrimaryBouncerTransitionInteractor = new FromPrimaryBouncerTransitionInteractor( +                keyguardTransitionRepository, +                keyguardTransitionInteractor, +                mTestScope.getBackgroundScope(), +                keyguardInteractor, +                featureFlags, +                mock(KeyguardSecurityModel.class), +                powerInteractor); + +        ResourcesSplitShadeStateController splitShadeStateController = +                new ResourcesSplitShadeStateController(); + +        mShadeInteractor = +                new ShadeInteractor( +                        mTestScope.getBackgroundScope(), +                        deviceProvisioningRepository, +                        new FakeDisableFlagsRepository(), +                        mDozeParameters, +                        sceneContainerFlags, +                        () -> sceneInteractor, +                        keyguardRepository, +                        keyguardTransitionInteractor, +                        powerInteractor, +                        new FakeUserSetupRepository(), +                        mock(UserInteractor.class), +                        new SharedNotificationContainerInteractor( +                                configurationRepository, +                                mContext, +                                splitShadeStateController), +                        new FakeShadeRepository() +                );          mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(                  mContext, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt index 0e594964bb30..dc5fd953239d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt @@ -15,21 +15,29 @@   */  package com.android.systemui +import com.android.systemui.classifier.FakeClassifierModule  import com.android.systemui.data.FakeSystemUiDataLayerModule  import com.android.systemui.flags.FakeFeatureFlagsClassicModule  import com.android.systemui.log.FakeUiEventLoggerModule  import com.android.systemui.scene.FakeSceneModule  import com.android.systemui.settings.FakeSettingsModule +import com.android.systemui.statusbar.policy.FakeConfigurationControllerModule +import com.android.systemui.statusbar.policy.FakeSplitShadeStateControllerModule  import com.android.systemui.util.concurrency.FakeExecutorModule +import com.android.systemui.util.time.FakeSystemClockModule  import dagger.Module  @Module(      includes =          [ +            FakeClassifierModule::class, +            FakeConfigurationControllerModule::class,              FakeExecutorModule::class,              FakeFeatureFlagsClassicModule::class, -            FakeSettingsModule::class,              FakeSceneModule::class, +            FakeSettingsModule::class, +            FakeSplitShadeStateControllerModule::class, +            FakeSystemClockModule::class,              FakeSystemUiDataLayerModule::class,              FakeUiEventLoggerModule::class,          ] diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/FakeAuthenticationDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/FakeAuthenticationDataLayerModule.kt new file mode 100644 index 000000000000..8fa6695cab99 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/FakeAuthenticationDataLayerModule.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.authentication.data + +import com.android.systemui.authentication.data.repository.FakeAuthenticationRepositoryModule +import dagger.Module + +@Module(includes = [FakeAuthenticationRepositoryModule::class]) +object FakeAuthenticationDataLayerModule diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt index 4fc3e3f66e6d..ddfe79aedce6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt @@ -24,10 +24,17 @@ import com.android.systemui.authentication.data.model.AuthenticationMethodModel  import com.android.systemui.authentication.shared.model.AuthenticationPatternCoordinate  import com.android.systemui.authentication.shared.model.AuthenticationResultModel  import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel +import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository +import dagger.Binds +import dagger.Module +import dagger.Provides +import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.flow.MutableStateFlow  import kotlinx.coroutines.flow.StateFlow  import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.currentTime  class FakeAuthenticationRepository(      private val deviceEntryRepository: FakeDeviceEntryRepository, @@ -201,3 +208,19 @@ class FakeAuthenticationRepository(          }      }  } + +@OptIn(ExperimentalCoroutinesApi::class) +@Module(includes = [FakeAuthenticationRepositoryModule.Bindings::class]) +object FakeAuthenticationRepositoryModule { +    @Provides +    @SysUISingleton +    fun provideFake( +        deviceEntryRepository: FakeDeviceEntryRepository, +        scope: TestScope, +    ) = FakeAuthenticationRepository(deviceEntryRepository, currentTime = { scope.currentTime }) + +    @Module +    interface Bindings { +        @Binds fun bindFake(fake: FakeAuthenticationRepository): AuthenticationRepository +    } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeClassifierModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeClassifierModule.kt new file mode 100644 index 000000000000..23bad39a262e --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeClassifierModule.kt @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + * + */ + +package com.android.systemui.classifier + +import dagger.Module + +@Module(includes = [FakeFalsingCollectorModule::class, FakeFalsingManagerModule::class]) +object FakeClassifierModule diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingCollectorModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingCollectorModule.kt new file mode 100644 index 000000000000..92acc9465bb0 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingCollectorModule.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + * + */ + +package com.android.systemui.classifier + +import dagger.Binds +import dagger.Module + +@Module +interface FakeFalsingCollectorModule { +    @Binds @FalsingCollectorActual fun bindFake(fake: FalsingCollectorFake): FalsingCollector +    @Binds fun bindFakeLegacy(fake: FalsingCollectorFake): FalsingCollector +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingManagerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingManagerModule.kt new file mode 100644 index 000000000000..554fc75ec1db --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FakeFalsingManagerModule.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + * + */ + +package com.android.systemui.classifier + +import com.android.systemui.plugins.FalsingManager +import dagger.Binds +import dagger.Module + +@Module +interface FakeFalsingManagerModule { +    @Binds fun bindFake(fake: FalsingManagerFake): FalsingManager +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java index d47e88fc9385..5038285aef00 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java @@ -21,15 +21,19 @@ import static com.google.common.truth.Truth.assertWithMessage;  import android.net.Uri;  import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.dagger.SysUISingleton;  import com.android.systemui.plugins.FalsingManager;  import java.io.PrintWriter;  import java.util.ArrayList;  import java.util.List; +import javax.inject.Inject; +  /**   * Simple Fake for testing where {@link FalsingManager} is required.   */ +@SysUISingleton  public class FalsingManagerFake implements FalsingManager {      private boolean mIsFalseTouch;      private boolean mIsSimpleTap; @@ -46,6 +50,10 @@ public class FalsingManagerFake implements FalsingManager {      private final List<FalsingBeliefListener> mFalsingBeliefListeners = new ArrayList<>();      private final List<FalsingTapListener> mTapListeners = new ArrayList<>(); +    @Inject +    public FalsingManagerFake() { +    } +      @Override      public void onSuccessfulUnlock() { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt index f866932309bb..cffbf0271c29 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt @@ -15,8 +15,10 @@   */  package com.android.systemui.data +import com.android.systemui.authentication.data.FakeAuthenticationDataLayerModule  import com.android.systemui.bouncer.data.repository.FakeBouncerDataLayerModule  import com.android.systemui.common.ui.data.FakeCommonDataLayerModule +import com.android.systemui.deviceentry.data.FakeDeviceEntryDataLayerModule  import com.android.systemui.keyguard.data.FakeKeyguardDataLayerModule  import com.android.systemui.power.data.FakePowerDataLayerModule  import com.android.systemui.shade.data.repository.FakeShadeDataLayerModule @@ -28,8 +30,10 @@ import dagger.Module  @Module(      includes =          [ -            FakeCommonDataLayerModule::class, +            FakeAuthenticationDataLayerModule::class,              FakeBouncerDataLayerModule::class, +            FakeCommonDataLayerModule::class, +            FakeDeviceEntryDataLayerModule::class,              FakeKeyguardDataLayerModule::class,              FakePowerDataLayerModule::class,              FakeShadeDataLayerModule::class, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt new file mode 100644 index 000000000000..ef02bdd9c35c --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + * + */ + +package com.android.systemui.deviceentry.data + +import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepositoryModule +import dagger.Module + +@Module(includes = [FakeDeviceEntryRepositoryModule::class]) object FakeDeviceEntryDataLayerModule diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryDataLayerModule.kt new file mode 100644 index 000000000000..f4feee19df65 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryDataLayerModule.kt @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.deviceentry.data.repository + +import dagger.Module + +@Module(includes = [FakeDeviceEntryRepositoryModule::class]) object FakeDeviceEntryDataLayerModule diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt index 5e60a09e006b..f0293489cb87 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/FakeDeviceEntryRepository.kt @@ -1,22 +1,40 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */  package com.android.systemui.deviceentry.data.repository +import com.android.systemui.dagger.SysUISingleton +import dagger.Binds +import dagger.Module +import javax.inject.Inject  import kotlinx.coroutines.flow.MutableStateFlow  import kotlinx.coroutines.flow.StateFlow  import kotlinx.coroutines.flow.asStateFlow  /** Fake implementation of [DeviceEntryRepository] */ -class FakeDeviceEntryRepository : DeviceEntryRepository { +@SysUISingleton +class FakeDeviceEntryRepository @Inject constructor() : DeviceEntryRepository {      private var isInsecureLockscreenEnabled = true -    private var isBypassEnabled = false + +    private val _isBypassEnabled = MutableStateFlow(false) +    override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled      private val _isUnlocked = MutableStateFlow(false)      override val isUnlocked: StateFlow<Boolean> = _isUnlocked.asStateFlow() -    override fun isBypassEnabled(): Boolean { -        return isBypassEnabled -    } -      override suspend fun isInsecureLockscreenEnabled(): Boolean {          return isInsecureLockscreenEnabled      } @@ -30,6 +48,11 @@ class FakeDeviceEntryRepository : DeviceEntryRepository {      }      fun setBypassEnabled(isBypassEnabled: Boolean) { -        this.isBypassEnabled = isBypassEnabled +        _isBypassEnabled.value = isBypassEnabled      }  } + +@Module +interface FakeDeviceEntryRepositoryModule { +    @Binds fun bindFake(fake: FakeDeviceEntryRepository): DeviceEntryRepository +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt index 1bec82b0875b..e59f642071fb 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt @@ -16,14 +16,18 @@  package com.android.systemui.statusbar.data  import com.android.systemui.statusbar.disableflags.data.FakeStatusBarDisableFlagsDataLayerModule +import com.android.systemui.statusbar.notification.data.FakeStatusBarNotificationsDataLayerModule  import com.android.systemui.statusbar.pipeline.data.FakeStatusBarPipelineDataLayerModule +import com.android.systemui.statusbar.policy.data.FakeStatusBarPolicyDataLayerModule  import dagger.Module  @Module(      includes =          [              FakeStatusBarDisableFlagsDataLayerModule::class, +            FakeStatusBarNotificationsDataLayerModule::class,              FakeStatusBarPipelineDataLayerModule::class, +            FakeStatusBarPolicyDataLayerModule::class,          ]  )  object FakeStatusBarDataLayerModule diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt new file mode 100644 index 000000000000..788e3aa9c41a --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/FakeStatusBarNotificationsDataLayerModule.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.notification.data + +import com.android.systemui.statusbar.notification.data.repository.FakeNotificationsKeyguardStateRepositoryModule +import dagger.Module + +@Module(includes = [FakeNotificationsKeyguardStateRepositoryModule::class]) +object FakeStatusBarNotificationsDataLayerModule diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/FakeNotificationsKeyguardViewStateRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/FakeNotificationsKeyguardViewStateRepository.kt new file mode 100644 index 000000000000..5d3cb4db9c7e --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/FakeNotificationsKeyguardViewStateRepository.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.notification.data.repository + +import com.android.systemui.dagger.SysUISingleton +import dagger.Binds +import dagger.Module +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow + +@SysUISingleton +class FakeNotificationsKeyguardViewStateRepository @Inject constructor() : +    NotificationsKeyguardViewStateRepository { +    private val _notificationsFullyHidden = MutableStateFlow(false) +    override val areNotificationsFullyHidden: Flow<Boolean> = _notificationsFullyHidden + +    private val _isPulseExpanding = MutableStateFlow(false) +    override val isPulseExpanding: Flow<Boolean> = _isPulseExpanding + +    fun setNotificationsFullyHidden(fullyHidden: Boolean) { +        _notificationsFullyHidden.value = fullyHidden +    } + +    fun setPulseExpanding(expanding: Boolean) { +        _isPulseExpanding.value = expanding +    } +} + +@Module +interface FakeNotificationsKeyguardStateRepositoryModule { +    @Binds +    fun bindFake( +        fake: FakeNotificationsKeyguardViewStateRepository +    ): NotificationsKeyguardViewStateRepository +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt index 16a326869562..23477d86807c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt @@ -1,9 +1,14 @@  package com.android.systemui.statusbar.policy  import android.content.res.Configuration +import com.android.systemui.dagger.SysUISingleton +import dagger.Binds +import dagger.Module +import javax.inject.Inject  /** Fake implementation of [ConfigurationController] for tests. */ -class FakeConfigurationController : ConfigurationController { +@SysUISingleton +class FakeConfigurationController @Inject constructor() : ConfigurationController {      private var listeners = mutableListOf<ConfigurationController.ConfigurationListener>() @@ -33,3 +38,8 @@ class FakeConfigurationController : ConfigurationController {      override fun isLayoutRtl(): Boolean = false  } + +@Module +interface FakeConfigurationControllerModule { +    @Binds fun bindFake(fake: FakeConfigurationController): ConfigurationController +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSplitShadeStateControllerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSplitShadeStateControllerModule.kt new file mode 100644 index 000000000000..14bab84e62b2 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSplitShadeStateControllerModule.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + * + */ + +package com.android.systemui.statusbar.policy + +import dagger.Binds +import dagger.Module + +@Module +interface FakeSplitShadeStateControllerModule { +    @Binds fun bindFake(fake: ResourcesSplitShadeStateController): SplitShadeStateController +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/FakeStatusBarPolicyDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/FakeStatusBarPolicyDataLayerModule.kt new file mode 100644 index 000000000000..5aece1bbbd31 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/FakeStatusBarPolicyDataLayerModule.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.policy.data + +import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepositoryModule +import dagger.Module + +@Module(includes = [FakeDeviceProvisioningRepositoryModule::class]) +object FakeStatusBarPolicyDataLayerModule diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeDeviceProvisioningRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeDeviceProvisioningRepository.kt new file mode 100644 index 000000000000..300229954044 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeDeviceProvisioningRepository.kt @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.policy.data.repository + +import com.android.systemui.dagger.SysUISingleton +import dagger.Binds +import dagger.Module +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow + +@SysUISingleton +class FakeDeviceProvisioningRepository @Inject constructor() : DeviceProvisioningRepository { +    private val _isDeviceProvisioned = MutableStateFlow(false) +    override val isDeviceProvisioned: Flow<Boolean> = _isDeviceProvisioned +    private val _isFactoryResetProtectionActive = MutableStateFlow(false) +    override val isFactoryResetProtectionActive: Flow<Boolean> = _isFactoryResetProtectionActive +    fun setDeviceProvisioned(isProvisioned: Boolean) { +        _isDeviceProvisioned.value = isProvisioned +    } +    fun setFactoryResetProtectionActive(isActive: Boolean) { +        _isFactoryResetProtectionActive.value = isActive +    } +} + +@Module +interface FakeDeviceProvisioningRepositoryModule { +    @Binds fun bindFake(fake: FakeDeviceProvisioningRepository): DeviceProvisioningRepository +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/FakeExecutorModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/FakeExecutorModule.kt index 5de05c27ba2e..1f48d940f91c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/FakeExecutorModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/FakeExecutorModule.kt @@ -15,6 +15,7 @@   */  package com.android.systemui.util.concurrency +import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Main  import com.android.systemui.util.time.FakeSystemClock  import dagger.Binds @@ -22,14 +23,12 @@ import dagger.Module  import dagger.Provides  import java.util.concurrent.Executor -@Module(includes = [FakeExecutorModule.Bindings::class]) -class FakeExecutorModule( -    @get:Provides val clock: FakeSystemClock = FakeSystemClock(), -) { -    @get:Provides val executor = FakeExecutor(clock) +@Module +interface FakeExecutorModule { +    @Binds @Main @SysUISingleton fun bindMainExecutor(executor: FakeExecutor): Executor -    @Module -    interface Bindings { -        @Binds @Main fun bindMainExecutor(executor: FakeExecutor): Executor +    companion object { +        @Provides +        fun provideFake(clock: FakeSystemClock) = FakeExecutor(clock)      }  } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/RoboPilotTest.java b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockModule.kt index 3fff136db03a..3e3d7cbb40b5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/RoboPilotTest.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockModule.kt @@ -13,19 +13,18 @@   * See the License for the specific language governing permissions and   * limitations under the License.   */ +package com.android.systemui.util.time -package com.android.systemui; +import com.android.systemui.dagger.SysUISingleton +import dagger.Binds +import dagger.Module +import dagger.Provides -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +@Module +interface FakeSystemClockModule { +    @Binds fun bindFake(fake: FakeSystemClock): SystemClock -/** - * Mark as tests for Robolectric pilot projects. The filter can better help grouping test results - * that runs on CI - */ -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface RoboPilotTest { +    companion object { +        @Provides @SysUISingleton fun providesFake() = FakeSystemClock() +    }  } diff --git a/packages/WallpaperBackup/Android.bp b/packages/WallpaperBackup/Android.bp index 155dc1a68295..18f783146c72 100644 --- a/packages/WallpaperBackup/Android.bp +++ b/packages/WallpaperBackup/Android.bp @@ -49,7 +49,7 @@ android_test {          "androidx.test.core",          "androidx.test.rules",          "mockito-target-minus-junit4", -        "truth-prebuilt", +        "truth",      ],      resource_dirs: ["test/res"],      certificate: "platform", diff --git a/packages/overlays/tests/Android.bp b/packages/overlays/tests/Android.bp index b781602399a3..0244c0fe0533 100644 --- a/packages/overlays/tests/Android.bp +++ b/packages/overlays/tests/Android.bp @@ -34,7 +34,7 @@ android_test {          "androidx.test.rules",          "androidx.test.espresso.core",          "mockito-target-minus-junit4", -        "truth-prebuilt", +        "truth",      ],      dxflags: ["--multi-dex"],  } diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 7e09b5ea9fa5..258820a5a03c 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -24,6 +24,7 @@ import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;  import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; +import android.Manifest;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.RequiresPermission; @@ -1660,8 +1661,21 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku          synchronized (mLock) {              ensureGroupStateLoadedLocked(userId); +            final String pkg = componentName.getPackageName(); +            final ProviderId id; +            if (!mPackageManagerInternal.isSameApp(pkg, callingUid, userId)) { +                // If the calling process is requesting to pin appwidgets from another process, +                // check if the calling process has the necessary permission. +                if (!injectHasAccessWidgetsPermission(Binder.getCallingPid(), callingUid)) { +                    return false; +                } +                id = new ProviderId(mPackageManagerInternal.getPackageUid( +                        pkg, 0 /* flags */, userId), componentName); +            } else { +                id = new ProviderId(callingUid, componentName); +            }              // Look for the widget associated with the caller. -            Provider provider = lookupProviderLocked(new ProviderId(callingUid, componentName)); +            Provider provider = lookupProviderLocked(id);              if (provider == null || provider.zombie) {                  return false;              } @@ -1675,6 +1689,14 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku                  .requestPinAppWidget(callingPackage, info, extras, resultSender, userId);      } +    /** +     * Returns true if the caller has the proper permission to access app widgets. +     */ +    private boolean injectHasAccessWidgetsPermission(int callingPid, int callingUid) { +        return mContext.checkPermission(Manifest.permission.CLEAR_APP_USER_DATA, +                callingPid, callingUid) == PackageManager.PERMISSION_GRANTED; +    } +      @Override      public ParceledListSlice<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter,              int profileId, String packageName) { @@ -4131,7 +4153,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku              return false;          } -        @GuardedBy("mLock") +        @GuardedBy("AppWidgetServiceImpl.mLock")          public AppWidgetProviderInfo getInfoLocked(Context context) {              if (!mInfoParsed) {                  // parse @@ -4159,18 +4181,18 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku           * be completely parsed and only contain placeHolder information like           * {@link AppWidgetProviderInfo#providerInfo}           */ -        @GuardedBy("mLock") +        @GuardedBy("AppWidgetServiceImpl.mLock")          public AppWidgetProviderInfo getPartialInfoLocked() {              return info;          } -        @GuardedBy("mLock") +        @GuardedBy("AppWidgetServiceImpl.mLock")          public void setPartialInfoLocked(AppWidgetProviderInfo info) {              this.info = info;              mInfoParsed = false;          } -        @GuardedBy("mLock") +        @GuardedBy("AppWidgetServiceImpl.mLock")          public void setInfoLocked(AppWidgetProviderInfo info) {              this.info = info;              mInfoParsed = true; diff --git a/services/autofill/Android.bp b/services/autofill/Android.bp index d43a219e6205..eb23f2f9b435 100644 --- a/services/autofill/Android.bp +++ b/services/autofill/Android.bp @@ -19,19 +19,4 @@ java_library_static {      defaults: ["platform_service_defaults"],      srcs: [":services.autofill-sources"],      libs: ["services.core"], -    static_libs: ["autofill_flags_java_lib"], -} - -aconfig_declarations { -    name: "autofill_flags", -    package: "android.service.autofill", -    srcs: [ -        "bugfixes.aconfig", -        "features.aconfig", -    ], -} - -java_aconfig_library { -    name: "autofill_flags_java_lib", -    aconfig_declarations: "autofill_flags",  } diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig index ef237546378e..123b65c039ba 100644 --- a/services/autofill/bugfixes.aconfig +++ b/services/autofill/bugfixes.aconfig @@ -5,4 +5,11 @@ flag {    namespace: "autofill"    description: "Test flag "    bug: "297380045" -}
\ No newline at end of file +} + +flag { +  name: "relayout" +  namespace: "autofill" +  description: "Mitigation for relayout issue" +  bug: "294330426" +} diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java index 9bab261bb0f4..93dca2f4f192 100644 --- a/services/core/java/com/android/server/PinnerService.java +++ b/services/core/java/com/android/server/PinnerService.java @@ -359,8 +359,10 @@ public final class PinnerService extends SystemService {                      @Override                      public void onChange(boolean selfChange, Uri uri) {                          if (userSetupCompleteUri.equals(uri)) { -                            sendPinAppMessage(KEY_HOME, ActivityManager.getCurrentUser(), -                                    true /* force */); +                            if (mConfiguredToPinHome) { +                                sendPinAppMessage(KEY_HOME, ActivityManager.getCurrentUser(), +                                        true /* force */); +                            }                          }                      }                  }, UserHandle.USER_ALL); diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 8cc2665b3562..962f38f10b5d 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -214,6 +214,9 @@ class StorageManagerService extends IStorageManager.Stub      // external storage service.      public static final int FAILED_MOUNT_RESET_TIMEOUT_SECONDS = 10; +     /** Extended timeout for the system server watchdog. */ +    private static final int SLOW_OPERATION_WATCHDOG_TIMEOUT_MS = 60 * 1000; +      @GuardedBy("mLock")      private final Set<Integer> mFuseMountedUser = new ArraySet<>(); @@ -1230,6 +1233,8 @@ class StorageManagerService extends IStorageManager.Stub      private void onUserStopped(int userId) {          Slog.d(TAG, "onUserStopped " + userId); +        Watchdog.getInstance().setOneOffTimeoutForMonitors( +                SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#onUserStopped might be slow");          try {              mVold.onUserStopped(userId);              mStoraged.onUserStopped(userId); @@ -1312,6 +1317,8 @@ class StorageManagerService extends IStorageManager.Stub                  unlockedUsers.add(userId);              }          } +        Watchdog.getInstance().setOneOffTimeoutForMonitors( +                SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#onUserStopped might be slow");          for (Integer userId : unlockedUsers) {              try {                  mVold.onUserStopped(userId); @@ -3600,6 +3607,8 @@ class StorageManagerService extends IStorageManager.Stub          @Override          public ParcelFileDescriptor open() throws AppFuseMountException { +            Watchdog.getInstance().setOneOffTimeoutForMonitors( +                SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#open might be slow");              try {                  final FileDescriptor fd = mVold.mountAppFuse(uid, mountId);                  mMounted = true; @@ -3612,6 +3621,8 @@ class StorageManagerService extends IStorageManager.Stub          @Override          public ParcelFileDescriptor openFile(int mountId, int fileId, int flags)                  throws AppFuseMountException { +            Watchdog.getInstance().setOneOffTimeoutForMonitors( +                SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#openFile might be slow");              try {                  return new ParcelFileDescriptor(                          mVold.openAppFuseFile(uid, mountId, fileId, flags)); @@ -3622,6 +3633,8 @@ class StorageManagerService extends IStorageManager.Stub          @Override          public void close() throws Exception { +            Watchdog.getInstance().setOneOffTimeoutForMonitors( +                SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#close might be slow");              if (mMounted) {                  mVold.unmountAppFuse(uid, mountId);                  mMounted = false; diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index b05b397a45de..55aa7164a67b 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -644,6 +644,16 @@ public class Watchdog implements Dumpable {      }      /** +     * Sets a one-off timeout for the next run of the watchdog for the monitor thread. +     * +     * <p>Simiar to {@link setOneOffTimeoutForCurrentThread} but used for monitors added through +     * {@link #addMonitor} +     */ +    public void setOneOffTimeoutForMonitors(int oneOffTimeoutMillis, String reason) { +        mMonitorChecker.setOneOffTimeoutLocked(oneOffTimeoutMillis, reason); +    } + +    /**       * Pauses Watchdog action for the currently running thread. Useful before executing long running       * operations that could falsely trigger the watchdog. Each call to this will require a matching       * call to {@link #resumeWatchingCurrentThread}. diff --git a/services/core/java/com/android/server/am/AnrTimer.java b/services/core/java/com/android/server/am/AnrTimer.java index 378a38602211..9ba49ce35dad 100644 --- a/services/core/java/com/android/server/am/AnrTimer.java +++ b/services/core/java/com/android/server/am/AnrTimer.java @@ -108,6 +108,14 @@ class AnrTimer<V> {      private static final boolean ENABLE_TRACING = false;      /** +     * Return true if the feature is enabled.  By default, the value is take from the Flags class +     * but it can be changed for local testing. +     */ +    private static boolean anrTimerServiceEnabled() { +        return Flags.anrTimerServiceEnabled(); +    } + +    /**       * The status of an ANR timer.  TIMER_INVALID status is returned when an error is detected.       */      private static final int TIMER_INVALID = 0; @@ -327,18 +335,33 @@ class AnrTimer<V> {       */      @VisibleForTesting      static class Injector { +        private final Handler mReferenceHandler; + +        Injector(@NonNull Handler handler) { +            mReferenceHandler = handler; +        } +          /** -         * Return a handler for the given Callback. +         * Return a handler for the given Callback, based on the reference handler. The handler +         * might be mocked, in which case it does not have a valid Looper.  In this case, use the +         * main Looper.           */ +        @NonNull          Handler getHandler(@NonNull Handler.Callback callback) { -            return null; +            Looper looper = mReferenceHandler.getLooper(); +            if (looper == null) looper = Looper.getMainLooper(); +            return new Handler(looper, callback);          }; -        /** -         * Return a CpuTracker. -         */ +        /** Return a CpuTracker. */ +        @NonNull          CpuTracker getTracker() { -            return null; +            return new CpuTracker(); +        } + +        /** Return true if the feature is enabled. */ +        boolean getFeatureEnabled() { +            return anrTimerServiceEnabled();          }      } @@ -375,12 +398,6 @@ class AnrTimer<V> {          /** The interface to fetch process statistics that might extend an ANR timeout. */          private final CpuTracker mCpu; -        /** Create a HandlerTimerService based on the input handler. */ -        HandlerTimerService(@NonNull Handler handler) { -            mHandler = new Handler(handler.getLooper(), this::expires); -            mCpu = new CpuTracker(); -        } -          /** Create a HandlerTimerService that directly uses the supplied handler and tracker. */          @VisibleForTesting          HandlerTimerService(@NonNull Injector injector) { @@ -491,38 +508,56 @@ class AnrTimer<V> {      private final boolean mLenientCancel = true;      /** +     * The top-level switch for the feature enabled or disabled. +     */ +    private final FeatureSwitch mFeature; + +    /**       * The common constructor.  A null injector results in a normal, production timer.       */      @VisibleForTesting      AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend, -            @Nullable Injector injector) { +            @NonNull Injector injector) {          mHandler = handler;          mWhat = what;          mLabel = label;          mExtend = extend; -        if (injector == null) { -            mTimerService = new HandlerTimerService(handler); +        boolean enabled = injector.getFeatureEnabled(); +        if (!enabled) { +            mFeature = new FeatureDisabled(); +            mTimerService = null;          } else { +            mFeature = new FeatureEnabled();              mTimerService = new HandlerTimerService(injector); + +            synchronized (sAnrTimerList) { +                sAnrTimerList.add(new WeakReference(this)); +            }          } -        synchronized (sAnrTimerList) { -            sAnrTimerList.add(new WeakReference(this)); -        } -        Log.i(TAG, formatSimple("created %s label: \"%s\"", mTimerService.toString(), label)); +        Log.i(TAG, formatSimple("created %s label: \"%s\"", mTimerService, label));      }      /**       * Create one timer instance for production.  The client can ask for extensible timeouts.       */      AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend) { -        this(handler, what, label, extend, null); +        this(handler, what, label, extend, new Injector(handler));      }      /**       * Create one timer instance for production.  There are no extensible timeouts.       */      AnrTimer(@NonNull Handler handler, int what, @NonNull String label) { -        this(handler, what, label, false, null); +        this(handler, what, label, false); +    } + +    /** +     * Return true if the service is enabled on this instance.  Clients should use this method to +     * decide if the feature is enabled, and not read the flags directly.  This method should be +     * deleted if and when the feature is enabled permanently. +     */ +    boolean serviceEnabled() { +        return mFeature.enabled();      }      /** @@ -613,93 +648,186 @@ class AnrTimer<V> {          Log.i(TAG, msg + " " + timer + " " + Objects.toString(timer.arg));      } -   /** -     * Start a timer. +    /** +     * The FeatureSwitch class provides a quick switch between feature-enabled behavior and +     * feature-disabled behavior.       */ -    boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) { -        final Timer timer = Timer.obtain(pid, uid, arg, timeoutMs, this); -        synchronized (mLock) { -            Timer old = mTimerMap.get(arg); -            if (old != null) { -                // There is an existing timer.  This is a protocol error in the client.  Record -                // the error and then clean up by canceling running timers and discarding expired -                // timers. -                restartedLocked(old.status, arg); -                if (old.status == TIMER_EXPIRED) { -                    discard(arg); +    private abstract class FeatureSwitch { +        abstract boolean start(@NonNull V arg, int pid, int uid, long timeoutMs); +        abstract boolean cancel(@NonNull V arg); +        abstract boolean accept(@NonNull V arg); +        abstract boolean discard(@NonNull V arg); +        abstract boolean enabled(); +    } + +    /** +     * The FeatureDisabled class bypasses almost all AnrTimer logic.  It is used when the AnrTimer +     * service is disabled via Flags.anrTimerServiceEnabled. +     */ +    private class FeatureDisabled extends FeatureSwitch { +        /** Start a timer by sending a message to the client's handler. */ +        boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) { +            final Message msg = mHandler.obtainMessage(mWhat, arg); +            mHandler.sendMessageDelayed(msg, timeoutMs); +            return true; +        } + +        /** Cancel a timer by removing the message from the client's handler. */ +        boolean cancel(@NonNull V arg) { +            mHandler.removeMessages(mWhat, arg); +            return true; +        } + +        /** accept() is a no-op when the feature is disabled. */ +        boolean accept(@NonNull V arg) { +            return true; +        } + +        /** discard() is a no-op when the feature is disabled. */ +        boolean discard(@NonNull V arg) { +            return true; +        } + +        /** The feature is not enabled. */ +        boolean enabled() { +            return false; +        } +    } + +    /** +     * The FeatureEnabled class enables the AnrTimer logic.  It is used when the AnrTimer service +     * is enabled via Flags.anrTimerServiceEnabled. +     */ +    private class FeatureEnabled extends FeatureSwitch { + +        /** +         * Start a timer. +         */ +        boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) { +            final Timer timer = Timer.obtain(pid, uid, arg, timeoutMs, AnrTimer.this); +            synchronized (mLock) { +                Timer old = mTimerMap.get(arg); +                if (old != null) { +                    // There is an existing timer.  This is a protocol error in the client. +                    // Record the error and then clean up by canceling running timers and +                    // discarding expired timers. +                    restartedLocked(old.status, arg); +                    if (old.status == TIMER_EXPIRED) { +                        discard(arg); +                    } else { +                        cancel(arg); +                    } +                } +                if (mTimerService.start(timer)) { +                    timer.status = TIMER_RUNNING; +                    mTimerMap.put(arg, timer); +                    mTotalStarted++; +                    mMaxStarted = Math.max(mMaxStarted, mTimerMap.size()); +                    if (DEBUG) report(timer, "start"); +                    return true;                  } else { -                    cancel(arg); +                    Log.e(TAG, "AnrTimer.start failed"); +                    return false;                  }              } -            if (mTimerService.start(timer)) { -                timer.status = TIMER_RUNNING; -                mTimerMap.put(arg, timer); -                mTotalStarted++; -                mMaxStarted = Math.max(mMaxStarted, mTimerMap.size()); -                if (DEBUG) report(timer, "start"); +        } + +        /** +         * Cancel a timer.  Return false if the timer was not found. +         */ +        boolean cancel(@NonNull V arg) { +            synchronized (mLock) { +                Timer timer = removeLocked(arg); +                if (timer == null) { +                    if (!mLenientCancel) notFoundLocked("cancel", arg); +                    return false; +                } +                mTimerService.cancel(timer); +                // There may be an expiration message in flight.  Cancel it. +                mHandler.removeMessages(mWhat, arg); +                if (DEBUG) report(timer, "cancel"); +                timer.release();                  return true; -            } else { -                Log.e(TAG, "AnrTimer.start failed"); -                return false;              }          } + +        /** +         * Accept a timer in the framework-level handler.  The timeout has been accepted and the +         * timeout handler is executing.  Return false if the timer was not found. +         */ +        boolean accept(@NonNull V arg) { +            synchronized (mLock) { +                Timer timer = removeLocked(arg); +                if (timer == null) { +                    notFoundLocked("accept", arg); +                    return false; +                } +                mTimerService.accept(timer); +                traceEnd(timer); +                if (DEBUG) report(timer, "accept"); +                timer.release(); +                return true; +            } +        } + +        /** +         * Discard a timer in the framework-level handler.  For whatever reason, the timer is no +         * longer interesting.  No statistics are collected.  Return false if the time was not +         * found. +         */ +        boolean discard(@NonNull V arg) { +            synchronized (mLock) { +                Timer timer = removeLocked(arg); +                if (timer == null) { +                    notFoundLocked("discard", arg); +                    return false; +                } +                mTimerService.discard(timer); +                traceEnd(timer); +                if (DEBUG) report(timer, "discard"); +                timer.release(); +                return true; +            } +        } + +        /** The feature is enabled. */ +        boolean enabled() { +            return true; +        }      }      /** -     * Cancel a timer.  Return false if the timer was not found. +     * Start a timer associated with arg.  If a timer already exists with the same arg, then that +     * timer is canceled and a new timer is created.  This returns false if the timer cannot be +     * created. +     */ +    boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) { +        return mFeature.start(arg, pid, uid, timeoutMs); +    } + +    /** +     * Cancel a running timer and remove it from any list.  This returns true if the timer was +     * found and false otherwise.  It is not an error to cancel a non-existent timer.  It is also +     * not an error to cancel an expired timer.       */      boolean cancel(@NonNull V arg) { -        synchronized (mLock) { -            Timer timer = removeLocked(arg); -            if (timer == null) { -                if (!mLenientCancel) notFoundLocked("cancel", arg); -                return false; -            } -            mTimerService.cancel(timer); -            // There may be an expiration message in flight.  Cancel it. -            mHandler.removeMessages(mWhat, arg); -            if (DEBUG) report(timer, "cancel"); -            timer.release(); -            return true; -        } +        return mFeature.cancel(arg);      }      /** -     * Accept a timer in the framework-level handler.  The timeout has been accepted and the -     * timeout handler is executing.  Return false if the timer was not found. +     * Accept an expired timer.  This returns false if the timer was not found or if the timer was +     * not expired.       */      boolean accept(@NonNull V arg) { -        synchronized (mLock) { -            Timer timer = removeLocked(arg); -            if (timer == null) { -                notFoundLocked("accept", arg); -                return false; -            } -            mTimerService.accept(timer); -            traceEnd(timer); -            if (DEBUG) report(timer, "accept"); -            timer.release(); -            return true; -        } +        return mFeature.accept(arg);      }      /** -     * Discard a timer in the framework-level handler.  For whatever reason, the timer is no -     * longer interesting.  No statistics are collected.  Return false if the time was not found. +     * Discard an expired timer.  This returns false if the timer was not found or if the timer was +     * not expired.       */      boolean discard(@NonNull V arg) { -        synchronized (mLock) { -            Timer timer = removeLocked(arg); -            if (timer == null) { -                notFoundLocked("discard", arg); -                return false; -            } -            mTimerService.discard(timer); -            traceEnd(timer); -            if (DEBUG) report(timer, "discard"); -            timer.release(); -            return true; -        } +        return mFeature.discard(arg);      }      /** diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java index 907069de8c97..147f8d1a1e32 100644 --- a/services/core/java/com/android/server/am/AppBatteryTracker.java +++ b/services/core/java/com/android/server/am/AppBatteryTracker.java @@ -580,7 +580,11 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>                              batteryStatsInternal);              curDuration += curStart - lastUidBatteryUsageStartTs;              try { -                statsCommit.close(); +                if (statsCommit != null) { +                    statsCommit.close(); +                } else { +                    Slog.w(TAG, "Stat was null"); +                }              } catch (IOException e) {                  Slog.w(TAG, "Failed to close a stat");              } @@ -660,7 +664,11 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>              }          }          try { -            stats.close(); +            if (stats != null) { +                stats.close(); +            } else { +                Slog.w(TAG, "Stat was null"); +            }          } catch (IOException e) {              Slog.w(TAG, "Failed to close a stat");          } @@ -684,7 +692,11 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>          final BatteryUsageStats stats = statsList.get(0);          for (int i = 1; i < statsList.size(); i++) {              try { -                statsList.get(i).close(); +                if (statsList.get(i) != null) { +                    statsList.get(i).close(); +                } else { +                    Slog.w(TAG, "Stat was null"); +                }              } catch (IOException e) {                  Slog.w(TAG, "Failed to close a stat in BatteryUsageStats List");              } diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java index 5d31d1545b8d..e07c2bcaaaed 100644 --- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java +++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java @@ -106,6 +106,14 @@ class BroadcastProcessQueue {      private boolean mTimeoutScheduled;      /** +     * Snapshotted value of {@link ProcessRecord#getCpuDelayTime()}, typically +     * used when deciding if we should extend the soft ANR timeout. +     * +     * Required when Flags.anrTimerServiceEnabled is false. +     */ +    long lastCpuDelayTime; + +     /**       * Snapshotted value of {@link ProcessStateRecord#getCurProcState()} before       * dispatching the current broadcast to the receiver in this process.       */ diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index eb219a8819c6..a42890707368 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -258,6 +258,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue {      private static final int MSG_PROCESS_FREEZABLE_CHANGED = 6;      private static final int MSG_UID_STATE_CHANGED = 7; +    // Required when Flags.anrTimerServiceEnabled is false. +    private static final int MSG_DELIVERY_TIMEOUT_SOFT = 8; +      private void enqueueUpdateRunningList() {          mLocalHandler.removeMessages(MSG_UPDATE_RUNNING_LIST);          mLocalHandler.sendEmptyMessage(MSG_UPDATE_RUNNING_LIST); @@ -271,6 +274,13 @@ class BroadcastQueueModernImpl extends BroadcastQueue {                  updateRunningList();                  return true;              } +            // Required when Flags.anrTimerServiceEnabled is false. +            case MSG_DELIVERY_TIMEOUT_SOFT: { +                synchronized (mService) { +                    deliveryTimeoutSoftLocked((BroadcastProcessQueue) msg.obj, msg.arg1); +                    return true; +                } +            }              case MSG_DELIVERY_TIMEOUT: {                  deliveryTimeout((BroadcastProcessQueue) msg.obj);                  return true; @@ -1030,7 +1040,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {              queue.setTimeoutScheduled(true);              final int softTimeoutMillis = (int) (r.isForeground() ? mFgConstants.TIMEOUT                      : mBgConstants.TIMEOUT); -            mAnrTimer.start(queue, softTimeoutMillis); +            startDeliveryTimeoutLocked(queue, softTimeoutMillis);          } else {              queue.setTimeoutScheduled(false);          } @@ -1110,7 +1120,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {                  // If we were trying to deliver a manifest broadcast, throw the error as we need                  // to try redelivering the broadcast to this receiver.                  if (receiver instanceof ResolveInfo) { -                    mAnrTimer.cancel(queue); +                    cancelDeliveryTimeoutLocked(queue);                      throw new BroadcastDeliveryFailedException(e);                  }                  finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, @@ -1159,6 +1169,41 @@ class BroadcastQueueModernImpl extends BroadcastQueue {          r.resultTo = null;      } +    // Required when Flags.anrTimerServiceEnabled is false. +    private void startDeliveryTimeoutLocked(@NonNull BroadcastProcessQueue queue, +            int softTimeoutMillis) { +        if (mAnrTimer.serviceEnabled()) { +            mAnrTimer.start(queue, softTimeoutMillis); +        } else { +            queue.lastCpuDelayTime = queue.app.getCpuDelayTime(); +            mLocalHandler.sendMessageDelayed(Message.obtain(mLocalHandler, +                    MSG_DELIVERY_TIMEOUT_SOFT, softTimeoutMillis, 0, queue), softTimeoutMillis); +        } +    } + +    // Required when Flags.anrTimerServiceEnabled is false. +    private void cancelDeliveryTimeoutLocked(@NonNull BroadcastProcessQueue queue) { +        mAnrTimer.cancel(queue); +        if (!mAnrTimer.serviceEnabled()) { +            mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT_SOFT, queue); +        } +    } + +    // Required when Flags.anrTimerServiceEnabled is false. +    private void deliveryTimeoutSoftLocked(@NonNull BroadcastProcessQueue queue, +            int softTimeoutMillis) { +        if (queue.app != null) { +            // Instead of immediately triggering an ANR, extend the timeout by +            // the amount of time the process was runnable-but-waiting; we're +            // only willing to do this once before triggering an hard ANR +            final long cpuDelayTime = queue.app.getCpuDelayTime() - queue.lastCpuDelayTime; +            final long hardTimeoutMillis = MathUtils.constrain(cpuDelayTime, 0, softTimeoutMillis); +            mAnrTimer.start(queue, hardTimeoutMillis); +        } else { +            deliveryTimeoutLocked(queue); +        } +    } +      private void deliveryTimeout(@NonNull BroadcastProcessQueue queue) {          synchronized (mService) {              deliveryTimeoutLocked(queue); @@ -1292,7 +1337,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {                  mAnrTimer.discard(queue);              }          } else if (queue.timeoutScheduled()) { -            mAnrTimer.cancel(queue); +            cancelDeliveryTimeoutLocked(queue);          }          // Given that a receiver just finished, check if the "waitingFor" conditions are met. diff --git a/services/core/java/com/android/server/am/OomConnection.java b/services/core/java/com/android/server/am/OomConnection.java new file mode 100644 index 000000000000..17a4ce5b921c --- /dev/null +++ b/services/core/java/com/android/server/am/OomConnection.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.am; + +import android.os.OomKillRecord; +import android.util.Slog; + +/** Connection to the out-of-memory (OOM) events' file */ +public final class OomConnection { +    private static final String TAG = "OomConnection"; + +    /** Connection listener interface */ +    public interface OomConnectionListener { + +        /** +         * Callback function to handle the newest OOM kills. +         * +         * @param oomKills List of oom kills received from `waitOom()` +         */ +        void handleOomEvent(OomKillRecord[] oomKills); +    } + +    private final OomConnectionListener mOomListener; + +    private final OomConnectionThread mOomConnectionThread; + +    private static native OomKillRecord[] waitOom(); + +    public OomConnection(OomConnectionListener listener) { +        mOomListener = listener; +        mOomConnectionThread = new OomConnectionThread(); +        mOomConnectionThread.start(); +    } + +    private final class OomConnectionThread extends Thread { +        public void run() { +            while (true) { +                OomKillRecord[] oom_kills = null; +                try { +                    oom_kills = waitOom(); +                    mOomListener.handleOomEvent(oom_kills); +                } catch (RuntimeException e) { +                    Slog.e(TAG, "failed waiting for OOM events: " + e); +                    break; +                } +            } +        } +    } +} diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index a97675f1d776..4572766371ec 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -97,6 +97,7 @@ import android.os.Handler;  import android.os.IBinder;  import android.os.Looper;  import android.os.Message; +import android.os.OomKillRecord;  import android.os.PowerManager;  import android.os.Process;  import android.os.RemoteCallbackList; @@ -412,6 +413,8 @@ public final class ProcessList {      private static LmkdConnection sLmkdConnection = null; +    private static OomConnection sOomConnection = null; +      private boolean mOomLevelsSet = false;      private boolean mAppDataIsolationEnabled = false; @@ -855,6 +858,21 @@ public final class ProcessList {                      THREAD_PRIORITY_BACKGROUND, true /* allowIo */);              sKillThread.start();              sKillHandler = new KillHandler(sKillThread.getLooper()); +            sOomConnection = new OomConnection(new OomConnection.OomConnectionListener() { +                @Override +                public void handleOomEvent(OomKillRecord[] oomKills) { +                    for (OomKillRecord oomKill: oomKills) { +                        synchronized (mProcLock) { +                            noteAppKill( +                                oomKill.getPid(), +                                oomKill.getUid(), +                                ApplicationExitInfo.REASON_LOW_MEMORY, +                                ApplicationExitInfo.SUBREASON_OOM_KILL, +                                "oom"); +                        } +                    } +                } +            });              sLmkdConnection = new LmkdConnection(sKillThread.getLooper().getQueue(),                      new LmkdConnection.LmkdConnectionListener() {                          @Override diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index 4a0bc4b9ca6c..1ba1f55af71b 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -131,13 +131,17 @@ public class SettingsToPropertiesMapper {          "car_telemetry",          "codec_fwk",          "companion", +        "content_protection",          "context_hub",          "core_experiments_team_internal",          "core_graphics",          "haptics",          "hardware_backed_security_mainline", +        "input",          "machine_learning", +        "mainline_sdk",          "media_audio", +        "media_drm",          "media_solutions",          "nfc",          "pixel_audio_android", diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig index b03cc6295b8d..26d99d843c7e 100644 --- a/services/core/java/com/android/server/am/flags.aconfig +++ b/services/core/java/com/android/server/am/flags.aconfig @@ -6,4 +6,12 @@ flag {      description: "Utilize new OomAdjuster implementation"      bug: "298055811"      is_fixed_read_only: true -}
\ No newline at end of file +} + +flag { +     name: "anr_timer_service_enabled" +     namespace: "system_performance" +     is_fixed_read_only: true +     description: "Feature flag for the ANR timer service" +     bug: "282428924" +} diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java index 9805fd3d1316..333f62a81e94 100644 --- a/services/core/java/com/android/server/content/SyncStorageEngine.java +++ b/services/core/java/com/android/server/content/SyncStorageEngine.java @@ -1845,7 +1845,7 @@ public class SyncStorageEngine {      private void parseListenForTickles(TypedXmlPullParser parser) {          int userId = 0;          try { -            parser.getAttributeInt(null, XML_ATTR_USER); +            userId = parser.getAttributeInt(null, XML_ATTR_USER);          } catch (XmlPullParserException e) {              Slog.e(TAG, "error parsing the user for listen-for-tickles", e);          } diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index 9e92c8d7342d..cfbe0c69b320 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -60,6 +60,9 @@ import com.android.server.display.config.LuxThrottling;  import com.android.server.display.config.NitsMap;  import com.android.server.display.config.NonNegativeFloatToFloatPoint;  import com.android.server.display.config.Point; +import com.android.server.display.config.PowerThrottlingConfig; +import com.android.server.display.config.PowerThrottlingMap; +import com.android.server.display.config.PowerThrottlingPoint;  import com.android.server.display.config.PredefinedBrightnessLimitNames;  import com.android.server.display.config.RefreshRateConfigs;  import com.android.server.display.config.RefreshRateRange; @@ -139,6 +142,30 @@ import javax.xml.datatype.DatatypeConfigurationException;   *      </screenBrightnessMap>   *   *      <screenBrightnessDefault>0.65</screenBrightnessDefault> + *      <powerThrottlingConfig> + *        <brightnessLowestCapAllowed>0.1</brightnessLowestCapAllowed> + *        <pollingWindowMillis>15</pollingWindowMillis> + *          <powerThrottlingMap> + *              <powerThrottlingPoint> + *                  <thermalStatus>severe</thermalStatus> + *                  <powerQuotaMilliWatts>200.6</powerQuotaMilliWatts> + *              </powerThrottlingPoint> + *              <powerThrottlingPoint> + *                  <thermalStatus>critical</thermalStatus> + *                  <powerQuotaMilliWatts>300</powerQuotaMilliWatts> + *              </powerThrottlingPoint> + *          </powerThrottlingMap> + *          <powerThrottlingMap id="id_2"> // optional attribute, leave blank for default + *             <powerThrottlingPoint> + *                 <thermalStatus>moderate</thermalStatus> + *                 <powerQuotaMilliWatts>400</powerQuotaMilliWatts> + *             </powerThrottlingPoint> + *             <powerThrottlingPoint> + *                 <thermalStatus>severe</thermalStatus> + *                 <powerQuotaMilliWatts>250</powerQuotaMilliWatts> + *            </powerThrottlingPoint> + *          </powerThrottlingMap> + *      </powerThrottlingConfig>   *   *      <thermalThrottling>   *        <brightnessThrottlingMap> @@ -669,6 +696,8 @@ public class DisplayDeviceConfig {      private List<String> mQuirks;      private boolean mIsHighBrightnessModeEnabled = false;      private HighBrightnessModeData mHbmData; +    @Nullable +    private PowerThrottlingConfigData mPowerThrottlingConfigData;      private DensityMapping mDensityMapping;      private String mLoadedFrom = null;      private Spline mSdrToHdrRatioSpline; @@ -781,6 +810,9 @@ public class DisplayDeviceConfig {      private final HashMap<String, ThermalBrightnessThrottlingData>              mThermalBrightnessThrottlingDataMapByThrottlingId = new HashMap<>(); +    private final HashMap<String, PowerThrottlingData> +            mPowerThrottlingDataMapByThrottlingId = new HashMap<>(); +      private final Map<String, SparseArray<SurfaceControl.RefreshRateRange>>              mRefreshRateThrottlingMap = new HashMap<>(); @@ -1458,6 +1490,14 @@ public class DisplayDeviceConfig {          return hbmData;      } +    /** +     * @return Power throttling configuration data for the display. +     */ +    @Nullable +    public PowerThrottlingConfigData getPowerThrottlingConfigData() { +        return mPowerThrottlingConfigData; +    } +      @NonNull      public Map<BrightnessLimitMapType, Map<Float, Float>> getLuxThrottlingData() {          return mLuxThrottlingData; @@ -1491,6 +1531,14 @@ public class DisplayDeviceConfig {      }      /** +     * @return power throttling configuration data for this display, for each throttling id. +     **/ +    public HashMap<String, PowerThrottlingData> +            getPowerThrottlingDataMapByThrottlingId() { +        return mPowerThrottlingDataMapByThrottlingId; +    } + +    /**       * @return Auto brightness darkening light debounce       */      public long getAutoBrightnessDarkeningLightDebounce() { @@ -1702,6 +1750,9 @@ public class DisplayDeviceConfig {                  + ", mThermalBrightnessThrottlingDataMapByThrottlingId="                  + mThermalBrightnessThrottlingDataMapByThrottlingId                  + "\n" +                + ", mPowerThrottlingDataMapByThrottlingId=" +                + mPowerThrottlingDataMapByThrottlingId +                + "\n"                  + "mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease                  + ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease                  + ", mBrightnessRampSlowDecrease=" + mBrightnessRampSlowDecrease @@ -1853,6 +1904,7 @@ public class DisplayDeviceConfig {                  loadBrightnessConstraintsFromConfigXml();                  loadBrightnessMap(config);                  loadThermalThrottlingConfig(config); +                loadPowerThrottlingConfigData(config);                  loadHighBrightnessModeData(config);                  loadLuxThrottling(config);                  loadQuirks(config); @@ -2171,6 +2223,59 @@ public class DisplayDeviceConfig {          }      } +    private boolean loadPowerThrottlingMaps(PowerThrottlingConfig throttlingConfig) { +        final List<PowerThrottlingMap> maps = throttlingConfig.getPowerThrottlingMap(); +        if (maps == null || maps.isEmpty()) { +            Slog.i(TAG, "No power throttling map found"); +            return false; +        } + +        for (PowerThrottlingMap map : maps) { +            final List<PowerThrottlingPoint> points = map.getPowerThrottlingPoint(); +            // At least 1 point is guaranteed by the display device config schema +            List<PowerThrottlingData.ThrottlingLevel> throttlingLevels = +                    new ArrayList<>(points.size()); + +            boolean badConfig = false; +            for (PowerThrottlingPoint point : points) { +                ThermalStatus status = point.getThermalStatus(); +                if (!thermalStatusIsValid(status)) { +                    badConfig = true; +                    break; +                } + +                throttlingLevels.add(new PowerThrottlingData.ThrottlingLevel( +                        convertThermalStatus(status), +                            point.getPowerQuotaMilliWatts().floatValue())); +            } + +            if (!badConfig) { +                String id = map.getId() == null ? DEFAULT_ID : map.getId(); +                if (mPowerThrottlingDataMapByThrottlingId.containsKey(id)) { +                    throw new RuntimeException("Power throttling data with ID " + id +                            + " already exists"); +                } +                mPowerThrottlingDataMapByThrottlingId.put(id, +                        PowerThrottlingData.create(throttlingLevels)); +            } +        } +        return true; +    } + +    private void loadPowerThrottlingConfigData(DisplayConfiguration config) { +        final PowerThrottlingConfig powerThrottlingCfg = config.getPowerThrottlingConfig(); +        if (powerThrottlingCfg == null) { +            return; +        } +        if (!loadPowerThrottlingMaps(powerThrottlingCfg)) { +            return; +        } +        float lowestBrightnessCap = powerThrottlingCfg.getBrightnessLowestCapAllowed().floatValue(); +        int pollingWindowMillis = powerThrottlingCfg.getPollingWindowMillis().intValue(); +        mPowerThrottlingConfigData = new PowerThrottlingConfigData(lowestBrightnessCap, +                                                                   pollingWindowMillis); +    } +      private void loadRefreshRateSetting(DisplayConfiguration config) {          final RefreshRateConfigs refreshRateConfigs =                  (config == null) ? null : config.getRefreshRate(); @@ -3379,6 +3484,148 @@ public class DisplayDeviceConfig {      }      /** +     * Container for Power throttling configuration data. +     * TODO(b/302814899): extract to separate class. +     */ +    public static class PowerThrottlingConfigData { +        /** Lowest brightness cap allowed for this device. */ +        public final float brightnessLowestCapAllowed; +        /** Time window for polling power in seconds. */ +        public final int pollingWindowMillis; +        public PowerThrottlingConfigData(float brightnessLowestCapAllowed, +                int pollingWindowMillis) { +            this.brightnessLowestCapAllowed = brightnessLowestCapAllowed; +            this.pollingWindowMillis = pollingWindowMillis; +        } + +        @Override +        public String toString() { +            return "PowerThrottlingConfigData{" +                    + "brightnessLowestCapAllowed: " +                    + brightnessLowestCapAllowed +                    + ", pollingWindowMillis: " + pollingWindowMillis +                    + "} "; +        } +    } + +    /** +     * Container for power throttling data. +     * TODO(b/302814899): extract to separate class and unify with ThermalBrightnessThrottlingData. +     */ +    public static class PowerThrottlingData { +        public List<ThrottlingLevel> throttlingLevels; + +        /** +         * thermal status to power quota mapping. +         */ +        public static class ThrottlingLevel { +            public @PowerManager.ThermalStatus int thermalStatus; +            public float powerQuotaMilliWatts; + +            public ThrottlingLevel( +                    @PowerManager.ThermalStatus int thermalStatus, float powerQuotaMilliWatts) { +                this.thermalStatus = thermalStatus; +                this.powerQuotaMilliWatts = powerQuotaMilliWatts; +            } + +            @Override +            public String toString() { +                return "[" + thermalStatus + "," + powerQuotaMilliWatts + "]"; +            } + +            @Override +            public boolean equals(Object obj) { +                if (!(obj instanceof ThrottlingLevel)) { +                    return false; +                } +                ThrottlingLevel otherThrottlingLevel = (ThrottlingLevel) obj; + +                return otherThrottlingLevel.thermalStatus == this.thermalStatus +                        && otherThrottlingLevel.powerQuotaMilliWatts == this.powerQuotaMilliWatts; +            } + +            @Override +            public int hashCode() { +                int result = 1; +                result = 31 * result + thermalStatus; +                result = 31 * result + Float.hashCode(powerQuotaMilliWatts); +                return result; +            } +        } + + +        /** +         * Creates multiple temperature based throttling levels of power quota. +         */ +        public static PowerThrottlingData create( +                List<ThrottlingLevel> throttlingLevels) { +            if (throttlingLevels == null || throttlingLevels.size() == 0) { +                Slog.e(TAG, "PowerThrottlingData received null or empty throttling levels"); +                return null; +            } + +            ThrottlingLevel prevLevel = throttlingLevels.get(0); +            final int numLevels = throttlingLevels.size(); +            for (int i = 1; i < numLevels; i++) { +                ThrottlingLevel thisLevel = throttlingLevels.get(i); + +                if (thisLevel.thermalStatus <= prevLevel.thermalStatus) { +                    Slog.e(TAG, "powerThrottlingMap must be strictly increasing, ignoring " +                            + "configuration. ThermalStatus " + thisLevel.thermalStatus + " <= " +                            + prevLevel.thermalStatus); +                    return null; +                } + +                if (thisLevel.powerQuotaMilliWatts >= prevLevel.powerQuotaMilliWatts) { +                    Slog.e(TAG, "powerThrottlingMap must be strictly decreasing, ignoring " +                            + "configuration. powerQuotaMilliWatts " +                            + thisLevel.powerQuotaMilliWatts + " >= " +                            + prevLevel.powerQuotaMilliWatts); +                    return null; +                } + +                prevLevel = thisLevel; +            } +            return new PowerThrottlingData(throttlingLevels); +        } + +        @Override +        public String toString() { +            return "PowerThrottlingData{" +                    + "throttlingLevels:" + throttlingLevels +                    + "} "; +        } + +        @Override +        public boolean equals(Object obj) { +            if (this == obj) { +                return true; +            } + +            if (!(obj instanceof PowerThrottlingData)) { +                return false; +            } + +            PowerThrottlingData otherData = (PowerThrottlingData) obj; +            return throttlingLevels.equals(otherData.throttlingLevels); +        } + +        @Override +        public int hashCode() { +            return throttlingLevels.hashCode(); +        } + +        @VisibleForTesting +        PowerThrottlingData(List<ThrottlingLevel> inLevels) { +            throttlingLevels = new ArrayList<>(inLevels.size()); +            for (ThrottlingLevel level : inLevels) { +                throttlingLevels.add(new ThrottlingLevel(level.thermalStatus, +                        level.powerQuotaMilliWatts)); +            } +        } +    } + +    /**       * Container for brightness throttling data.       */      public static class ThermalBrightnessThrottlingData { diff --git a/services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java b/services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java index 652e6cfd67be..39f0b13f716a 100644 --- a/services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java +++ b/services/core/java/com/android/server/display/brightness/clamper/HdrClamper.java @@ -105,16 +105,21 @@ public class HdrClamper {      public void resetHdrConfig(HdrBrightnessData data, int width, int height,              float minimumHdrPercentOfScreen, IBinder displayToken) {          mHdrBrightnessData = data; -        mHdrListener.mHdrMinPixels = (float) (width * height) * minimumHdrPercentOfScreen; +        mHdrListener.mHdrMinPixels = minimumHdrPercentOfScreen <= 0 ? -1 +                : (float) (width * height) * minimumHdrPercentOfScreen;          if (displayToken != mRegisteredDisplayToken) { // token changed, resubscribe              if (mRegisteredDisplayToken != null) { // previous token not null, unsubscribe                  mHdrListener.unregister(mRegisteredDisplayToken);                  mHdrVisible = false; +                mRegisteredDisplayToken = null;              } -            if (displayToken != null) { // new token not null, subscribe +            // new token not null and hdr min % of the screen is set, subscribe. +            // e.g. for virtual display, HBM data will be missing and HdrListener +            // should not be registered +            if (displayToken != null && mHdrListener.mHdrMinPixels > 0) {                  mHdrListener.register(displayToken); +                mRegisteredDisplayToken = displayToken;              } -            mRegisteredDisplayToken = displayToken;          }          recalculateBrightnessCap(data, mAmbientLux, mHdrVisible);      } 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 b6273e1daf82..e66fa5b3d516 100644 --- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java @@ -51,22 +51,10 @@ public class DisplayManagerFlags {              Flags.FLAG_ENABLE_DISPLAY_OFFLOAD,              Flags::enableDisplayOffload); -    private final FlagState mDisplayResolutionRangeVotingState = new FlagState( -            Flags.FLAG_ENABLE_DISPLAY_RESOLUTION_RANGE_VOTING, -            Flags::enableDisplayResolutionRangeVoting); - -    private final FlagState mUserPreferredModeVoteState = new FlagState( -            Flags.FLAG_ENABLE_USER_PREFERRED_MODE_VOTE, -            Flags::enableUserPreferredModeVote); -      private final FlagState mExternalDisplayLimitModeState = new FlagState(              Flags.FLAG_ENABLE_MODE_LIMIT_FOR_EXTERNAL_DISPLAY,              Flags::enableModeLimitForExternalDisplay); -    private final FlagState mDisplaysRefreshRatesSynchronizationState = new FlagState( -            Flags.FLAG_ENABLE_DISPLAYS_REFRESH_RATES_SYNCHRONIZATION, -            Flags::enableDisplaysRefreshRatesSynchronization); -      /** Returns whether connected display management is enabled or not. */      public boolean isConnectedDisplayManagementEnabled() {          return mConnectedDisplayManagementFlagState.isEnabled(); @@ -90,7 +78,7 @@ public class DisplayManagerFlags {      /** Returns whether resolution range voting feature is enabled or not. */      public boolean isDisplayResolutionRangeVotingEnabled() { -        return mDisplayResolutionRangeVotingState.isEnabled(); +        return isExternalDisplayLimitModeEnabled();      }      /** @@ -98,7 +86,7 @@ public class DisplayManagerFlags {       *      {@link com.android.server.display.mode.DisplayModeDirector}       */      public boolean isUserPreferredModeVoteEnabled() { -        return mUserPreferredModeVoteState.isEnabled(); +        return isExternalDisplayLimitModeEnabled();      }      /** @@ -112,7 +100,7 @@ public class DisplayManagerFlags {       * @return Whether displays refresh rate synchronization is enabled.       */      public boolean isDisplaysRefreshRatesSynchronizationEnabled() { -        return mDisplaysRefreshRatesSynchronizationState.isEnabled(); +        return isExternalDisplayLimitModeEnabled();      }      /** Returns whether displayoffload is enabled on not */ @@ -150,19 +138,20 @@ public class DisplayManagerFlags {          }          private boolean flagOrSystemProperty(Supplier<Boolean> flagFunction, String flagName) { -            // TODO(b/299462337) Remove when the infrastructure is ready. -            if ((Build.IS_ENG || Build.IS_USERDEBUG) -                    && SystemProperties.getBoolean("persist.sys." + flagName, false)) { -                return true; -            } +            boolean flagValue = false;              try { -                return flagFunction.get(); +                flagValue = flagFunction.get();              } catch (Throwable ex) {                  if (DEBUG) {                      Slog.i(TAG, "Flags not ready yet. Return false for " + flagName, ex);                  } -                return false;              } +            // TODO(b/299462337) Remove when the infrastructure is ready. +            if (Build.IS_ENG || Build.IS_USERDEBUG) { +                return SystemProperties.getBoolean("persist.sys." + flagName + "-override", +                        flagValue); +            } +            return flagValue;          }      }  } diff --git a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java index 2ede56dcecd9..a2c8748a9142 100644 --- a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java +++ b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java @@ -62,10 +62,10 @@ class GestureMonitorSpyWindow {          mWindowHandle.ownerUid = uid;          mWindowHandle.scaleFactor = 1.0f;          mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */); -        mWindowHandle.inputConfig = -                InputConfig.NOT_FOCUSABLE | InputConfig.SPY | InputConfig.TRUSTED_OVERLAY; +        mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.SPY;          final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); +        mWindowHandle.setTrustedOverlay(t, mInputSurface, true);          t.setInputWindowInfo(mInputSurface, mWindowHandle);          t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_GESTURE_MONITOR);          t.setPosition(mInputSurface, 0, 0); diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 6b399def4d73..2533e0297679 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -117,6 +117,7 @@ import com.android.server.DisplayThread;  import com.android.server.LocalServices;  import com.android.server.Watchdog;  import com.android.server.input.InputManagerInternal.LidSwitchCallback; +import com.android.server.input.debug.FocusEventDebugView;  import com.android.server.inputmethod.InputMethodManagerInternal;  import com.android.server.policy.WindowManagerPolicy; diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java index 0eb620f3f4df..bad6bf0f0141 100644 --- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java +++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java @@ -71,6 +71,7 @@ import android.widget.Toast;  import com.android.internal.R;  import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting;  import com.android.internal.inputmethod.InputMethodSubtypeHandle;  import com.android.internal.messages.nano.SystemMessageProto;  import com.android.internal.notification.SystemNotificationChannels; @@ -99,7 +100,7 @@ import java.util.stream.Stream;   *   * @hide   */ -final class KeyboardLayoutManager implements InputManager.InputDeviceListener { +class KeyboardLayoutManager implements InputManager.InputDeviceListener {      private static final String TAG = "KeyboardLayoutManager"; @@ -1295,7 +1296,8 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {      }      @SuppressLint("MissingPermission") -    private List<ImeInfo> getImeInfoListForLayoutMapping() { +    @VisibleForTesting +    public List<ImeInfo> getImeInfoListForLayoutMapping() {          List<ImeInfo> imeInfoList = new ArrayList<>();          UserManager userManager = Objects.requireNonNull(                  mContext.getSystemService(UserManager.class)); @@ -1402,7 +1404,8 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {          }      } -    private static class ImeInfo { +    @VisibleForTesting +    public static class ImeInfo {          @UserIdInt int mUserId;          @NonNull InputMethodSubtypeHandle mImeSubtypeHandle;          @Nullable InputMethodSubtype mImeSubtype; diff --git a/services/core/java/com/android/server/input/FocusEventDebugGlobalMonitor.java b/services/core/java/com/android/server/input/debug/FocusEventDebugGlobalMonitor.java index 67c221f77037..2b21e49a4e03 100644 --- a/services/core/java/com/android/server/input/FocusEventDebugGlobalMonitor.java +++ b/services/core/java/com/android/server/input/debug/FocusEventDebugGlobalMonitor.java @@ -14,7 +14,7 @@   * limitations under the License.   */ -package com.android.server.input; +package com.android.server.input.debug;  import android.view.Display;  import android.view.InputEvent; @@ -22,6 +22,7 @@ import android.view.InputEventReceiver;  import android.view.MotionEvent;  import com.android.server.UiThread; +import com.android.server.input.InputManagerService;  /**   * Receives input events before they are dispatched and reports them to FocusEventDebugView. diff --git a/services/core/java/com/android/server/input/FocusEventDebugView.java b/services/core/java/com/android/server/input/debug/FocusEventDebugView.java index 4b8fabde7d35..6eec0dee9152 100644 --- a/services/core/java/com/android/server/input/FocusEventDebugView.java +++ b/services/core/java/com/android/server/input/debug/FocusEventDebugView.java @@ -14,7 +14,7 @@   * limitations under the License.   */ -package com.android.server.input; +package com.android.server.input.debug;  import static android.util.TypedValue.COMPLEX_UNIT_DIP;  import static android.util.TypedValue.COMPLEX_UNIT_SP; @@ -24,11 +24,9 @@ import android.animation.LayoutTransition;  import android.annotation.AnyThread;  import android.annotation.Nullable;  import android.content.Context; -import android.graphics.Canvas;  import android.graphics.Color;  import android.graphics.ColorFilter;  import android.graphics.ColorMatrixColorFilter; -import android.graphics.Paint;  import android.graphics.Typeface;  import android.util.DisplayMetrics;  import android.util.Pair; @@ -40,7 +38,6 @@ import android.view.KeyEvent;  import android.view.MotionEvent;  import android.view.RoundedCorner;  import android.view.View; -import android.view.ViewConfiguration;  import android.view.WindowInsets;  import android.view.animation.AccelerateInterpolator;  import android.widget.HorizontalScrollView; @@ -50,19 +47,17 @@ import android.widget.TextView;  import com.android.internal.R;  import com.android.internal.annotations.VisibleForTesting; +import com.android.server.input.InputManagerService;  import java.util.HashMap; -import java.util.Iterator; -import java.util.Locale;  import java.util.Map; -import java.util.concurrent.TimeUnit;  import java.util.function.Supplier;  /**   *  Displays focus events, such as physical keyboard KeyEvents and non-pointer MotionEvents on   *  the screen.   */ -class FocusEventDebugView extends RelativeLayout { +public class FocusEventDebugView extends RelativeLayout {      private static final String TAG = FocusEventDebugView.class.getSimpleName(); @@ -112,7 +107,7 @@ class FocusEventDebugView extends RelativeLayout {          mOuterPadding = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, OUTER_PADDING_DP, mDm);      } -    FocusEventDebugView(Context c, InputManagerService service) { +    public FocusEventDebugView(Context c, InputManagerService service) {          this(c, service, () -> new RotaryInputValueView(c), () -> new RotaryInputGraphView(c));      } @@ -149,11 +144,13 @@ class FocusEventDebugView extends RelativeLayout {          return super.dispatchKeyEvent(event);      } +    /** Determines whether to show the key presses visualization. */      @AnyThread      public void updateShowKeyPresses(boolean enabled) {          post(() -> handleUpdateShowKeyPresses(enabled));      } +    /** Determines whether to show the rotary input visualization. */      @AnyThread      public void updateShowRotaryInput(boolean enabled) {          post(() -> handleUpdateShowRotaryInput(enabled)); @@ -358,13 +355,6 @@ class FocusEventDebugView extends RelativeLayout {          return mRotaryInputValueView != null;      } -    /** -     * Converts a dimension in scaled pixel units to integer display pixels. -     */ -    private static int applyDimensionSp(int dimensionSp, DisplayMetrics dm) { -        return (int) TypedValue.applyDimension(COMPLEX_UNIT_SP, dimensionSp, dm); -    } -      private static class PressedKeyView extends TextView {          private static final ColorFilter sInvertColors = new ColorMatrixColorFilter(new float[]{ @@ -473,376 +463,4 @@ class FocusEventDebugView extends RelativeLayout {              invalidate();          }      } - -    // TODO(b/286086154): move RotaryInputGraphView and RotaryInputValueView to a subpackage. - -    /** Draws the most recent rotary input value and indicates whether the source is active. */ -    @VisibleForTesting -    static class RotaryInputValueView extends TextView { - -        private static final int INACTIVE_TEXT_COLOR = 0xffff00ff; -        private static final int ACTIVE_TEXT_COLOR = 0xff420f28; -        private static final int TEXT_SIZE_SP = 8; -        private static final int SIDE_PADDING_SP = 4; -        /** Determines how long the active status lasts. */ -        private static final int ACTIVE_STATUS_DURATION = 250 /* milliseconds */; -        private static final ColorFilter ACTIVE_BACKGROUND_FILTER = -                new ColorMatrixColorFilter(new float[]{ -                        0, 0, 0, 0, 255, // red -                        0, 0, 0, 0,   0, // green -                        0, 0, 0, 0, 255, // blue -                        0, 0, 0, 0, 200  // alpha -                }); - -        private final Runnable mUpdateActivityStatusCallback = () -> updateActivityStatus(false); -        private final float mScaledVerticalScrollFactor; - -        @VisibleForTesting -        RotaryInputValueView(Context c) { -            super(c); - -            DisplayMetrics dm = mContext.getResources().getDisplayMetrics(); -            mScaledVerticalScrollFactor = ViewConfiguration.get(c).getScaledVerticalScrollFactor(); - -            setText(getFormattedValue(0)); -            setTextColor(INACTIVE_TEXT_COLOR); -            setTextSize(applyDimensionSp(TEXT_SIZE_SP, dm)); -            setPaddingRelative(applyDimensionSp(SIDE_PADDING_SP, dm), 0, -                    applyDimensionSp(SIDE_PADDING_SP, dm), 0); -            setTypeface(null, Typeface.BOLD); -            setBackgroundResource(R.drawable.focus_event_rotary_input_background); -        } - -        void updateValue(float value) { -            removeCallbacks(mUpdateActivityStatusCallback); - -            setText(getFormattedValue(value * mScaledVerticalScrollFactor)); - -            updateActivityStatus(true); -            postDelayed(mUpdateActivityStatusCallback, ACTIVE_STATUS_DURATION); -        } - -        @VisibleForTesting -        void updateActivityStatus(boolean active) { -            if (active) { -                setTextColor(ACTIVE_TEXT_COLOR); -                getBackground().setColorFilter(ACTIVE_BACKGROUND_FILTER); -            } else { -                setTextColor(INACTIVE_TEXT_COLOR); -                getBackground().clearColorFilter(); -            } -        } - -        private static String getFormattedValue(float value) { -            return String.format("%s%.1f", value < 0 ? "-" : "+", Math.abs(value)); -        } -    } - -    /** -     * Shows a graph with the rotary input values as a function of time. -     * The graph gets reset if no action is received for a certain amount of time. -     */ -    @VisibleForTesting -    static class RotaryInputGraphView extends View { - -        private static final int FRAME_COLOR = 0xbf741b47; -        private static final int FRAME_WIDTH_SP = 2; -        private static final int FRAME_BORDER_GAP_SP = 10; -        private static final int FRAME_TEXT_SIZE_SP = 10; -        private static final int FRAME_TEXT_OFFSET_SP = 2; -        private static final int GRAPH_COLOR = 0xffff00ff; -        private static final int GRAPH_LINE_WIDTH_SP = 1; -        private static final int GRAPH_POINT_RADIUS_SP = 4; -        private static final long MAX_SHOWN_TIME_INTERVAL = TimeUnit.SECONDS.toMillis(5); -        private static final float DEFAULT_FRAME_CENTER_POSITION = 0; -        private static final int MAX_GRAPH_VALUES_SIZE = 400; -        /** Maximum time between values so that they are considered part of the same gesture. */ -        private static final long MAX_GESTURE_TIME = TimeUnit.SECONDS.toMillis(1); - -        private final DisplayMetrics mDm; -        /** -         * Distance in position units (amount scrolled in display pixels) from the center to the -         * top/bottom frame lines. -         */ -        private final float mFrameCenterToBorderDistance; -        private final float mScaledVerticalScrollFactor; -        private final Locale mDefaultLocale; -        private final Paint mFramePaint = new Paint(); -        private final Paint mFrameTextPaint = new Paint(); -        private final Paint mGraphLinePaint = new Paint(); -        private final Paint mGraphPointPaint = new Paint(); - -        private final CyclicBuffer mGraphValues = new CyclicBuffer(MAX_GRAPH_VALUES_SIZE); -        /** Position at which graph values are placed at the center of the graph. */ -        private float mFrameCenterPosition = DEFAULT_FRAME_CENTER_POSITION; - -        @VisibleForTesting -        RotaryInputGraphView(Context c) { -            super(c); - -            mDm = mContext.getResources().getDisplayMetrics(); -            // This makes the center-to-border distance equivalent to the display height, meaning -            // that the total height of the graph is equivalent to 2x the display height. -            mFrameCenterToBorderDistance = mDm.heightPixels; -            mScaledVerticalScrollFactor = ViewConfiguration.get(c).getScaledVerticalScrollFactor(); -            mDefaultLocale = Locale.getDefault(); - -            mFramePaint.setColor(FRAME_COLOR); -            mFramePaint.setStrokeWidth(applyDimensionSp(FRAME_WIDTH_SP, mDm)); - -            mFrameTextPaint.setColor(GRAPH_COLOR); -            mFrameTextPaint.setTextSize(applyDimensionSp(FRAME_TEXT_SIZE_SP, mDm)); - -            mGraphLinePaint.setColor(GRAPH_COLOR); -            mGraphLinePaint.setStrokeWidth(applyDimensionSp(GRAPH_LINE_WIDTH_SP, mDm)); -            mGraphLinePaint.setStrokeCap(Paint.Cap.ROUND); -            mGraphLinePaint.setStrokeJoin(Paint.Join.ROUND); - -            mGraphPointPaint.setColor(GRAPH_COLOR); -            mGraphPointPaint.setStrokeWidth(applyDimensionSp(GRAPH_POINT_RADIUS_SP, mDm)); -            mGraphPointPaint.setStrokeCap(Paint.Cap.ROUND); -            mGraphPointPaint.setStrokeJoin(Paint.Join.ROUND); -        } - -        /** -         * Reads new scroll axis value and updates the list accordingly. Old positions are -         * kept at the front (what you would get with getFirst), while the recent positions are -         * kept at the back (what you would get with getLast). Also updates the frame center -         * position to handle out-of-bounds cases. -         */ -        void addValue(float scrollAxisValue, long eventTime) { -            // Remove values that are too old. -            while (mGraphValues.getSize() > 0 -                    && (eventTime - mGraphValues.getFirst().mTime) > MAX_SHOWN_TIME_INTERVAL) { -                mGraphValues.removeFirst(); -            } - -            // If there are no recent values, reset the frame center. -            if (mGraphValues.getSize() == 0) { -                mFrameCenterPosition = DEFAULT_FRAME_CENTER_POSITION; -            } - -            // Handle new value. We multiply the scroll axis value by the scaled scroll factor to -            // get the amount of pixels to be scrolled. We also compute the accumulated position -            // by adding the current value to the last one (if not empty). -            final float displacement = scrollAxisValue * mScaledVerticalScrollFactor; -            final float prevPos = (mGraphValues.getSize() == 0 ? 0 : mGraphValues.getLast().mPos); -            final float pos = prevPos + displacement; - -            mGraphValues.add(pos, eventTime); - -            // The difference between the distance of the most recent position from the center -            // frame (pos - mFrameCenterPosition) and the maximum allowed distance from the center -            // frame (mFrameCenterToBorderDistance). -            final float verticalDiff = Math.abs(pos - mFrameCenterPosition) -                    - mFrameCenterToBorderDistance; -            // If needed, translate frame. -            if (verticalDiff > 0) { -                final int sign = pos - mFrameCenterPosition < 0 ? -1 : 1; -                // Here, we update the center frame position by the exact amount needed for us to -                // stay within the maximum allowed distance from the center frame. -                mFrameCenterPosition += sign * verticalDiff; -            } - -            // Redraw canvas. -            invalidate(); -        } - -        @Override -        protected void onDraw(Canvas canvas) { -            super.onDraw(canvas); - -            // Note: vertical coordinates in Canvas go from top to bottom, -            // that is bottomY > middleY > topY. -            final int verticalMargin = applyDimensionSp(FRAME_BORDER_GAP_SP, mDm); -            final int topY = verticalMargin; -            final int bottomY = getHeight() - verticalMargin; -            final int middleY = (topY + bottomY) / 2; - -            // Note: horizontal coordinates in Canvas go from left to right, -            // that is rightX > leftX. -            final int leftX = 0; -            final int rightX = getWidth(); - -            // Draw the frame, which includes 3 lines that show the maximum, -            // minimum and middle positions of the graph. -            canvas.drawLine(leftX, topY, rightX, topY, mFramePaint); -            canvas.drawLine(leftX, middleY, rightX, middleY, mFramePaint); -            canvas.drawLine(leftX, bottomY, rightX, bottomY, mFramePaint); - -            // Draw the position that each frame line corresponds to. -            final int frameTextOffset = applyDimensionSp(FRAME_TEXT_OFFSET_SP, mDm); -            canvas.drawText( -                    String.format(mDefaultLocale, "%.1f", -                            mFrameCenterPosition + mFrameCenterToBorderDistance), -                    leftX, -                    topY - frameTextOffset, mFrameTextPaint -            ); -            canvas.drawText( -                    String.format(mDefaultLocale, "%.1f", mFrameCenterPosition), -                    leftX, -                    middleY - frameTextOffset, mFrameTextPaint -            ); -            canvas.drawText( -                    String.format(mDefaultLocale, "%.1f", -                            mFrameCenterPosition - mFrameCenterToBorderDistance), -                    leftX, -                    bottomY - frameTextOffset, mFrameTextPaint -            ); - -            // If there are no graph values to be drawn, stop here. -            if (mGraphValues.getSize() == 0) { -                return; -            } - -            // Draw the graph using the times and positions. -            // We start at the most recent value (which should be drawn at the right) and move -            // to the older values (which should be drawn to the left of more recent ones). Negative -            // indices are handled by circuling back to the end of the buffer. -            final long mostRecentTime = mGraphValues.getLast().mTime; -            float prevCoordX = 0; -            float prevCoordY = 0; -            float prevAge = 0; -            for (Iterator<GraphValue> iter = mGraphValues.reverseIterator(); iter.hasNext();) { -                final GraphValue value = iter.next(); - -                final int age = (int) (mostRecentTime - value.mTime); -                final float pos = value.mPos; - -                // We get the horizontal coordinate in time units from left to right with -                // (MAX_SHOWN_TIME_INTERVAL - age). Then, we rescale it to match the canvas -                // units by dividing it by the time-domain length (MAX_SHOWN_TIME_INTERVAL) -                // and by multiplying it by the canvas length (rightX - leftX). Finally, we -                // offset the coordinate by adding it to leftX. -                final float coordX = leftX + ((float) (MAX_SHOWN_TIME_INTERVAL - age) -                        / MAX_SHOWN_TIME_INTERVAL) * (rightX - leftX); - -                // We get the vertical coordinate in position units from middle to top with -                // (pos - mFrameCenterPosition). Then, we rescale it to match the canvas -                // units by dividing it by half of the position-domain length -                // (mFrameCenterToBorderDistance) and by multiplying it by half of the canvas -                // length (middleY - topY). Finally, we offset the coordinate by subtracting -                // it from middleY (we can't "add" here because the coordinate grows from top -                // to bottom). -                final float coordY = middleY - ((pos - mFrameCenterPosition) -                        / mFrameCenterToBorderDistance) * (middleY - topY); - -                // Draw a point for this value. -                canvas.drawPoint(coordX, coordY, mGraphPointPaint); - -                // If this value is part of the same gesture as the previous one, draw a line -                // between them. We ignore the first value (with age = 0). -                if (age != 0 && (age - prevAge) <= MAX_GESTURE_TIME) { -                    canvas.drawLine(prevCoordX, prevCoordY, coordX, coordY, mGraphLinePaint); -                } - -                prevCoordX = coordX; -                prevCoordY = coordY; -                prevAge = age; -            } -        } - -        @VisibleForTesting -        float getFrameCenterPosition() { -            return mFrameCenterPosition; -        } - -        /** -         * Holds data needed to draw each entry in the graph. -         */ -        private static class GraphValue { -            /** Position. */ -            float mPos; -            /** Time when this value was added. */ -            long mTime; - -            GraphValue(float pos, long time) { -                this.mPos = pos; -                this.mTime = time; -            } -        } - -        /** -         * Holds the graph values as a cyclic buffer. It has a fixed capacity, and it replaces the -         * old values with new ones to avoid creating new objects. -         */ -        private static class CyclicBuffer { -            private final GraphValue[] mValues; -            private final int mCapacity; -            private int mSize = 0; -            private int mLastIndex = 0; - -            // The iteration index and counter are here to make it easier to reset them. -            /** Determines the value currently pointed by the iterator. */ -            private int mIteratorIndex; -            /** Counts how many values have been iterated through. */ -            private int mIteratorCount; - -            /** Used traverse the values in reverse order. */ -            private final Iterator<GraphValue> mReverseIterator = new Iterator<GraphValue>() { -                @Override -                public boolean hasNext() { -                    return mIteratorCount <= mSize; -                } - -                @Override -                public GraphValue next() { -                    // Returns the value currently pointed by the iterator and moves the iterator to -                    // the previous one. -                    mIteratorCount++; -                    return mValues[(mIteratorIndex-- + mCapacity) % mCapacity]; -                } -            }; - -            CyclicBuffer(int capacity) { -                mCapacity = capacity; -                mValues = new GraphValue[capacity]; -            } - -            /** -             * Add new graph value. If there is an existing object, we replace its data with the -             * new one. With this, we re-use old objects instead of creating new ones. -             */ -            void add(float pos, long time) { -                mLastIndex = (mLastIndex + 1) % mCapacity; -                if (mValues[mLastIndex] == null) { -                    mValues[mLastIndex] = new GraphValue(pos, time); -                } else { -                    final GraphValue oldValue = mValues[mLastIndex]; -                    oldValue.mPos = pos; -                    oldValue.mTime = time; -                } - -                // If needed, account for new value in the buffer size. -                if (mSize != mCapacity) { -                    mSize++; -                } -            } - -            int getSize() { -                return mSize; -            } - -            GraphValue getFirst() { -                final int distanceBetweenLastAndFirst = (mCapacity - mSize) + 1; -                final int firstIndex = (mLastIndex + distanceBetweenLastAndFirst) % mCapacity; -                return mValues[firstIndex]; -            } - -            GraphValue getLast() { -                return mValues[mLastIndex]; -            } - -            void removeFirst() { -                mSize--; -            } - -            /** Returns an iterator pointing at the last value. */ -            Iterator<GraphValue> reverseIterator() { -                mIteratorIndex = mLastIndex; -                mIteratorCount = 1; -                return mReverseIterator; -            } -        } -    }  } diff --git a/services/core/java/com/android/server/input/debug/RotaryInputGraphView.java b/services/core/java/com/android/server/input/debug/RotaryInputGraphView.java new file mode 100644 index 000000000000..95635d925855 --- /dev/null +++ b/services/core/java/com/android/server/input/debug/RotaryInputGraphView.java @@ -0,0 +1,342 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.input.debug; + +import static android.util.TypedValue.COMPLEX_UNIT_SP; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewConfiguration; + +import java.util.Iterator; +import java.util.Locale; +import java.util.concurrent.TimeUnit; + +/** + * Shows a graph with the rotary input values as a function of time. + * The graph gets reset if no action is received for a certain amount of time. + */ +public class RotaryInputGraphView extends View { + +    private static final int FRAME_COLOR = 0xbf741b47; +    private static final int FRAME_WIDTH_SP = 2; +    private static final int FRAME_BORDER_GAP_SP = 10; +    private static final int FRAME_TEXT_SIZE_SP = 10; +    private static final int FRAME_TEXT_OFFSET_SP = 2; +    private static final int GRAPH_COLOR = 0xffff00ff; +    private static final int GRAPH_LINE_WIDTH_SP = 1; +    private static final int GRAPH_POINT_RADIUS_SP = 4; +    private static final long MAX_SHOWN_TIME_INTERVAL = TimeUnit.SECONDS.toMillis(5); +    private static final float DEFAULT_FRAME_CENTER_POSITION = 0; +    private static final int MAX_GRAPH_VALUES_SIZE = 400; +    /** Maximum time between values so that they are considered part of the same gesture. */ +    private static final long MAX_GESTURE_TIME = TimeUnit.SECONDS.toMillis(1); + +    private final DisplayMetrics mDm; +    /** +     * Distance in position units (amount scrolled in display pixels) from the center to the +     * top/bottom frame lines. +     */ +    private final float mFrameCenterToBorderDistance; +    private final float mScaledVerticalScrollFactor; +    private final Locale mDefaultLocale = Locale.getDefault(); +    private final Paint mFramePaint = new Paint(); +    private final Paint mFrameTextPaint = new Paint(); +    private final Paint mGraphLinePaint = new Paint(); +    private final Paint mGraphPointPaint = new Paint(); + +    private final CyclicBuffer mGraphValues = new CyclicBuffer(MAX_GRAPH_VALUES_SIZE); +    /** Position at which graph values are placed at the center of the graph. */ +    private float mFrameCenterPosition = DEFAULT_FRAME_CENTER_POSITION; + +    public RotaryInputGraphView(Context c) { +        super(c); + +        mDm = mContext.getResources().getDisplayMetrics(); +        // This makes the center-to-border distance equivalent to the display height, meaning +        // that the total height of the graph is equivalent to 2x the display height. +        mFrameCenterToBorderDistance = mDm.heightPixels; +        mScaledVerticalScrollFactor = ViewConfiguration.get(c).getScaledVerticalScrollFactor(); + +        mFramePaint.setColor(FRAME_COLOR); +        mFramePaint.setStrokeWidth(applyDimensionSp(FRAME_WIDTH_SP, mDm)); + +        mFrameTextPaint.setColor(GRAPH_COLOR); +        mFrameTextPaint.setTextSize(applyDimensionSp(FRAME_TEXT_SIZE_SP, mDm)); + +        mGraphLinePaint.setColor(GRAPH_COLOR); +        mGraphLinePaint.setStrokeWidth(applyDimensionSp(GRAPH_LINE_WIDTH_SP, mDm)); +        mGraphLinePaint.setStrokeCap(Paint.Cap.ROUND); +        mGraphLinePaint.setStrokeJoin(Paint.Join.ROUND); + +        mGraphPointPaint.setColor(GRAPH_COLOR); +        mGraphPointPaint.setStrokeWidth(applyDimensionSp(GRAPH_POINT_RADIUS_SP, mDm)); +        mGraphPointPaint.setStrokeCap(Paint.Cap.ROUND); +        mGraphPointPaint.setStrokeJoin(Paint.Join.ROUND); +    } + +    /** +     * Reads new scroll axis value and updates the list accordingly. Old positions are +     * kept at the front (what you would get with getFirst), while the recent positions are +     * kept at the back (what you would get with getLast). Also updates the frame center +     * position to handle out-of-bounds cases. +     */ +    public void addValue(float scrollAxisValue, long eventTime) { +        // Remove values that are too old. +        while (mGraphValues.getSize() > 0 +                && (eventTime - mGraphValues.getFirst().mTime) > MAX_SHOWN_TIME_INTERVAL) { +            mGraphValues.removeFirst(); +        } + +        // If there are no recent values, reset the frame center. +        if (mGraphValues.getSize() == 0) { +            mFrameCenterPosition = DEFAULT_FRAME_CENTER_POSITION; +        } + +        // Handle new value. We multiply the scroll axis value by the scaled scroll factor to +        // get the amount of pixels to be scrolled. We also compute the accumulated position +        // by adding the current value to the last one (if not empty). +        final float displacement = scrollAxisValue * mScaledVerticalScrollFactor; +        final float prevPos = (mGraphValues.getSize() == 0 ? 0 : mGraphValues.getLast().mPos); +        final float pos = prevPos + displacement; + +        mGraphValues.add(pos, eventTime); + +        // The difference between the distance of the most recent position from the center +        // frame (pos - mFrameCenterPosition) and the maximum allowed distance from the center +        // frame (mFrameCenterToBorderDistance). +        final float verticalDiff = Math.abs(pos - mFrameCenterPosition) +                - mFrameCenterToBorderDistance; +        // If needed, translate frame. +        if (verticalDiff > 0) { +            final int sign = pos - mFrameCenterPosition < 0 ? -1 : 1; +            // Here, we update the center frame position by the exact amount needed for us to +            // stay within the maximum allowed distance from the center frame. +            mFrameCenterPosition += sign * verticalDiff; +        } + +        // Redraw canvas. +        invalidate(); +    } + +    @Override +    protected void onDraw(Canvas canvas) { +        super.onDraw(canvas); + +        // Note: vertical coordinates in Canvas go from top to bottom, +        // that is bottomY > middleY > topY. +        final int verticalMargin = applyDimensionSp(FRAME_BORDER_GAP_SP, mDm); +        final int topY = verticalMargin; +        final int bottomY = getHeight() - verticalMargin; +        final int middleY = (topY + bottomY) / 2; + +        // Note: horizontal coordinates in Canvas go from left to right, +        // that is rightX > leftX. +        final int leftX = 0; +        final int rightX = getWidth(); + +        // Draw the frame, which includes 3 lines that show the maximum, +        // minimum and middle positions of the graph. +        canvas.drawLine(leftX, topY, rightX, topY, mFramePaint); +        canvas.drawLine(leftX, middleY, rightX, middleY, mFramePaint); +        canvas.drawLine(leftX, bottomY, rightX, bottomY, mFramePaint); + +        // Draw the position that each frame line corresponds to. +        final int frameTextOffset = applyDimensionSp(FRAME_TEXT_OFFSET_SP, mDm); +        canvas.drawText( +                String.format(mDefaultLocale, "%.1f", +                        mFrameCenterPosition + mFrameCenterToBorderDistance), +                leftX, +                topY - frameTextOffset, mFrameTextPaint +        ); +        canvas.drawText( +                String.format(mDefaultLocale, "%.1f", mFrameCenterPosition), +                leftX, +                middleY - frameTextOffset, mFrameTextPaint +        ); +        canvas.drawText( +                String.format(mDefaultLocale, "%.1f", +                        mFrameCenterPosition - mFrameCenterToBorderDistance), +                leftX, +                bottomY - frameTextOffset, mFrameTextPaint +        ); + +        // If there are no graph values to be drawn, stop here. +        if (mGraphValues.getSize() == 0) { +            return; +        } + +        // Draw the graph using the times and positions. +        // We start at the most recent value (which should be drawn at the right) and move +        // to the older values (which should be drawn to the left of more recent ones). Negative +        // indices are handled by circuling back to the end of the buffer. +        final long mostRecentTime = mGraphValues.getLast().mTime; +        float prevCoordX = 0; +        float prevCoordY = 0; +        float prevAge = 0; +        for (Iterator<GraphValue> iter = mGraphValues.reverseIterator(); iter.hasNext();) { +            final GraphValue value = iter.next(); + +            final int age = (int) (mostRecentTime - value.mTime); +            final float pos = value.mPos; + +            // We get the horizontal coordinate in time units from left to right with +            // (MAX_SHOWN_TIME_INTERVAL - age). Then, we rescale it to match the canvas +            // units by dividing it by the time-domain length (MAX_SHOWN_TIME_INTERVAL) +            // and by multiplying it by the canvas length (rightX - leftX). Finally, we +            // offset the coordinate by adding it to leftX. +            final float coordX = leftX + ((float) (MAX_SHOWN_TIME_INTERVAL - age) +                    / MAX_SHOWN_TIME_INTERVAL) * (rightX - leftX); + +            // We get the vertical coordinate in position units from middle to top with +            // (pos - mFrameCenterPosition). Then, we rescale it to match the canvas +            // units by dividing it by half of the position-domain length +            // (mFrameCenterToBorderDistance) and by multiplying it by half of the canvas +            // length (middleY - topY). Finally, we offset the coordinate by subtracting +            // it from middleY (we can't "add" here because the coordinate grows from top +            // to bottom). +            final float coordY = middleY - ((pos - mFrameCenterPosition) +                    / mFrameCenterToBorderDistance) * (middleY - topY); + +            // Draw a point for this value. +            canvas.drawPoint(coordX, coordY, mGraphPointPaint); + +            // If this value is part of the same gesture as the previous one, draw a line +            // between them. We ignore the first value (with age = 0). +            if (age != 0 && (age - prevAge) <= MAX_GESTURE_TIME) { +                canvas.drawLine(prevCoordX, prevCoordY, coordX, coordY, mGraphLinePaint); +            } + +            prevCoordX = coordX; +            prevCoordY = coordY; +            prevAge = age; +        } +    } + +    public float getFrameCenterPosition() { +        return mFrameCenterPosition; +    } + +    /** +     * Converts a dimension in scaled pixel units to integer display pixels. +     */ +    private static int applyDimensionSp(int dimensionSp, DisplayMetrics dm) { +        return (int) TypedValue.applyDimension(COMPLEX_UNIT_SP, dimensionSp, dm); +    } + +    /** +     * Holds data needed to draw each entry in the graph. +     */ +    private static class GraphValue { +        /** Position. */ +        float mPos; +        /** Time when this value was added. */ +        long mTime; + +        GraphValue(float pos, long time) { +            this.mPos = pos; +            this.mTime = time; +        } +    } + +    /** +     * Holds the graph values as a cyclic buffer. It has a fixed capacity, and it replaces the +     * old values with new ones to avoid creating new objects. +     */ +    private static class CyclicBuffer { +        private final GraphValue[] mValues; +        private final int mCapacity; +        private int mSize = 0; +        private int mLastIndex = 0; + +        // The iteration index and counter are here to make it easier to reset them. +        /** Determines the value currently pointed by the iterator. */ +        private int mIteratorIndex; +        /** Counts how many values have been iterated through. */ +        private int mIteratorCount; + +        /** Used traverse the values in reverse order. */ +        private final Iterator<GraphValue> mReverseIterator = new Iterator<GraphValue>() { +            @Override +            public boolean hasNext() { +                return mIteratorCount <= mSize; +            } + +            @Override +            public GraphValue next() { +                // Returns the value currently pointed by the iterator and moves the iterator to +                // the previous one. +                mIteratorCount++; +                return mValues[(mIteratorIndex-- + mCapacity) % mCapacity]; +            } +        }; + +        CyclicBuffer(int capacity) { +            mCapacity = capacity; +            mValues = new GraphValue[capacity]; +        } + +        /** +         * Add new graph value. If there is an existing object, we replace its data with the +         * new one. With this, we re-use old objects instead of creating new ones. +         */ +        void add(float pos, long time) { +            mLastIndex = (mLastIndex + 1) % mCapacity; +            if (mValues[mLastIndex] == null) { +                mValues[mLastIndex] = new GraphValue(pos, time); +            } else { +                final GraphValue oldValue = mValues[mLastIndex]; +                oldValue.mPos = pos; +                oldValue.mTime = time; +            } + +            // If needed, account for new value in the buffer size. +            if (mSize != mCapacity) { +                mSize++; +            } +        } + +        int getSize() { +            return mSize; +        } + +        GraphValue getFirst() { +            final int distanceBetweenLastAndFirst = (mCapacity - mSize) + 1; +            final int firstIndex = (mLastIndex + distanceBetweenLastAndFirst) % mCapacity; +            return mValues[firstIndex]; +        } + +        GraphValue getLast() { +            return mValues[mLastIndex]; +        } + +        void removeFirst() { +            mSize--; +        } + +        /** Returns an iterator pointing at the last value. */ +        Iterator<GraphValue> reverseIterator() { +            mIteratorIndex = mLastIndex; +            mIteratorCount = 1; +            return mReverseIterator; +        } +    } +} diff --git a/services/core/java/com/android/server/input/debug/RotaryInputValueView.java b/services/core/java/com/android/server/input/debug/RotaryInputValueView.java new file mode 100644 index 000000000000..9fadac57cef9 --- /dev/null +++ b/services/core/java/com/android/server/input/debug/RotaryInputValueView.java @@ -0,0 +1,103 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.input.debug; + +import static android.util.TypedValue.COMPLEX_UNIT_SP; + +import android.content.Context; +import android.graphics.ColorFilter; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.Typeface; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.ViewConfiguration; +import android.widget.TextView; + +import com.android.internal.R; + +import java.util.Locale; + +/** + * Draws the most recent rotary input value and indicates whether the source is active. + */ +public class RotaryInputValueView extends TextView { + +    private static final int INACTIVE_TEXT_COLOR = 0xffff00ff; +    private static final int ACTIVE_TEXT_COLOR = 0xff420f28; +    private static final int TEXT_SIZE_SP = 8; +    private static final int SIDE_PADDING_SP = 4; +    /** Determines how long the active status lasts. */ +    private static final int ACTIVE_STATUS_DURATION = 250 /* milliseconds */; +    private static final ColorFilter ACTIVE_BACKGROUND_FILTER = +            new ColorMatrixColorFilter(new float[]{ +                    0, 0, 0, 0, 255, // red +                    0, 0, 0, 0,   0, // green +                    0, 0, 0, 0, 255, // blue +                    0, 0, 0, 0, 200  // alpha +            }); + +    private final Runnable mUpdateActivityStatusCallback = () -> updateActivityStatus(false); +    private final float mScaledVerticalScrollFactor; +    private final Locale mDefaultLocale = Locale.getDefault(); + +    public RotaryInputValueView(Context c) { +        super(c); + +        DisplayMetrics dm = mContext.getResources().getDisplayMetrics(); +        mScaledVerticalScrollFactor = ViewConfiguration.get(c).getScaledVerticalScrollFactor(); + +        setText(getFormattedValue(0)); +        setTextColor(INACTIVE_TEXT_COLOR); +        setTextSize(applyDimensionSp(TEXT_SIZE_SP, dm)); +        setPaddingRelative(applyDimensionSp(SIDE_PADDING_SP, dm), 0, +                applyDimensionSp(SIDE_PADDING_SP, dm), 0); +        setTypeface(null, Typeface.BOLD); +        setBackgroundResource(R.drawable.focus_event_rotary_input_background); +    } + +    /** Updates the shown text with the formatted value. */ +    public void updateValue(float value) { +        removeCallbacks(mUpdateActivityStatusCallback); + +        setText(getFormattedValue(value * mScaledVerticalScrollFactor)); + +        updateActivityStatus(true); +        postDelayed(mUpdateActivityStatusCallback, ACTIVE_STATUS_DURATION); +    } + +    /** Updates whether or not there's active rotary input. */ +    public void updateActivityStatus(boolean active) { +        if (active) { +            setTextColor(ACTIVE_TEXT_COLOR); +            getBackground().setColorFilter(ACTIVE_BACKGROUND_FILTER); +        } else { +            setTextColor(INACTIVE_TEXT_COLOR); +            getBackground().clearColorFilter(); +        } +    } + +    private String getFormattedValue(float value) { +        return String.format(mDefaultLocale, "%s%.1f", value < 0 ? "-" : "+", Math.abs(value)); +    } + +    /** +     * Converts a dimension in scaled pixel units to integer display pixels. +     */ +    private static int applyDimensionSp(int dimensionSp, DisplayMetrics dm) { +        return (int) TypedValue.applyDimension(COMPLEX_UNIT_SP, dimensionSp, dm); +    } +} diff --git a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java index 7726f40fa2ae..dbbbed31df76 100644 --- a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java +++ b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java @@ -57,13 +57,13 @@ final class HandwritingEventReceiverSurface {                  InputConfig.NOT_FOCUSABLE                          | InputConfig.NOT_TOUCHABLE                          | InputConfig.SPY -                        | InputConfig.INTERCEPTS_STYLUS -                        | InputConfig.TRUSTED_OVERLAY; +                        | InputConfig.INTERCEPTS_STYLUS;          // Configure the surface to receive stylus events across the entire display.          mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);          final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); +        mWindowHandle.setTrustedOverlay(t, mInputSurface, true);          t.setInputWindowInfo(mInputSurface, mWindowHandle);          t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_HANDWRITING_SURFACE);          t.setPosition(mInputSurface, 0, 0); diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java index 93c66a19c89d..08cf3f775cc3 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java @@ -1431,13 +1431,17 @@ public class ContextHubService extends IContextHubService.Stub {                  mContextHubWrapper.onBtMainSettingChanged(btEnabled);              }          } else { -            Log.d(TAG, "BT adapter not available. Defaulting to disabled"); -            if (forceUpdate || mIsBtMainEnabled) { -                mIsBtMainEnabled = false; +            Log.d(TAG, "BT adapter not available. Getting permissions from user settings"); +            boolean btEnabled = Settings.Global.getInt(mContext.getContentResolver(), +                    Settings.Global.BLUETOOTH_ON, 0) == 1; +            boolean btScanEnabled = Settings.Global.getInt(mContext.getContentResolver(), +                    Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1; +            if (forceUpdate || mIsBtMainEnabled != btEnabled) { +                mIsBtMainEnabled = btEnabled;                  mContextHubWrapper.onBtMainSettingChanged(mIsBtMainEnabled);              } -            if (forceUpdate || mIsBtScanningEnabled) { -                mIsBtScanningEnabled = false; +            if (forceUpdate || mIsBtScanningEnabled != btScanEnabled) { +                mIsBtScanningEnabled = btScanEnabled;                  mContextHubWrapper.onBtScanningSettingChanged(mIsBtScanningEnabled);              }          } diff --git a/services/core/java/com/android/server/notification/NotificationBitmapJobService.java b/services/core/java/com/android/server/notification/NotificationBitmapJobService.java index 4335a1dcfa75..e1a07076cb2d 100644 --- a/services/core/java/com/android/server/notification/NotificationBitmapJobService.java +++ b/services/core/java/com/android/server/notification/NotificationBitmapJobService.java @@ -29,7 +29,12 @@ import android.util.Slog;  import com.android.internal.annotations.VisibleForTesting;  import com.android.server.LocalServices; -import java.util.Calendar; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.time.ZoneId;  /**   * This service runs everyday at 2am local time to remove expired bitmaps. @@ -69,26 +74,25 @@ public class NotificationBitmapJobService extends JobService {       * @return Milliseconds until the next time the job should run.       */      private static long getRunAfterMs() { -        Calendar cal = Calendar.getInstance();  // Uses local time zone -        final long now = cal.getTimeInMillis(); +        ZoneId zoneId = ZoneId.systemDefault(); +        ZonedDateTime now = Instant.now().atZone(zoneId); -        cal.set(Calendar.HOUR_OF_DAY, 2); -        cal.set(Calendar.MINUTE, 0); -        cal.set(Calendar.MILLISECOND, 0); -        final long today2AM = cal.getTimeInMillis(); +        LocalDate today = now.toLocalDate(); +        LocalTime twoAM = LocalTime.of(/* hour= */ 2, /* minute= */ 0); -        cal.add(Calendar.DAY_OF_YEAR, 1); -        final long tomorrow2AM = cal.getTimeInMillis(); +        ZonedDateTime today2AM = ZonedDateTime.of(today, twoAM, zoneId); +        ZonedDateTime tomorrow2AM = today2AM.plusDays(1);          return getTimeUntilRemoval(now, today2AM, tomorrow2AM);      }      @VisibleForTesting -    static long getTimeUntilRemoval(long now, long today2AM, long tomorrow2AM) { -        if (now < today2AM) { -            return today2AM - now; +    static long getTimeUntilRemoval(ZonedDateTime now, ZonedDateTime today2AM, +                                    ZonedDateTime tomorrow2AM) { +        if (Duration.between(now, today2AM).isNegative()) { +            return Duration.between(now, tomorrow2AM).toMillis();          } -        return tomorrow2AM - now; +        return Duration.between(now, today2AM).toMillis();      }      @Override diff --git a/services/core/java/com/android/server/notification/NotificationHistoryJobService.java b/services/core/java/com/android/server/notification/NotificationHistoryJobService.java index 3776ad7a0799..c9317d17be37 100644 --- a/services/core/java/com/android/server/notification/NotificationHistoryJobService.java +++ b/services/core/java/com/android/server/notification/NotificationHistoryJobService.java @@ -27,6 +27,7 @@ import android.content.Context;  import android.os.CancellationSignal;  import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting;  import com.android.server.LocalServices;  import java.util.concurrent.TimeUnit; @@ -77,5 +78,11 @@ public class NotificationHistoryJobService extends JobService {          }          return false;      } + +    @Override +    @VisibleForTesting +    protected void attachBaseContext(Context base) { +        super.attachBaseContext(base); +    }  } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index db69d93583d4..87c30674bfb7 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -396,7 +396,7 @@ public class NotificationManagerService extends SystemService {      static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7;      static final int MESSAGE_ON_PACKAGE_CHANGED = 8; -    static final long BITMAP_EXPIRATION_TIME_MS = TimeUnit.HOURS.toMillis(24); +    static final Duration BITMAP_DURATION = Duration.ofHours(24);      // ranking thread messages      private static final int MESSAGE_RECONSIDER_RANKING = 1000; @@ -6705,7 +6705,7 @@ public class NotificationManagerService extends SystemService {                      final long timePostedMs = r.getSbn().getPostTime();                      final long timeNowMs = System.currentTimeMillis(); -                    if (isBitmapExpired(timePostedMs, timeNowMs, BITMAP_EXPIRATION_TIME_MS)) { +                    if (isBitmapExpired(timePostedMs, timeNowMs, BITMAP_DURATION.toMillis())) {                          removeBitmapAndRepost(r);                      }                  } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 82d3e9157986..68a8e40d0528 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -286,6 +286,8 @@ public class UserManagerService extends IUserManager.Stub {      private static final int USER_VERSION = 11; +    private static final int MAX_USER_STRING_LENGTH = 500; +      private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms      static final int WRITE_USER_MSG = 1; @@ -4374,15 +4376,17 @@ public class UserManagerService extends IUserManager.Stub {          // Write seed data          if (userData.persistSeedData) {              if (userData.seedAccountName != null) { -                serializer.attribute(null, ATTR_SEED_ACCOUNT_NAME, userData.seedAccountName); +                serializer.attribute(null, ATTR_SEED_ACCOUNT_NAME, +                        truncateString(userData.seedAccountName));              }              if (userData.seedAccountType != null) { -                serializer.attribute(null, ATTR_SEED_ACCOUNT_TYPE, userData.seedAccountType); +                serializer.attribute(null, ATTR_SEED_ACCOUNT_TYPE, +                        truncateString(userData.seedAccountType));              }          }          if (userInfo.name != null) {              serializer.startTag(null, TAG_NAME); -            serializer.text(userInfo.name); +            serializer.text(truncateString(userInfo.name));              serializer.endTag(null, TAG_NAME);          }          synchronized (mRestrictionsLock) { @@ -4431,6 +4435,13 @@ public class UserManagerService extends IUserManager.Stub {          serializer.endDocument();      } +    private String truncateString(String original) { +        if (original == null || original.length() <= MAX_USER_STRING_LENGTH) { +            return original; +        } +        return original.substring(0, MAX_USER_STRING_LENGTH); +    } +      /*       * Writes the user list file in this format:       * @@ -4869,7 +4880,7 @@ public class UserManagerService extends IUserManager.Stub {              @UserIdInt int parentId, boolean preCreate, @Nullable String[] disallowedPackages,              @NonNull TimingsTraceAndSlog t, @Nullable Object token)              throws UserManager.CheckedUserOperationException { - +        String truncatedName = truncateString(name);          final UserTypeDetails userTypeDetails = mUserTypes.get(userType);          if (userTypeDetails == null) {              throwCheckedUserOperationException( @@ -4904,8 +4915,8 @@ public class UserManagerService extends IUserManager.Stub {          // Try to use a pre-created user (if available).          if (!preCreate && parentId < 0 && isUserTypeEligibleForPreCreation(userTypeDetails)) { -            final UserInfo preCreatedUser = convertPreCreatedUserIfPossible(userType, flags, name, -                    token); +            final UserInfo preCreatedUser = convertPreCreatedUserIfPossible(userType, flags, +                    truncatedName, token);              if (preCreatedUser != null) {                  return preCreatedUser;              } @@ -5000,7 +5011,7 @@ public class UserManagerService extends IUserManager.Stub {                          flags |= UserInfo.FLAG_EPHEMERAL_ON_CREATE;                      } -                    userInfo = new UserInfo(userId, name, null, flags, userType); +                    userInfo = new UserInfo(userId, truncatedName, null, flags, userType);                      userInfo.serialNumber = mNextSerialNumber++;                      userInfo.creationTime = getCreationTime();                      userInfo.partial = true; @@ -6456,8 +6467,8 @@ public class UserManagerService extends IUserManager.Stub {                      Slog.e(LOG_TAG, "No such user for settings seed data u=" + userId);                      return;                  } -                userData.seedAccountName = accountName; -                userData.seedAccountType = accountType; +                userData.seedAccountName = truncateString(accountName); +                userData.seedAccountType = truncateString(accountType);                  userData.seedAccountOptions = accountOptions;                  userData.persistSeedData = persist;              } diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java index ebc7163cd05c..b83421fe78d7 100644 --- a/services/core/java/com/android/server/policy/AppOpsPolicy.java +++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java @@ -42,6 +42,7 @@ import android.os.PackageTagsList;  import android.os.Process;  import android.os.SystemProperties;  import android.os.UserHandle; +import android.permission.flags.Flags;  import android.service.voice.VoiceInteractionManagerInternal;  import android.service.voice.VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity;  import android.text.TextUtils; @@ -75,9 +76,6 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat      private static final boolean SYSPROP_HOTWORD_DETECTION_SERVICE_REQUIRED =              SystemProperties.getBoolean("ro.hotword.detection_service_required", false); -    //TODO(b/289087412): import this from the flag value in set up in device config. -    private static final boolean IS_VOICE_ACTIVATION_OP_ENABLED = false; -      @NonNull      private final Object mLock = new Object(); @@ -212,7 +210,7 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat       * @return the op that should be noted for the voice activations of the app by detected hotword.       */      public static int getVoiceActivationOp() { -        if (IS_VOICE_ACTIVATION_OP_ENABLED) { +        if (Flags.voiceActivationPermissionApis()) {              return OP_RECEIVE_SANDBOX_TRIGGER_AUDIO;          }          return OP_RECORD_AUDIO_HOTWORD; diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 097656cac7f7..3a6664a72439 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -333,6 +333,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {      static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP = 0;      static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME = 1; +    // must match: config_shortPressOnSettingsBehavior in config.xml +    static final int SHORT_PRESS_SETTINGS_NOTHING = 0; +    static final int SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL = 1; +    static final int LAST_SHORT_PRESS_SETTINGS_BEHAVIOR = SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL; +      static final int PENDING_KEY_NULL = -1;      // Must match: config_shortPressOnStemPrimaryBehavior in config.xml @@ -611,6 +616,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {      // What we do when the user double-taps on home      int mDoubleTapOnHomeBehavior; +    // What we do when the user presses on settings +    int mShortPressOnSettingsBehavior; +      // Must match config_primaryShortPressTargetActivity in config.xml      ComponentName mPrimaryShortPressTargetActivity; @@ -2766,6 +2774,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {          if (mPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {              mShortPressOnWindowBehavior = SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE;          } + +        mShortPressOnSettingsBehavior = res.getInteger( +                com.android.internal.R.integer.config_shortPressOnSettingsBehavior); +        if (mShortPressOnSettingsBehavior < SHORT_PRESS_SETTINGS_NOTHING +                || mShortPressOnSettingsBehavior > LAST_SHORT_PRESS_SETTINGS_BEHAVIOR) { +            mShortPressOnSettingsBehavior = SHORT_PRESS_SETTINGS_NOTHING; +        }      }      private void updateSettings() { @@ -3632,6 +3647,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {                  Slog.wtf(TAG, "KEYCODE_STYLUS_BUTTON_* should be handled in"                          + " interceptKeyBeforeQueueing");                  return true; +            case KeyEvent.KEYCODE_SETTINGS: +                if (mShortPressOnSettingsBehavior == SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL) { +                    if (!down) { +                        toggleNotificationPanel(); +                        logKeyboardSystemsEvent(event, KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL); +                    } +                    return true; +                } +                break;          }          if (isValidGlobalKey(keyCode)                  && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { @@ -6272,6 +6296,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {                  pw.print("mLongPressOnPowerBehavior=");                  pw.println(longPressOnPowerBehaviorToString(mLongPressOnPowerBehavior));          pw.print(prefix); +        pw.print("mShortPressOnSettingsBehavior="); +        pw.println(shortPressOnSettingsBehaviorToString(mShortPressOnSettingsBehavior)); +        pw.print(prefix);          pw.print("mLongPressOnPowerAssistantTimeoutMs=");          pw.println(mLongPressOnPowerAssistantTimeoutMs);          pw.print(prefix); @@ -6470,6 +6497,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {          }      } +    private static String shortPressOnSettingsBehaviorToString(int behavior) { +        switch (behavior) { +            case SHORT_PRESS_SETTINGS_NOTHING: +                return "SHORT_PRESS_SETTINGS_NOTHING"; +            case SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL: +                return "SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL"; +            default: +                return Integer.toString(behavior); +        } +    } +      private static String veryLongPressOnPowerBehaviorToString(int behavior) {          switch (behavior) {              case VERY_LONG_PRESS_POWER_NOTHING: diff --git a/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java b/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java index 3d89afaae88f..becbbf2ea76a 100644 --- a/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java +++ b/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java @@ -25,6 +25,8 @@ import android.os.VibratorInfo;  import android.util.Slog;  import android.util.SparseArray;  import android.view.HapticFeedbackConstants; +import android.view.flags.FeatureFlags; +import android.view.flags.FeatureFlagsImpl;  import com.android.internal.annotations.VisibleForTesting; @@ -54,6 +56,7 @@ public final class HapticFeedbackVibrationProvider {      // If present and valid, a vibration here will be used for an effect.      // Otherwise, the system's default vibration will be used.      @Nullable private final SparseArray<VibrationEffect> mHapticCustomizations; +    private final FeatureFlags mViewFeatureFlags;      /** @hide */      public HapticFeedbackVibrationProvider(Resources res, Vibrator vibrator) { @@ -62,14 +65,16 @@ public final class HapticFeedbackVibrationProvider {      /** @hide */      public HapticFeedbackVibrationProvider(Resources res, VibratorInfo vibratorInfo) { -        this(res, vibratorInfo, loadHapticCustomizations(res, vibratorInfo)); +        this(res, vibratorInfo, loadHapticCustomizations(res, vibratorInfo), +                new FeatureFlagsImpl());      }      /** @hide */      @VisibleForTesting HapticFeedbackVibrationProvider(              Resources res,              VibratorInfo vibratorInfo, -            @Nullable SparseArray<VibrationEffect> hapticCustomizations) { +            @Nullable SparseArray<VibrationEffect> hapticCustomizations, +            FeatureFlags viewFeatureFlags) {          mVibratorInfo = vibratorInfo;          mHapticTextHandleEnabled = res.getBoolean(                  com.android.internal.R.bool.config_enableHapticTextHandle); @@ -78,6 +83,7 @@ public final class HapticFeedbackVibrationProvider {              hapticCustomizations = null;          }          mHapticCustomizations = hapticCustomizations; +        mViewFeatureFlags = viewFeatureFlags;          mSafeModeEnabledVibrationEffect =                  effectHasCustomization(HapticFeedbackConstants.SAFE_MODE_ENABLED) @@ -201,12 +207,16 @@ public final class HapticFeedbackVibrationProvider {              default:                  attrs = TOUCH_VIBRATION_ATTRIBUTES;          } + +        int flags = 0;          if (bypassVibrationIntensitySetting) { -            attrs = new VibrationAttributes.Builder(attrs) -                    .setFlags(VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF) -                    .build(); +            flags |= VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF; +        } +        if (shouldBypassInterruptionPolicy(effectId, mViewFeatureFlags)) { +            flags |= VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;          } -        return attrs; + +        return flags == 0 ? attrs : new VibrationAttributes.Builder(attrs).setFlags(flags).build();      }      /** Dumps relevant state. */ @@ -295,4 +305,19 @@ public final class HapticFeedbackVibrationProvider {              return null;          }      } + +    private static boolean shouldBypassInterruptionPolicy( +            int effectId, FeatureFlags viewFeatureFlags) { +        switch (effectId) { +            case HapticFeedbackConstants.SCROLL_TICK: +            case HapticFeedbackConstants.SCROLL_ITEM_FOCUS: +            case HapticFeedbackConstants.SCROLL_LIMIT: +                // The SCROLL_* constants should bypass interruption filter, so that scroll haptics +                // can play regardless of focus modes like DND. Guard this behavior by the feature +                // flag controlling the general scroll feedback APIs. +                return viewFeatureFlags.scrollFeedbackApi(); +            default: +                return false; +        } +    }  } diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java index ee3d697cddb8..45bd1521bc35 100644 --- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java +++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java @@ -448,6 +448,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {              String reason, IBinder token) {          Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason);          try { +            attrs = fixupVibrationAttributes(attrs, effect);              mContext.enforceCallingOrSelfPermission(                      android.Manifest.permission.VIBRATE, "vibrate");              return vibrateInternal(uid, displayId, opPkg, effect, attrs, reason, token); @@ -457,7 +458,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {      }      HalVibration vibrateWithoutPermissionCheck(int uid, int displayId, String opPkg, -            @NonNull CombinedVibration effect, @Nullable VibrationAttributes attrs, +            @NonNull CombinedVibration effect, @NonNull VibrationAttributes attrs,              String reason, IBinder token) {          Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate no perm check, reason = " + reason);          try { @@ -468,7 +469,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {      }      private HalVibration vibrateInternal(int uid, int displayId, String opPkg, -            @NonNull CombinedVibration effect, @Nullable VibrationAttributes attrs, +            @NonNull CombinedVibration effect, @NonNull VibrationAttributes attrs,              String reason, IBinder token) {          if (token == null) {              Slog.e(TAG, "token must not be null"); @@ -478,7 +479,6 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {          if (!isEffectValid(effect)) {              return null;          } -        attrs = fixupVibrationAttributes(attrs, effect);          // Create Vibration.Stats as close to the received request as possible, for tracking.          HalVibration vib = new HalVibration(token, effect,                  new Vibration.CallerInfo(attrs, uid, displayId, opPkg, reason)); diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index c39b266a7701..4a5311b14397 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -577,7 +577,8 @@ public class ActivityStartController {                  .getRootTask(WINDOWING_MODE_UNDEFINED, activityType);          if (rootTask == null) return false;          final ActivityRecord r = rootTask.topRunningActivity(); -        if (r == null || r.isVisibleRequested() || !r.attachedToProcess() +        if (r == null || (r.isVisibleRequested() && rootTask.isTopRootTaskInDisplayArea()) +                || !r.attachedToProcess()                  || !r.mActivityComponent.equals(intent.getComponent())                  || !mService.isCallerRecents(r.getUid())                  // Recents keeps invisible while device is locked. diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 61bae7153f6d..0b673211a1c9 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -6448,19 +6448,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {                  if (!restarting && hasVisibleActivities) {                      deferWindowLayout();                      try { -                        final Task topTask = mRootWindowContainer.getTopDisplayFocusedRootTask(); -                        if (topTask != null -                                && topTask.topRunningActivity(true /* focusableOnly */) == null) { -                            topTask.adjustFocusToNextFocusableTask("handleAppDied"); -                        } -                        if (!mRootWindowContainer.resumeFocusedTasksTopActivities()) { -                            // If there was nothing to resume, and we are not already restarting -                            // this process, but there is a visible activity that is hosted by the -                            // process...then make sure all visible activities are running, taking -                            // care of restarting this process. -                            mRootWindowContainer.ensureActivitiesVisible(null, 0, -                                    !PRESERVE_WINDOWS); -                        } +                        mRootWindowContainer.ensureVisibilityOnVisibleActivityDiedOrCrashed( +                                "handleAppDied");                      } finally {                          continueWindowLayout();                      } @@ -6901,7 +6890,18 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {          @Override          public int finishTopCrashedActivities(WindowProcessController crashedApp, String reason) {              synchronized (mGlobalLock) { -                return mRootWindowContainer.finishTopCrashedActivities(crashedApp, reason); +                deferWindowLayout(); +                try { +                    final Task finishedTask = mRootWindowContainer.finishTopCrashedActivities( +                            crashedApp, reason); +                    if (finishedTask != null) { +                        mRootWindowContainer.ensureVisibilityOnVisibleActivityDiedOrCrashed(reason); +                        return finishedTask.mTaskId; +                    } +                    return INVALID_TASK_ID; +                } finally { +                    continueWindowLayout(); +                }              }          } diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index c2885dab12f0..42376685498a 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -163,7 +163,8 @@ class BackNavigationController {              if (window == null) {                  EmbeddedWindowController.EmbeddedWindow embeddedWindow = -                        wmService.mEmbeddedWindowController.getByFocusToken(focusedWindowToken); +                        wmService.mEmbeddedWindowController.getByInputTransferToken( +                                focusedWindowToken);                  if (embeddedWindow != null) {                      ProtoLog.d(WM_DEBUG_BACK_PREVIEW,                              "Current focused window is embeddedWindow. Dispatch KEYCODE_BACK."); diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java index 2439159164fd..73bcc8d94252 100644 --- a/services/core/java/com/android/server/wm/CompatModePackages.java +++ b/services/core/java/com/android/server/wm/CompatModePackages.java @@ -66,29 +66,29 @@ import java.util.Map;  public final class CompatModePackages {      /** -     * {@link CompatModePackages#DOWNSCALED_INVERSE} is the gatekeeper of all per-app buffer inverse -     * downscale changes. Enabling this change will allow the following scaling factors: -     * {@link CompatModePackages#DOWNSCALE_90} -     * {@link CompatModePackages#DOWNSCALE_85} -     * {@link CompatModePackages#DOWNSCALE_80} -     * {@link CompatModePackages#DOWNSCALE_75} -     * {@link CompatModePackages#DOWNSCALE_70} -     * {@link CompatModePackages#DOWNSCALE_65} -     * {@link CompatModePackages#DOWNSCALE_60} -     * {@link CompatModePackages#DOWNSCALE_55} -     * {@link CompatModePackages#DOWNSCALE_50} -     * {@link CompatModePackages#DOWNSCALE_45} -     * {@link CompatModePackages#DOWNSCALE_40} -     * {@link CompatModePackages#DOWNSCALE_35} -     * {@link CompatModePackages#DOWNSCALE_30} +     * <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> is the gatekeeper of all per-app buffer +     * inverse downscale changes. Enabling this change will allow the following scaling factors: +     * <a href="#DOWNSCALE_90">DOWNSCALE_90</a> +     * <a href="#DOWNSCALE_85">DOWNSCALE_85</a> +     * <a href="#DOWNSCALE_80">DOWNSCALE_80</a> +     * <a href="#DOWNSCALE_75">DOWNSCALE_75</a> +     * <a href="#DOWNSCALE_70">DOWNSCALE_70</a> +     * <a href="#DOWNSCALE_65">DOWNSCALE_65</a> +     * <a href="#DOWNSCALE_60">DOWNSCALE_60</a> +     * <a href="#DOWNSCALE_55">DOWNSCALE_55</a> +     * <a href="#DOWNSCALE_50">DOWNSCALE_50</a> +     * <a href="#DOWNSCALE_45">DOWNSCALE_45</a> +     * <a href="#DOWNSCALE_40">DOWNSCALE_40</a> +     * <a href="#DOWNSCALE_35">DOWNSCALE_35</a> +     * <a href="#DOWNSCALE_30">DOWNSCALE_30</a>       * -     * If {@link CompatModePackages#DOWNSCALED_INVERSE} is enabled for an app package, then the app -     * will be forcibly resized to the lowest enabled scaling factor e.g. 1/0.8 if both 1/0.8 and -     * 1/0.7 (* 100%) were enabled. +     * If <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> is enabled for an app package, then +     * the app will be forcibly resized to the lowest enabled scaling factor e.g. 1/0.8 if both +     * 1/0.8 and 1/0.7 (* 100%) were enabled.       * -     * When both {@link CompatModePackages#DOWNSCALED_INVERSE} -     * and {@link CompatModePackages#DOWNSCALED} are enabled, then -     * {@link CompatModePackages#DOWNSCALED_INVERSE} takes precedence. +     * When both <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> +     * and <a href="#DOWNSCALED">DOWNSCALED</a> are enabled, then +     * <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> takes precedence.       */      @ChangeId      @Disabled @@ -96,29 +96,29 @@ public final class CompatModePackages {      public static final long DOWNSCALED_INVERSE = 273564678L; // This is a Bug ID.      /** -     * {@link CompatModePackages#DOWNSCALED} is the gatekeeper of all per-app buffer downscaling +     * <a href="#DOWNSCALED">DOWNSCALED</a> is the gatekeeper of all per-app buffer downscaling       * changes. Enabling this change will allow the following scaling factors: -     * {@link CompatModePackages#DOWNSCALE_90} -     * {@link CompatModePackages#DOWNSCALE_85} -     * {@link CompatModePackages#DOWNSCALE_80} -     * {@link CompatModePackages#DOWNSCALE_75} -     * {@link CompatModePackages#DOWNSCALE_70} -     * {@link CompatModePackages#DOWNSCALE_65} -     * {@link CompatModePackages#DOWNSCALE_60} -     * {@link CompatModePackages#DOWNSCALE_55} -     * {@link CompatModePackages#DOWNSCALE_50} -     * {@link CompatModePackages#DOWNSCALE_45} -     * {@link CompatModePackages#DOWNSCALE_40} -     * {@link CompatModePackages#DOWNSCALE_35} -     * {@link CompatModePackages#DOWNSCALE_30} +     * <a href="#DOWNSCALE_90">DOWNSCALE_90</a> +     * <a href="#DOWNSCALE_85">DOWNSCALE_85</a> +     * <a href="#DOWNSCALE_80">DOWNSCALE_80</a> +     * <a href="#DOWNSCALE_75">DOWNSCALE_75</a> +     * <a href="#DOWNSCALE_70">DOWNSCALE_70</a> +     * <a href="#DOWNSCALE_65">DOWNSCALE_65</a> +     * <a href="#DOWNSCALE_60">DOWNSCALE_60</a> +     * <a href="#DOWNSCALE_55">DOWNSCALE_55</a> +     * <a href="#DOWNSCALE_50">DOWNSCALE_50</a> +     * <a href="#DOWNSCALE_45">DOWNSCALE_45</a> +     * <a href="#DOWNSCALE_40">DOWNSCALE_40</a> +     * <a href="#DOWNSCALE_35">DOWNSCALE_35</a> +     * <a href="#DOWNSCALE_30">DOWNSCALE_30</a>       * -     * If {@link CompatModePackages#DOWNSCALED} is enabled for an app package, then the app will be +     * If <a href="#DOWNSCALED">DOWNSCALED</a> is enabled for an app package, then the app will be       * forcibly resized to the highest enabled scaling factor e.g. 80% if both 80% and 70% were       * enabled.       * -     * When both {@link CompatModePackages#DOWNSCALED_INVERSE} -     * and {@link CompatModePackages#DOWNSCALED} are enabled, then -     * {@link CompatModePackages#DOWNSCALED_INVERSE} takes precedence. +     * When both <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> +     * and <a href="#DOWNSCALED">DOWNSCALED</a> are enabled, then +     * <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> takes precedence.       */      @ChangeId      @Disabled @@ -126,12 +126,13 @@ public final class CompatModePackages {      public static final long DOWNSCALED = 168419799L;      /** -     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id -     * {@link CompatModePackages#DOWNSCALE_90} for a package will force the app to assume it's +     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id +     * <a href="#DOWNSCALE_90">DOWNSCALE_90</a> for a package will force the app to assume it's       * running on a display with 90% the vertical and horizontal resolution of the real display.       * -     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's -     * running on a display with 111.11% the vertical and horizontal resolution of the real display +     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to +     * assume it's running on a display with 111.11% the vertical and horizontal resolution of +     * the real display       */      @ChangeId      @Disabled @@ -139,12 +140,13 @@ public final class CompatModePackages {      public static final long DOWNSCALE_90 = 182811243L;      /** -     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id -     * {@link CompatModePackages#DOWNSCALE_85} for a package will force the app to assume it's +     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id +     * <a href="#DOWNSCALE_85">DOWNSCALE_85</a> for a package will force the app to assume it's       * running on a display with 85% the vertical and horizontal resolution of the real display.       * -     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's -     * running on a display with 117.65% the vertical and horizontal resolution of the real display +     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to +     * assume it's running on a display with 117.65% the vertical and horizontal resolution of the +     * real display       */      @ChangeId      @Disabled @@ -152,12 +154,13 @@ public final class CompatModePackages {      public static final long DOWNSCALE_85 = 189969734L;      /** -     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id -     * {@link CompatModePackages#DOWNSCALE_80} for a package will force the app to assume it's +     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id +     * <a href="#DOWNSCALE_80">DOWNSCALE_80</a> for a package will force the app to assume it's       * running on a display with 80% the vertical and horizontal resolution of the real display.       * -     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's -     * running on a display with 125% the vertical and horizontal resolution of the real display +     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to +     * assume it's running on a display with 125% the vertical and horizontal resolution of the real +     * display       */      @ChangeId      @Disabled @@ -165,12 +168,13 @@ public final class CompatModePackages {      public static final long DOWNSCALE_80 = 176926753L;      /** -     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id -     * {@link CompatModePackages#DOWNSCALE_75} for a package will force the app to assume it's +     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id +     * <a href="#DOWNSCALE_75">DOWNSCALE_75</a> for a package will force the app to assume it's       * running on a display with 75% the vertical and horizontal resolution of the real display.       * -     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's -     * running on a display with 133.33% the vertical and horizontal resolution of the real display +     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to +     * assume it's running on a display with 133.33% the vertical and horizontal resolution of the +     * real display       */      @ChangeId      @Disabled @@ -178,12 +182,13 @@ public final class CompatModePackages {      public static final long DOWNSCALE_75 = 189969779L;      /** -     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id -     * {@link CompatModePackages#DOWNSCALE_70} for a package will force the app to assume it's +     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id +     * <a href="#DOWNSCALE_70">DOWNSCALE_70</a> for a package will force the app to assume it's       * running on a display with 70% the vertical and horizontal resolution of the real display.       * -     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's -     * running on a display with 142.86% the vertical and horizontal resolution of the real display +     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to +     * assume it's running on a display with 142.86% the vertical and horizontal resolution of the +     * real display       */      @ChangeId      @Disabled @@ -191,12 +196,13 @@ public final class CompatModePackages {      public static final long DOWNSCALE_70 = 176926829L;      /** -     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id -     * {@link CompatModePackages#DOWNSCALE_65} for a package will force the app to assume it's +     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id +     * <a href="#DOWNSCALE_65">DOWNSCALE_65</a> for a package will force the app to assume it's       * running on a display with 65% the vertical and horizontal resolution of the real display.       * -     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's -     * running on a display with 153.85% the vertical and horizontal resolution of the real display +     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to +     * assume it's running on a display with 153.85% the vertical and horizontal resolution of the +     * real display       */      @ChangeId      @Disabled @@ -204,12 +210,13 @@ public final class CompatModePackages {      public static final long DOWNSCALE_65 = 189969744L;      /** -     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id -     * {@link CompatModePackages#DOWNSCALE_60} for a package will force the app to assume it's +     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id +     * <a href="#DOWNSCALE_60">DOWNSCALE_60</a> for a package will force the app to assume it's       * running on a display with 60% the vertical and horizontal resolution of the real display.       * -     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's -     * running on a display with 166.67% the vertical and horizontal resolution of the real display +     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to +     * assume it's running on a display with 166.67% the vertical and horizontal resolution of the +     * real display       */      @ChangeId      @Disabled @@ -217,12 +224,13 @@ public final class CompatModePackages {      public static final long DOWNSCALE_60 = 176926771L;      /** -     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id -     * {@link CompatModePackages#DOWNSCALE_55} for a package will force the app to assume it's +     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id +     * <a href="#DOWNSCALE_55">DOWNSCALE_55</a> for a package will force the app to assume it's       * running on a display with 55% the vertical and horizontal resolution of the real display.       * -     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's -     * running on a display with 181.82% the vertical and horizontal resolution of the real display +     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to +     * assume it's running on a display with 181.82% the vertical and horizontal resolution of the +     * real display       */      @ChangeId      @Disabled @@ -230,12 +238,13 @@ public final class CompatModePackages {      public static final long DOWNSCALE_55 = 189970036L;      /** -     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id -     * {@link CompatModePackages#DOWNSCALE_50} for a package will force the app to assume it's +     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id +     * <a href="#DOWNSCALE_50">DOWNSCALE_50</a> for a package will force the app to assume it's       * running on a display with 50% vertical and horizontal resolution of the real display.       * -     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's -     * running on a display with 200% the vertical and horizontal resolution of the real display +     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to +     * assume it's running on a display with 200% the vertical and horizontal resolution of the real +     * display       */      @ChangeId      @Disabled @@ -243,12 +252,13 @@ public final class CompatModePackages {      public static final long DOWNSCALE_50 = 176926741L;      /** -     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id -     * {@link CompatModePackages#DOWNSCALE_45} for a package will force the app to assume it's +     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id +     * <a href="#DOWNSCALE_45">DOWNSCALE_45</a> for a package will force the app to assume it's       * running on a display with 45% the vertical and horizontal resolution of the real display.       * -     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's -     * running on a display with 222.22% the vertical and horizontal resolution of the real display +     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to +     * assume it's running on a display with 222.22% the vertical and horizontal resolution of the +     * real display       */      @ChangeId      @Disabled @@ -256,12 +266,13 @@ public final class CompatModePackages {      public static final long DOWNSCALE_45 = 189969782L;      /** -     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id -     * {@link CompatModePackages#DOWNSCALE_40} for a package will force the app to assume it's +     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id +     * <a href="#DOWNSCALE_40">DOWNSCALE_40</a> for a package will force the app to assume it's       * running on a display with 40% the vertical and horizontal resolution of the real display.       * -     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's -     * running on a display with 250% the vertical and horizontal resolution of the real display +     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to +     * assume it's running on a display with 250% the vertical and horizontal resolution of the real +     * display       */      @ChangeId      @Disabled @@ -269,12 +280,13 @@ public final class CompatModePackages {      public static final long DOWNSCALE_40 = 189970038L;      /** -     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id -     * {@link CompatModePackages#DOWNSCALE_35} for a package will force the app to assume it's +     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id +     * <a href="#DOWNSCALE_35">DOWNSCALE_35</a> for a package will force the app to assume it's       * running on a display with 35% the vertical and horizontal resolution of the real display.       * -     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's -     * running on a display with 285.71% the vertical and horizontal resolution of the real display +     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to +     * assume it's running on a display with 285.71% the vertical and horizontal resolution of the +     * real display       */      @ChangeId      @Disabled @@ -282,12 +294,13 @@ public final class CompatModePackages {      public static final long DOWNSCALE_35 = 189969749L;      /** -     * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id -     * {@link CompatModePackages#DOWNSCALE_30} for a package will force the app to assume it's +     * With <a href="#DOWNSCALED">DOWNSCALED</a> enabled, subsequently enabling change-id +     * <a href="#DOWNSCALE_30">DOWNSCALE_30</a> for a package will force the app to assume it's       * running on a display with 30% the vertical and horizontal resolution of the real display.       * -     * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's -     * running on a display with 333.33% the vertical and horizontal resolution of the real display +     * With <a href="#DOWNSCALED_INVERSE">DOWNSCALED_INVERSE</a> enabled will force the app to +     * assume it's running on a display with 333.33% the vertical and horizontal resolution of the +     * real display       */      @ChangeId      @Disabled diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 0f1a1053716e..7af4aadb2f0e 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -48,7 +48,6 @@ import android.hardware.input.InputManagerGlobal;  import android.os.Binder;  import android.os.Build;  import android.os.IBinder; -import android.os.InputConfig;  import android.os.RemoteException;  import android.os.UserHandle;  import android.os.UserManager; @@ -186,6 +185,10 @@ class DragState {          // Crop the input surface to the display size.          mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y); +        // Make trusted overlay to not block any touches while D&D ongoing and allowing +        // touches to pass through to windows underneath. This allows user to interact with the +        // UI to navigate while dragging. +        h.setTrustedOverlay(mTransaction, mInputSurface, true);          mTransaction.show(mInputSurface)                  .setInputWindowInfo(mInputSurface, h)                  .setLayer(mInputSurface, Integer.MAX_VALUE) @@ -377,11 +380,6 @@ class DragState {              mDragWindowHandle.ownerUid = MY_UID;              mDragWindowHandle.scaleFactor = 1.0f; -            // InputConfig.TRUSTED_OVERLAY: To not block any touches while D&D ongoing and allowing -            // touches to pass through to windows underneath. This allows user to interact with the -            // UI to navigate while dragging. -            mDragWindowHandle.inputConfig = InputConfig.TRUSTED_OVERLAY; -              // The drag window cannot receive new touches.              mDragWindowHandle.touchableRegion.setEmpty(); diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java index c9bae127b800..275396f459bd 100644 --- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java +++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java @@ -45,8 +45,8 @@ class EmbeddedWindowController {      private static final String TAG = TAG_WITH_CLASS_NAME ? "EmbeddedWindowController" : TAG_WM;      /* maps input token to an embedded window */      private ArrayMap<IBinder /*input token */, EmbeddedWindow> mWindows = new ArrayMap<>(); -    private ArrayMap<IBinder /*focus grant token */, EmbeddedWindow> mWindowsByFocusToken = -        new ArrayMap<>(); +    private ArrayMap<IBinder /*input transfer token */, EmbeddedWindow> +            mWindowsByInputTransferToken = new ArrayMap<>();      private ArrayMap<IBinder /*window token*/, EmbeddedWindow> mWindowsByWindowToken =          new ArrayMap<>();      private final Object mGlobalLock; @@ -67,14 +67,14 @@ class EmbeddedWindowController {      void add(IBinder inputToken, EmbeddedWindow window) {          try {              mWindows.put(inputToken, window); -            final IBinder focusToken = window.getFocusGrantToken(); -            mWindowsByFocusToken.put(focusToken, window); +            final IBinder inputTransferToken = window.getInputTransferToken(); +            mWindowsByInputTransferToken.put(inputTransferToken, window);              mWindowsByWindowToken.put(window.getWindowToken(), window);              updateProcessController(window);              window.mClient.asBinder().linkToDeath(()-> {                  synchronized (mGlobalLock) {                      mWindows.remove(inputToken); -                    mWindowsByFocusToken.remove(focusToken); +                    mWindowsByInputTransferToken.remove(inputTransferToken);                  }              }, 0);          } catch (RemoteException e) { @@ -105,7 +105,7 @@ class EmbeddedWindowController {              EmbeddedWindow ew = mWindows.valueAt(i);              if (ew.mClient.asBinder() == client.asBinder()) {                  mWindows.removeAt(i).onRemoved(); -                mWindowsByFocusToken.remove(ew.getFocusGrantToken()); +                mWindowsByInputTransferToken.remove(ew.getInputTransferToken());                  mWindowsByWindowToken.remove(ew.getWindowToken());                  return;              } @@ -117,7 +117,7 @@ class EmbeddedWindowController {              EmbeddedWindow ew = mWindows.valueAt(i);              if (ew.mHostWindowState == host) {                  mWindows.removeAt(i).onRemoved(); -                mWindowsByFocusToken.remove(ew.getFocusGrantToken()); +                mWindowsByInputTransferToken.remove(ew.getInputTransferToken());                  mWindowsByWindowToken.remove(ew.getWindowToken());              }          } @@ -127,8 +127,8 @@ class EmbeddedWindowController {          return mWindows.get(inputToken);      } -    EmbeddedWindow getByFocusToken(IBinder focusGrantToken) { -        return mWindowsByFocusToken.get(focusGrantToken); +    EmbeddedWindow getByInputTransferToken(IBinder inputTransferToken) { +        return mWindowsByInputTransferToken.get(inputTransferToken);      }      EmbeddedWindow getByWindowToken(IBinder windowToken) { @@ -153,7 +153,7 @@ class EmbeddedWindowController {           * to request focus transfer to the embedded. This is not the input token since we don't           * want to give clients access to each others input token.           */ -        private final IBinder mFocusGrantToken; +        private final IBinder mInputTransferToken;          private boolean mIsFocusable; @@ -171,7 +171,7 @@ class EmbeddedWindowController {           */          EmbeddedWindow(Session session, WindowManagerService service, IWindow clientToken,                         WindowState hostWindowState, int ownerUid, int ownerPid, int windowType, -                       int displayId, IBinder focusGrantToken, String inputHandleName, +                       int displayId, IBinder inputTransferToken, String inputHandleName,                         boolean isFocusable) {              mSession = session;              mWmService = service; @@ -183,7 +183,7 @@ class EmbeddedWindowController {              mOwnerPid = ownerPid;              mWindowType = windowType;              mDisplayId = displayId; -            mFocusGrantToken = focusGrantToken; +            mInputTransferToken = inputTransferToken;              final String hostWindowName =                      (mHostWindowState != null) ? "-" + mHostWindowState.getWindowTag().toString()                              : ""; @@ -260,8 +260,8 @@ class EmbeddedWindowController {              return mOwnerUid;          } -        IBinder getFocusGrantToken() { -            return mFocusGrantToken; +        IBinder getInputTransferToken() { +            return mInputTransferToken;          }          IBinder getInputChannelToken() { @@ -290,7 +290,7 @@ class EmbeddedWindowController {                      // Use null session since this is being granted by system server and doesn't                      // require the host session to be passed in                      mWmService.grantEmbeddedWindowFocus(null, mHostWindowState.mClient, -                            mFocusGrantToken, grantFocus); +                            mInputTransferToken, grantFocus);                      if (grantFocus) {                          // If granting focus to the embedded when tapped, we need to ensure the host                          // gains focus as well or the transfer won't take effect since it requires @@ -298,7 +298,7 @@ class EmbeddedWindowController {                          mHostWindowState.handleTapOutsideFocusInsideSelf();                      }                  } else { -                    mWmService.grantEmbeddedWindowFocus(mSession, mFocusGrantToken, grantFocus); +                    mWmService.grantEmbeddedWindowFocus(mSession, mInputTransferToken, grantFocus);                  }              }          } diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java index 39622c1c5aaf..c21930dab5eb 100644 --- a/services/core/java/com/android/server/wm/InputConsumerImpl.java +++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java @@ -74,7 +74,7 @@ class InputConsumerImpl implements IBinder.DeathRecipient {          mWindowHandle.ownerPid = WindowManagerService.MY_PID;          mWindowHandle.ownerUid = WindowManagerService.MY_UID;          mWindowHandle.scaleFactor = 1.0f; -        mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.TRUSTED_OVERLAY; +        mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE;          mInputSurface = mService.makeSurfaceBuilder(                          mService.mRoot.getDisplayContent(displayId).getSession()) @@ -129,12 +129,14 @@ class InputConsumerImpl implements IBinder.DeathRecipient {      void show(SurfaceControl.Transaction t, WindowContainer w) {          t.show(mInputSurface); +        mWindowHandle.setTrustedOverlay(t, mInputSurface, true);          t.setInputWindowInfo(mInputSurface, mWindowHandle);          t.setRelativeLayer(mInputSurface, w.getSurfaceControl(), 1);      }      void show(SurfaceControl.Transaction t, int layer) {          t.show(mInputSurface); +        mWindowHandle.setTrustedOverlay(t, mInputSurface, true);          t.setInputWindowInfo(mInputSurface, mWindowHandle);          t.setLayer(mInputSurface, layer);      } diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 825d38b3eed7..af307ec3c2a9 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -675,6 +675,11 @@ final class InputMonitor {                      w.getKeyInterceptionInfo());              if (w.mWinAnimator.hasSurface()) { +                // Update trusted overlay changes here because they are tied to input info. Input +                // changes can be updated even if surfaces aren't. +                inputWindowHandle.setTrustedOverlay(mInputTransaction, +                        w.mWinAnimator.mSurfaceController.mSurfaceControl, +                        w.isWindowTrustedOverlay());                  populateInputWindowHandle(inputWindowHandle, w);                  setInputWindowInfoIfNeeded(mInputTransaction,                          w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle); @@ -732,7 +737,7 @@ final class InputMonitor {                  new InputWindowHandle(null /* inputApplicationHandle */, displayId));          inputWindowHandle.setName(name);          inputWindowHandle.setLayoutParamsType(TYPE_SECURE_SYSTEM_OVERLAY); -        inputWindowHandle.setTrustedOverlay(true); +        inputWindowHandle.setTrustedOverlay(t, sc, true);          populateOverlayInputInfo(inputWindowHandle);          setInputWindowInfoIfNeeded(t, sc, inputWindowHandle);      } diff --git a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java index 64b7a6064e45..90d81bd82087 100644 --- a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java +++ b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java @@ -195,6 +195,11 @@ class InputWindowHandleWrapper {          mChanged = true;      } +    void setTrustedOverlay(SurfaceControl.Transaction t, SurfaceControl sc, +            boolean trustedOverlay) { +        mHandle.setTrustedOverlay(t, sc, trustedOverlay); +    } +      void setOwnerPid(int pid) {          if (mHandle.ownerPid == pid) {              return; diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index c3977d6918e3..82d4b90d06be 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -62,6 +62,7 @@ import android.window.PictureInPictureSurfaceTransaction;  import android.window.TaskSnapshot;  import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.IResultReceiver;  import com.android.internal.protolog.common.ProtoLog;  import com.android.server.LocalServices;  import com.android.server.inputmethod.InputMethodManagerInternal; @@ -244,7 +245,8 @@ public class RecentsAnimationController implements DeathRecipient {          }          @Override -        public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint) { +        public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint, +                IResultReceiver finishCb) {              ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,                      "finish(%b): mCanceled=%b", moveHomeToTop, mCanceled);              final long token = Binder.clearCallingIdentity(); @@ -257,6 +259,13 @@ public class RecentsAnimationController implements DeathRecipient {              } finally {                  Binder.restoreCallingIdentity(token);              } +            if (finishCb != null) { +                try { +                    finishCb.send(0, new Bundle()); +                } catch (RemoteException e) { +                    Slog.e(TAG, "Failed to report animation finished", e); +                } +            }          }          @Override diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index a88aa2e3f780..cf6a1feef5ee 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2319,19 +2319,36 @@ class RootWindowContainer extends WindowContainer<DisplayContent>       *       * @param app    The app that crashed.       * @param reason Reason to perform this action. -     * @return The task id that was finished in this root task, or INVALID_TASK_ID if none was -     * finished. +     * @return The finished task which was on top or visible, otherwise {@code null} if the crashed +     *         app doesn't have activity in visible task.       */ -    int finishTopCrashedActivities(WindowProcessController app, String reason) { +    @Nullable +    Task finishTopCrashedActivities(WindowProcessController app, String reason) {          Task focusedRootTask = getTopDisplayFocusedRootTask();          final Task[] finishedTask = new Task[1];          forAllRootTasks(rootTask -> { +            final boolean recordTopOrVisible = finishedTask[0] == null +                    && (focusedRootTask == rootTask || rootTask.isVisibleRequested());              final Task t = rootTask.finishTopCrashedActivityLocked(app, reason); -            if (rootTask == focusedRootTask || finishedTask[0] == null) { +            if (recordTopOrVisible) {                  finishedTask[0] = t;              }          }); -        return finishedTask[0] != null ? finishedTask[0].mTaskId : INVALID_TASK_ID; +        return finishedTask[0]; +    } + +    void ensureVisibilityOnVisibleActivityDiedOrCrashed(String reason) { +        final Task topTask = getTopDisplayFocusedRootTask(); +        if (topTask != null && topTask.topRunningActivity(true /* focusableOnly */) == null) { +            // Move the next focusable task to front. +            topTask.adjustFocusToNextFocusableTask(reason); +        } +        if (!resumeFocusedTasksTopActivities()) { +            // It may be nothing to resume because there are pausing activities or all the top +            // activities are resumed. Then it still needs to make sure all visible activities are +            // running in case the tasks were reordered or there are non-top visible activities. +            ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, !PRESERVE_WINDOWS); +        }      }      boolean resumeFocusedTasksTopActivities() { diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index bbe44c540c39..e6d48667ffb0 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -884,8 +884,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {      @Override      public void grantInputChannel(int displayId, SurfaceControl surface,              IWindow window, IBinder hostInputToken, int flags, int privateFlags, int type, -            int inputFeatures, IBinder windowToken, IBinder focusGrantToken, String inputHandleName, -            InputChannel outInputChannel) { +            int inputFeatures, IBinder windowToken, IBinder inputTransferToken, +            String inputHandleName, InputChannel outInputChannel) {          if (hostInputToken == null && !mCanAddInternalSystemWindow) {              // Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to              // embedded windows without providing a host window input token @@ -896,7 +896,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {          try {              mService.grantInputChannel(this, mUid, mPid, displayId, surface, window, hostInputToken,                      flags, mCanAddInternalSystemWindow ? privateFlags : 0, -                    type, inputFeatures, windowToken, focusGrantToken, inputHandleName, +                    type, inputFeatures, windowToken, inputTransferToken, inputHandleName,                      outInputChannel);          } finally {              Binder.restoreCallingIdentity(identity); diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index c6547a0c11b8..882104a297ef 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -372,8 +372,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {              parent.forAllTasks(t -> {                  // Skip transient-launch task                  if (t == transientRootTask) return false; -                if (t.isVisibleRequested() && !t.isAlwaysOnTop() -                        && !t.getWindowConfiguration().tasksAreFloating()) { +                if (t.isVisibleRequested() && !t.isAlwaysOnTop()) {                      if (t.isRootTask()) {                          mTransientHideTasks.add(t);                      } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 60dc84c18654..074b4044fdaa 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2493,14 +2493,6 @@ public class WindowManagerService extends IWindowManager.Stub                  outInsetsState.set(win.getCompatInsetsState(), true /* copySources */);              } -            // TODO (b/298562855): Remove this after identifying the reason why the frame is empty. -            if (win.mAttrs.providedInsets != null && win.getFrame().isEmpty()) { -                Slog.w(TAG, "Empty frame of " + win -                        + " configChanged=" + configChanged -                        + " frame=" + win.getFrame().toShortString() -                        + " attrs=" + attrs); -            } -              ProtoLog.v(WM_DEBUG_FOCUS, "Relayout of %s: focusMayChange=%b",                      win, focusMayChange); @@ -8803,7 +8795,7 @@ public class WindowManagerService extends IWindowManager.Stub      void grantInputChannel(Session session, int callingUid, int callingPid, int displayId,              SurfaceControl surface, IWindow window, IBinder hostInputToken,              int flags, int privateFlags, int inputFeatures, int type, IBinder windowToken, -            IBinder focusGrantToken, String inputHandleName, InputChannel outInputChannel) { +            IBinder inputTransferToken, String inputHandleName, InputChannel outInputChannel) {          final int sanitizedType = sanitizeWindowType(session, displayId, windowToken, type);          final InputApplicationHandle applicationHandle;          final String name; @@ -8812,7 +8804,7 @@ public class WindowManagerService extends IWindowManager.Stub              EmbeddedWindowController.EmbeddedWindow win =                      new EmbeddedWindowController.EmbeddedWindow(session, this, window,                              mInputToWindowMap.get(hostInputToken), callingUid, callingPid, -                            sanitizedType, displayId, focusGrantToken, inputHandleName, +                            sanitizedType, displayId, inputTransferToken, inputHandleName,                              (flags & FLAG_NOT_FOCUSABLE) == 0);              win.openInputChannel(outInputChannel);              mEmbeddedWindowController.add(outInputChannel.getToken(), win); @@ -8884,11 +8876,6 @@ public class WindowManagerService extends IWindowManager.Stub              h.inputConfig |= InputConfig.NOT_FOCUSABLE;          } -        //  Check private trusted overlay flag to set trustedOverlay field of input window handle. -        if ((privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) { -            h.inputConfig |= InputConfig.TRUSTED_OVERLAY; -        } -          h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;          h.ownerUid = callingUid;          h.ownerPid = callingPid; @@ -8908,6 +8895,8 @@ public class WindowManagerService extends IWindowManager.Stub          }          final SurfaceControl.Transaction t = mTransactionFactory.get(); +        //  Check private trusted overlay flag to set trustedOverlay field of input window handle. +        h.setTrustedOverlay(t, surface, (privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0);          t.setInputWindowInfo(surface, h);          t.apply();          t.close(); @@ -9139,10 +9128,10 @@ public class WindowManagerService extends IWindowManager.Stub          return mPossibleDisplayInfoMapper.getPossibleDisplayInfos(displayId);      } -    void grantEmbeddedWindowFocus(Session session, IBinder focusToken, boolean grantFocus) { +    void grantEmbeddedWindowFocus(Session session, IBinder inputTransferToken, boolean grantFocus) {          synchronized (mGlobalLock) {              final EmbeddedWindowController.EmbeddedWindow embeddedWindow = -                    mEmbeddedWindowController.getByFocusToken(focusToken); +                    mEmbeddedWindowController.getByInputTransferToken(inputTransferToken);              if (embeddedWindow == null) {                  Slog.e(TAG, "Embedded window not found");                  return; @@ -9187,8 +9176,8 @@ public class WindowManagerService extends IWindowManager.Stub          }      } -    void grantEmbeddedWindowFocus(Session session, IWindow callingWindow, IBinder targetFocusToken, -                                  boolean grantFocus) { +    void grantEmbeddedWindowFocus(Session session, IWindow callingWindow, +            IBinder inputTransferToken, boolean grantFocus) {          synchronized (mGlobalLock) {              final WindowState hostWindow =                      windowForClientLocked(session, callingWindow, false /* throwOnError*/); @@ -9201,7 +9190,7 @@ public class WindowManagerService extends IWindowManager.Stub                  return;              }              final EmbeddedWindowController.EmbeddedWindow embeddedWindow = -                    mEmbeddedWindowController.getByFocusToken(targetFocusToken); +                    mEmbeddedWindowController.getByInputTransferToken(inputTransferToken);              if (embeddedWindow == null) {                  Slog.e(TAG, "Embedded window not found");                  return; diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index ebef606a8d60..4beec2bc79e6 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -178,6 +178,7 @@ import static com.android.server.wm.WindowStateProto.UNRESTRICTED_KEEP_CLEAR_ARE  import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY;  import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER;  import static com.android.server.wm.WindowStateProto.WINDOW_FRAMES; +import static com.android.window.flags.Flags.surfaceTrustedOverlay;  import android.annotation.CallSuper;  import android.annotation.NonNull; @@ -1110,7 +1111,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP          mInputWindowHandle.setName(getName());          mInputWindowHandle.setPackageName(mAttrs.packageName);          mInputWindowHandle.setLayoutParamsType(mAttrs.type); -        mInputWindowHandle.setTrustedOverlay(shouldWindowHandleBeTrusted(s)); +        if (!surfaceTrustedOverlay()) { +            mInputWindowHandle.setTrustedOverlay(isWindowTrustedOverlay()); +        }          if (DEBUG) {              Slog.v(TAG, "Window " + this + " client=" + c.asBinder()                              + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a); @@ -1185,12 +1188,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP          }      } -    boolean shouldWindowHandleBeTrusted(Session s) { +    public boolean isWindowTrustedOverlay() {          return InputMonitor.isTrustedOverlay(mAttrs.type)                  || ((mAttrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0 -                        && s.mCanAddInternalSystemWindow) +                        && mSession.mCanAddInternalSystemWindow)                  || ((mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY) != 0 -                        && s.mCanCreateSystemApplicationOverlay); +                        && mSession.mCanCreateSystemApplicationOverlay);      }      int getTouchOcclusionMode() { @@ -5187,6 +5190,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP              updateFrameRateSelectionPriorityIfNeeded();              updateScaleIfNeeded();              mWinAnimator.prepareSurfaceLocked(getSyncTransaction()); +            if (surfaceTrustedOverlay()) { +                getSyncTransaction().setTrustedOverlay(mSurfaceControl, isWindowTrustedOverlay()); +            }          }          super.prepareSurfaces();      } @@ -5939,7 +5945,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP      }      boolean isTrustedOverlay() { -        return mInputWindowHandle.isTrustedOverlay(); +        if (surfaceTrustedOverlay()) { +            WindowState parentWindow = getParentWindow(); +            return isWindowTrustedOverlay() || (parentWindow != null +                    && parentWindow.isWindowTrustedOverlay()); +        } else { +            return mInputWindowHandle.isTrustedOverlay(); +        }      }      public boolean receiveFocusFromTapOutside() { diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index ec5378f01ce3..bc70658a06c4 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -78,6 +78,7 @@ cc_library_static {          "onload.cpp",          ":lib_cachedAppOptimizer_native",          ":lib_gameManagerService_native", +        ":lib_oomConnection_native",      ],      include_dirs: [ @@ -122,6 +123,7 @@ cc_defaults {          "libhardware_legacy",          "libhidlbase",          "libmeminfo", +        "libmemevents",          "libmemtrackproxy",          "libmtp",          "libnativehelper", @@ -239,3 +241,8 @@ filegroup {          "com_android_server_app_GameManagerService.cpp",      ],  } + +filegroup { +    name: "lib_oomConnection_native", +    srcs: ["com_android_server_am_OomConnection.cpp",], +} diff --git a/services/core/jni/com_android_server_am_OomConnection.cpp b/services/core/jni/com_android_server_am_OomConnection.cpp new file mode 100644 index 000000000000..e892d23460c9 --- /dev/null +++ b/services/core/jni/com_android_server_am_OomConnection.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "OomConnection" + +#include <core_jni_helpers.h> +#include <jni.h> +#include <memevents/memevents.h> + +namespace android { + +// Used to cache the results of the JNI name lookup +static struct { +    jclass clazz; +    jmethodID ctor; +} sOomKillRecordInfo; + +static memevents::MemEventListener memevent_listener; + +/** + * Initialize listening and waiting for new out-of-memory (OOM) events to occur. + * Once a OOM event is detected, we then fetch the list of OOM kills, and return + * a corresponding java array with the information gathered. + * + * In the case that we encounter an error, we make sure to close the epfd, and + * the OOM file descriptor, by calling `deregisterAllEvents()`. + * + * @return list of `android.os.OomKillRecord` + * @throws java.lang.RuntimeException + */ +static jobjectArray android_server_am_OomConnection_waitOom(JNIEnv* env, jobject) { +    const memevents::MemEvent oom_event = memevents::MemEvent::OOM_KILL; +    if (!memevent_listener.registerEvent(oom_event)) { +        memevent_listener.deregisterAllEvents(); +        jniThrowRuntimeException(env, "listener failed to register to OOM events"); +        return nullptr; +    } + +    memevents::MemEvent event_received; +    do { +        event_received = memevent_listener.listen(); +        if (event_received == memevents::MemEvent::ERROR) { +            memevent_listener.deregisterAllEvents(); +            jniThrowRuntimeException(env, "listener received error event"); +            return nullptr; +        } +    } while (event_received != oom_event); + +    std::vector<memevents::OomKill> oom_events; +    if (!memevent_listener.getOomEvents(oom_events)) { +        memevent_listener.deregisterAllEvents(); +        jniThrowRuntimeException(env, "Failed to get OOM events"); +        return nullptr; +    } + +    jobjectArray java_oom_array = +            env->NewObjectArray(oom_events.size(), sOomKillRecordInfo.clazz, nullptr); +    if (java_oom_array == NULL) { +        memevent_listener.deregisterAllEvents(); +        jniThrowRuntimeException(env, "Failed to create OomKillRecord array"); +        return nullptr; +    } + +    for (int i = 0; i < oom_events.size(); i++) { +        const memevents::OomKill oom_event = oom_events[i]; +        jstring process_name = env->NewStringUTF(oom_event.process_name); +        if (process_name == NULL) { +            memevent_listener.deregisterAllEvents(); +            jniThrowRuntimeException(env, "Failed creating java string for process name"); +        } +        jobject java_oom_kill = env->NewObject(sOomKillRecordInfo.clazz, sOomKillRecordInfo.ctor, +                                               oom_event.timestamp_ms, oom_event.pid, oom_event.uid, +                                               process_name, oom_event.oom_score_adj); +        if (java_oom_kill == NULL) { +            memevent_listener.deregisterAllEvents(); +            jniThrowRuntimeException(env, "Failed to create OomKillRecord object"); +            return java_oom_array; +        } +        env->SetObjectArrayElement(java_oom_array, i, java_oom_kill); +    } +    return java_oom_array; +} + +static const JNINativeMethod sOomConnectionMethods[] = { +        /* name, signature, funcPtr */ +        {"waitOom", "()[Landroid/os/OomKillRecord;", +         (void*)android_server_am_OomConnection_waitOom}, +}; + +int register_android_server_am_OomConnection(JNIEnv* env) { +    sOomKillRecordInfo.clazz = FindClassOrDie(env, "android/os/OomKillRecord"); +    sOomKillRecordInfo.clazz = MakeGlobalRefOrDie(env, sOomKillRecordInfo.clazz); + +    sOomKillRecordInfo.ctor = +            GetMethodIDOrDie(env, sOomKillRecordInfo.clazz, "<init>", "(JIILjava/lang/String;S)V"); + +    return RegisterMethodsOrDie(env, "com/android/server/am/OomConnection", sOomConnectionMethods, +                                NELEM(sOomConnectionMethods)); +} +} // namespace android
\ No newline at end of file diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index f6f673746609..df4489528be5 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -52,6 +52,7 @@ int register_android_server_Watchdog(JNIEnv* env);  int register_android_server_HardwarePropertiesManagerService(JNIEnv* env);  int register_android_server_SyntheticPasswordManager(JNIEnv* env);  int register_android_hardware_display_DisplayViewport(JNIEnv* env); +int register_android_server_am_OomConnection(JNIEnv* env);  int register_android_server_am_CachedAppOptimizer(JNIEnv* env);  int register_android_server_am_LowMemDetector(JNIEnv* env);  int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(JNIEnv* env); @@ -112,6 +113,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)      register_android_server_storage_AppFuse(env);      register_android_server_SyntheticPasswordManager(env);      register_android_hardware_display_DisplayViewport(env); +    register_android_server_am_OomConnection(env);      register_android_server_am_CachedAppOptimizer(env);      register_android_server_am_LowMemDetector(env);      register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(env); diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd index d0a9c458a20f..debd891400b6 100644 --- a/services/core/xsd/display-device-config/display-device-config.xsd +++ b/services/core/xsd/display-device-config/display-device-config.xsd @@ -46,6 +46,8 @@                      <xs:annotation name="nonnull"/>                      <xs:annotation name="final"/>                  </xs:element> +                <xs:element type="powerThrottlingConfig" name="powerThrottlingConfig" minOccurs="0" +                            maxOccurs="1"/>                  <xs:element type="luxThrottling" name="luxThrottling" minOccurs="0"                              maxOccurs="1"/>                  <xs:element type="highBrightnessMode" name="highBrightnessMode" minOccurs="0" @@ -350,6 +352,43 @@          </xs:sequence>      </xs:complexType> +    <xs:complexType name="powerThrottlingMap"> +        <xs:sequence> +            <xs:element name="powerThrottlingPoint" type="powerThrottlingPoint" maxOccurs="unbounded" minOccurs="1"> +                <xs:annotation name="nonnull"/> +                <xs:annotation name="final"/> +            </xs:element> +        </xs:sequence> +        <xs:attribute name="id" type="xs:string"/> +    </xs:complexType> + +    <xs:complexType name="powerThrottlingPoint"> +        <xs:sequence> +            <xs:element type="thermalStatus" name="thermalStatus"> +                <xs:annotation name="nonnull"/> +                <xs:annotation name="final"/> +            </xs:element> +            <xs:element type="nonNegativeDecimal" name="powerQuotaMilliWatts"> +                <xs:annotation name="nonnull"/> +                <xs:annotation name="final"/> +            </xs:element> +        </xs:sequence> +    </xs:complexType> + +    <xs:complexType name="powerThrottlingConfig"> +        <xs:element type="nonNegativeDecimal" name="brightnessLowestCapAllowed"> +            <xs:annotation name="nonnull"/> +            <xs:annotation name="final"/> +        </xs:element> +        <xs:element name="pollingWindowMillis" type="xs:nonNegativeInteger"> +            <xs:annotation name="nonnull"/> +            <xs:annotation name="final"/> +        </xs:element> +        <xs:element type="powerThrottlingMap" name="powerThrottlingMap" maxOccurs="unbounded"> +                <xs:annotation name="final"/> +        </xs:element> +    </xs:complexType> +      <xs:complexType name="nitsMap">          <xs:sequence>              <xs:element name="point" type="point" maxOccurs="unbounded" minOccurs="2"> diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt index 949b1f2cb74b..2d27f0c79660 100644 --- a/services/core/xsd/display-device-config/schema/current.txt +++ b/services/core/xsd/display-device-config/schema/current.txt @@ -106,6 +106,7 @@ package com.android.server.display.config {      method public final com.android.server.display.config.SensorDetails getLightSensor();      method public com.android.server.display.config.LuxThrottling getLuxThrottling();      method @Nullable public final String getName(); +    method public com.android.server.display.config.PowerThrottlingConfig getPowerThrottlingConfig();      method public final com.android.server.display.config.SensorDetails getProxSensor();      method public com.android.server.display.config.DisplayQuirks getQuirks();      method public com.android.server.display.config.RefreshRateConfigs getRefreshRate(); @@ -138,6 +139,7 @@ package com.android.server.display.config {      method public final void setLightSensor(com.android.server.display.config.SensorDetails);      method public void setLuxThrottling(com.android.server.display.config.LuxThrottling);      method public final void setName(@Nullable String); +    method public void setPowerThrottlingConfig(com.android.server.display.config.PowerThrottlingConfig);      method public final void setProxSensor(com.android.server.display.config.SensorDetails);      method public void setQuirks(com.android.server.display.config.DisplayQuirks);      method public void setRefreshRate(com.android.server.display.config.RefreshRateConfigs); @@ -246,6 +248,30 @@ package com.android.server.display.config {      method public final void setValue(@NonNull java.math.BigDecimal);    } +  public class PowerThrottlingConfig { +    ctor public PowerThrottlingConfig(); +    method @NonNull public final java.math.BigDecimal getBrightnessLowestCapAllowed(); +    method @NonNull public final java.math.BigInteger getPollingWindowMillis(); +    method public final java.util.List<com.android.server.display.config.PowerThrottlingMap> getPowerThrottlingMap(); +    method public final void setBrightnessLowestCapAllowed(@NonNull java.math.BigDecimal); +    method public final void setPollingWindowMillis(@NonNull java.math.BigInteger); +  } + +  public class PowerThrottlingMap { +    ctor public PowerThrottlingMap(); +    method public String getId(); +    method @NonNull public final java.util.List<com.android.server.display.config.PowerThrottlingPoint> getPowerThrottlingPoint(); +    method public void setId(String); +  } + +  public class PowerThrottlingPoint { +    ctor public PowerThrottlingPoint(); +    method @NonNull public final java.math.BigDecimal getPowerQuotaMilliWatts(); +    method @NonNull public final com.android.server.display.config.ThermalStatus getThermalStatus(); +    method public final void setPowerQuotaMilliWatts(@NonNull java.math.BigDecimal); +    method public final void setThermalStatus(@NonNull com.android.server.display.config.ThermalStatus); +  } +    public enum PredefinedBrightnessLimitNames {      method public String getRawName();      enum_constant public static final com.android.server.display.config.PredefinedBrightnessLimitNames _default; diff --git a/services/core/xsd/display-layout-config/display-layout-config.xsd b/services/core/xsd/display-layout-config/display-layout-config.xsd index 57b5d00f75a0..4e954653bcbb 100644 --- a/services/core/xsd/display-layout-config/display-layout-config.xsd +++ b/services/core/xsd/display-layout-config/display-layout-config.xsd @@ -52,6 +52,7 @@              <xs:element name="address" type="xs:nonNegativeInteger"/>              <xs:element name="position" type="xs:string" minOccurs="0" maxOccurs="1" />              <xs:element name="brightnessThrottlingMapId" type="xs:string" minOccurs="0" maxOccurs="1" /> +            <xs:element name="powerThrottlingMapId" type="xs:string" minOccurs="0" maxOccurs="1" />              <xs:element name="refreshRateThermalThrottlingMapId" type="xs:string" minOccurs="0" />              <xs:element name="leadDisplayAddress" type="xs:nonNegativeInteger" minOccurs="0" maxOccurs="1" />          </xs:sequence> diff --git a/services/core/xsd/display-layout-config/schema/current.txt b/services/core/xsd/display-layout-config/schema/current.txt index 2d4f7a428db1..195cae5aee14 100644 --- a/services/core/xsd/display-layout-config/schema/current.txt +++ b/services/core/xsd/display-layout-config/schema/current.txt @@ -8,6 +8,7 @@ package com.android.server.display.config.layout {      method public String getDisplayGroup();      method public java.math.BigInteger getLeadDisplayAddress();      method public String getPosition(); +    method public String getPowerThrottlingMapId();      method public String getRefreshRateThermalThrottlingMapId();      method public String getRefreshRateZoneId();      method public boolean isDefaultDisplay(); @@ -19,6 +20,7 @@ package com.android.server.display.config.layout {      method public void setEnabled(boolean);      method public void setLeadDisplayAddress(java.math.BigInteger);      method public void setPosition(String); +    method public void setPowerThrottlingMapId(String);      method public void setRefreshRateThermalThrottlingMapId(String);      method public void setRefreshRateZoneId(String);    } diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java index b90f08e420e7..3c190bf7ad11 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java @@ -32,6 +32,7 @@ import android.os.Handler;  import android.os.IBinder;  import android.os.Looper;  import android.os.ResultReceiver; +import android.os.UserHandle;  import android.service.credentials.CredentialProviderInfoFactory;  import android.util.Slog; @@ -171,7 +172,9 @@ public class CredentialManagerUi {                  .setAction(UUID.randomUUID().toString());          //TODO: Create unique pending intent using request code and cancel any pre-existing pending          // intents -        return PendingIntent.getActivity( -                mContext, /*requestCode=*/0, intent, PendingIntent.FLAG_IMMUTABLE); +        return PendingIntent.getActivityAsUser( +                mContext, /*requestCode=*/0, intent, +                PendingIntent.FLAG_IMMUTABLE, /*options=*/null, +                UserHandle.of(mUserId));      }  } diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java index 3eb6718c0a95..7bd1cc4ca6c8 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java @@ -31,6 +31,7 @@ import android.credentials.ui.Entry;  import android.credentials.ui.GetCredentialProviderData;  import android.credentials.ui.ProviderPendingIntentResponse;  import android.os.ICancellationSignal; +import android.service.autofill.Flags;  import android.service.credentials.Action;  import android.service.credentials.BeginGetCredentialOption;  import android.service.credentials.BeginGetCredentialRequest; @@ -42,6 +43,7 @@ import android.service.credentials.GetCredentialRequest;  import android.service.credentials.RemoteEntry;  import android.util.Pair;  import android.util.Slog; +import android.view.autofill.AutofillId;  import java.util.ArrayList;  import java.util.HashMap; @@ -379,13 +381,23 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential          // but does not resolve to a valid option. For now, not skipping it because          // it may be possible that the provider adds their own extras and expects to receive          // those and complete the flow. -        if (mBeginGetOptionToCredentialOptionMap.get(id) == null) { +        Intent intent = new Intent(); +        CredentialOption credentialOption = mBeginGetOptionToCredentialOptionMap.get(id); +        if (credentialOption == null) {              Slog.w(TAG, "Id from Credential Entry does not resolve to a valid option"); -            return new Intent(); +            return intent;          } -        return new Intent().putExtra(CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST, +        AutofillId autofillId = credentialOption +                .getCandidateQueryData() +                .getParcelable(CredentialProviderService.EXTRA_AUTOFILL_ID, AutofillId.class); +        if (autofillId != null && Flags.autofillCredmanIntegration()) { +            intent.putExtra(CredentialProviderService.EXTRA_AUTOFILL_ID, autofillId); +        } +        return intent.putExtra( +                CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST,                  new GetCredentialRequest( -                        mCallingAppInfo, List.of(mBeginGetOptionToCredentialOptionMap.get(id)))); +                        mCallingAppInfo, +                        List.of(credentialOption)));      }      private Intent setUpFillInIntentWithQueryRequest() { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 6aa135a3eaa9..43e47d7a45fc 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -241,6 +241,7 @@ import static android.provider.Telephony.Carriers.ENFORCE_KEY;  import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;  import static android.provider.Telephony.Carriers.INVALID_APN_ID;  import static android.security.keystore.AttestationUtils.USE_INDIVIDUAL_ATTESTATION; +  import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;  import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;  import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; @@ -15781,57 +15782,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {          } else {              long ident = mInjector.binderClearCallingIdentity();              try { -                // TODO(b/277908283): check in the policy engine instead of calling user manager. -                List<UserManager.EnforcingUser> sources = mUserManager -                        .getUserRestrictionSources(restriction, UserHandle.of(userId)); -                if (sources == null) { -                    // The restriction is not enforced. -                    return null; -                } -                int sizeBefore = sources.size(); -                if (sizeBefore > 1) { -                    Slogf.d(LOG_TAG, "getEnforcingAdminAndUserDetailsInternal(%d, %s): " -                            + "%d sources found, excluding those set by UserManager", -                            userId, restriction, sizeBefore); -                    sources = getDevicePolicySources(sources); -                } -                if (sources.isEmpty()) { -                    // The restriction is not enforced (or is just enforced by the system) +                if (getEnforcingAdminsForRestrictionInternal(userId, restriction).size() == 0) {                      return null;                  } -                if (sources.size() > 1) { -                    // In this case, we'll show an admin support dialog that does not -                    // specify the admin. -                    // TODO(b/128928355): if this restriction is enforced by multiple DPCs, return -                    // the admin for the calling user. -                    Slogf.w(LOG_TAG, "getEnforcingAdminAndUserDetailsInternal(%d, %s): multiple " -                            + "sources for restriction %s on user %d", -                            userId, restriction, restriction, userId); +                ActiveAdmin admin = getMostProbableDPCAdminForLocalPolicy(userId); +                if (admin != null) {                      result = new Bundle(); -                    result.putInt(Intent.EXTRA_USER_ID, userId); +                    result.putInt(Intent.EXTRA_USER_ID, admin.getUserHandle().getIdentifier()); +                    result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN, +                            admin.info.getComponent());                      return result;                  } -                final UserManager.EnforcingUser enforcingUser = sources.get(0); -                final int sourceType = enforcingUser.getUserRestrictionSource(); -                if (sourceType == UserManager.RESTRICTION_SOURCE_PROFILE_OWNER -                        || sourceType == UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) { -                    ActiveAdmin admin = getMostProbableDPCAdminForLocalPolicy(userId); -                    if (admin != null) { -                        result = new Bundle(); -                        result.putInt(Intent.EXTRA_USER_ID, admin.getUserHandle().getIdentifier()); -                        result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN, -                                admin.info.getComponent()); -                        return result; -                    } -                } else if (sourceType == UserManager.RESTRICTION_SOURCE_SYSTEM) { -                    /* -                     * In this case, the user restriction is enforced by the system. -                     * So we won't show an admin support intent, even if it is also -                     * enforced by a profile/device owner. -                     */ -                    return null; -                } +                return null;              } finally {                  mInjector.binderRestoreCallingIdentity(ident);              } diff --git a/services/foldables/devicestateprovider/tests/Android.bp b/services/foldables/devicestateprovider/tests/Android.bp index a8db05e99179..84a6df38e0a0 100644 --- a/services/foldables/devicestateprovider/tests/Android.bp +++ b/services/foldables/devicestateprovider/tests/Android.bp @@ -20,11 +20,11 @@ android_test {          "foldable-device-state-provider",          "androidx.test.rules",          "junit", -        "truth-prebuilt", +        "truth",          "mockito-target-extended-minus-junit4",          "androidx.test.uiautomator_uiautomator",          "androidx.test.ext.junit",          "testables",      ], -    test_suites: ["device-tests"] +    test_suites: ["device-tests"],  } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 57fa12d20de5..49ad84a8e6d9 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -264,6 +264,8 @@ public final class SystemServer implements Dumpable {              "com.android.server.backup.BackupManagerService$Lifecycle";      private static final String APPWIDGET_SERVICE_CLASS =              "com.android.server.appwidget.AppWidgetService"; +    private static final String ARC_SYSTEM_HEALTH_SERVICE = +            "com.android.server.arc.health.ArcSystemHealthService";      private static final String VOICE_RECOGNITION_MANAGER_SERVICE_CLASS =              "com.android.server.voiceinteraction.VoiceInteractionManagerService";      private static final String APP_HIBERNATION_SERVICE_CLASS = @@ -1287,6 +1289,12 @@ public final class SystemServer implements Dumpable {              }          } +        if (Build.IS_ARC) { +            t.traceBegin("StartArcSystemHealthService"); +            mSystemServiceManager.startService(ARC_SYSTEM_HEALTH_SERVICE); +            t.traceEnd(); +        } +          t.traceBegin("StartUserManagerService");          mSystemServiceManager.startService(UserManagerService.LifeCycle.class);          t.traceEnd(); diff --git a/services/robotests/backup/Android.bp b/services/robotests/backup/Android.bp index e04dd688f2a2..8b9efb312efe 100644 --- a/services/robotests/backup/Android.bp +++ b/services/robotests/backup/Android.bp @@ -59,7 +59,7 @@ android_robolectric_test {          "mockito-robolectric-prebuilt",          "platform-test-annotations",          "testng", -        "truth-prebuilt", +        "truth",      ],      instrumentation_for: "BackupFrameworksServicesLib", diff --git a/services/tests/InputMethodSystemServerTests/Android.bp b/services/tests/InputMethodSystemServerTests/Android.bp index 36446f64bdce..ffe6dc5d1c63 100644 --- a/services/tests/InputMethodSystemServerTests/Android.bp +++ b/services/tests/InputMethodSystemServerTests/Android.bp @@ -44,7 +44,7 @@ android_test {          "service-permission.stubs.system_server",          "servicestests-core-utils",          "servicestests-utils-mockito-extended", -        "truth-prebuilt", +        "truth",      ],      libs: [ @@ -92,7 +92,7 @@ android_test {          "service-permission.stubs.system_server",          "servicestests-core-utils",          "servicestests-utils-mockito-extended", -        "truth-prebuilt", +        "truth",          "SimpleImeTestingLib",          "SimpleImeImsLib",      ], diff --git a/services/tests/PackageManager/packageinstaller/Android.bp b/services/tests/PackageManager/packageinstaller/Android.bp index 35d754b4adc5..e8fce8e72601 100644 --- a/services/tests/PackageManager/packageinstaller/Android.bp +++ b/services/tests/PackageManager/packageinstaller/Android.bp @@ -32,7 +32,7 @@ android_test {          "androidx.test.runner",          "junit",          "kotlin-test", -        "truth-prebuilt", +        "truth",      ],      platform_apis: true,      test_suites: ["device-tests"], diff --git a/services/tests/PackageManagerComponentOverrideTests/Android.bp b/services/tests/PackageManagerComponentOverrideTests/Android.bp index bc369701b2d4..00850a5e5be0 100644 --- a/services/tests/PackageManagerComponentOverrideTests/Android.bp +++ b/services/tests/PackageManagerComponentOverrideTests/Android.bp @@ -38,7 +38,7 @@ android_test {          "service-permission.stubs.system_server",          "servicestests-utils-mockito-extended",          "testng", // TODO: remove once Android migrates to JUnit 4.12, which provides assertThrows -        "truth-prebuilt", +        "truth",      ],      jni_libs: [ diff --git a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp index 9c4e6fd66ceb..ad7af44d4089 100644 --- a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp +++ b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp @@ -29,7 +29,7 @@ android_test {      static_libs: [          "compatibility-device-util-axt",          "androidx.test.runner", -        "truth-prebuilt", +        "truth",          "Harrier",      ],      platform_apis: true, diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp index ce28682c0a25..6eacef767042 100644 --- a/services/tests/PackageManagerServiceTests/host/Android.bp +++ b/services/tests/PackageManagerServiceTests/host/Android.bp @@ -30,7 +30,7 @@ java_test_host {      libs: [          "tradefed",          "junit", -        "truth-prebuilt", +        "truth",      ],      static_libs: [          "ApexInstallHelper", diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp index 462c5801e952..cea9c599317d 100644 --- a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp +++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp @@ -38,6 +38,6 @@ android_test_helper_app {          "junit-params",          "androidx.test.ext.junit",          "androidx.test.rules", -        "truth-prebuilt", +        "truth",      ],  } diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp index 57184748d074..ed5f2b51b9ed 100644 --- a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp +++ b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp @@ -28,6 +28,6 @@ android_test_helper_app {          "androidx.test.runner",          "junit",          "kotlin-test", -        "truth-prebuilt", +        "truth",      ],  } diff --git a/services/tests/PackageManagerServiceTests/server/Android.bp b/services/tests/PackageManagerServiceTests/server/Android.bp index a1d846e0f426..3aca1cafbf75 100644 --- a/services/tests/PackageManagerServiceTests/server/Android.bp +++ b/services/tests/PackageManagerServiceTests/server/Android.bp @@ -41,7 +41,7 @@ android_test {          "mockito-target-minus-junit4",          "platform-test-annotations",          "ShortcutManagerTestUtils", -        "truth-prebuilt", +        "truth",          "testables",          "platformprotosnano",          "framework-protos", @@ -51,7 +51,7 @@ android_test {          "servicestests-utils",          "service-permission.impl",          "testng", -        "truth-prebuilt", +        "truth",          "junit",          "junit-params",          "platform-compat-test-rules", diff --git a/services/tests/PackageManagerServiceTests/unit/Android.bp b/services/tests/PackageManagerServiceTests/unit/Android.bp index 9b3b8c35736c..8505983894a8 100644 --- a/services/tests/PackageManagerServiceTests/unit/Android.bp +++ b/services/tests/PackageManagerServiceTests/unit/Android.bp @@ -37,7 +37,7 @@ android_test {          "services.core",          "servicestests-utils",          "servicestests-core-utils", -        "truth-prebuilt", +        "truth",      ],      jni_libs: [          "libdexmakerjvmtiagent", diff --git a/services/tests/RemoteProvisioningServiceTests/Android.bp b/services/tests/RemoteProvisioningServiceTests/Android.bp index fc2c0857146b..19c913620760 100644 --- a/services/tests/RemoteProvisioningServiceTests/Android.bp +++ b/services/tests/RemoteProvisioningServiceTests/Android.bp @@ -30,8 +30,8 @@ android_test {          "mockito-target",          "service-rkp.impl",          "services.core", -        "truth-prebuilt", -        "truth-java8-extension-jar", +        "truth", +        "truth-java8-extension",      ],      test_suites: [          "device-tests", diff --git a/services/tests/apexsystemservices/Android.bp b/services/tests/apexsystemservices/Android.bp index e724e804f4e7..9dacfeabf1ef 100644 --- a/services/tests/apexsystemservices/Android.bp +++ b/services/tests/apexsystemservices/Android.bp @@ -34,7 +34,7 @@ java_test_host {          "compatibility-host-util",          "cts-install-lib-host",          "frameworks-base-hostutils", -        "truth-prebuilt", +        "truth",          "modules-utils-build-testing",      ],      test_suites: [ diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java index 6ef150c80037..c37d21ae1cc0 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java @@ -179,6 +179,89 @@ public final class DisplayDeviceConfigTest {      }      @Test +    public void testPowerThrottlingConfigFromDisplayConfig() throws IOException { +        setupDisplayDeviceConfigFromDisplayConfigFile(); + +        DisplayDeviceConfig.PowerThrottlingConfigData powerThrottlingConfigData = +                mDisplayDeviceConfig.getPowerThrottlingConfigData(); +        assertNotNull(powerThrottlingConfigData); +        assertEquals(0.1f, powerThrottlingConfigData.brightnessLowestCapAllowed, SMALL_DELTA); +        assertEquals(10, powerThrottlingConfigData.pollingWindowMillis); +    } + +    @Test +    public void testPowerThrottlingDataFromDisplayConfig() throws IOException { +        setupDisplayDeviceConfigFromDisplayConfigFile(); + +        List<DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel> +                defaultThrottlingLevels = new ArrayList<>(); +        defaultThrottlingLevels.add( +                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( +                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 800f +                )); +        defaultThrottlingLevels.add( +                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( +                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 600f +                )); +        defaultThrottlingLevels.add( +                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( +                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 400f +                )); +        defaultThrottlingLevels.add( +                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( +                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 200f +                )); +        defaultThrottlingLevels.add( +                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( +                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 100f +                )); +        defaultThrottlingLevels.add( +                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( +                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 50f +                )); + +        DisplayDeviceConfig.PowerThrottlingData defaultThrottlingData = +                new DisplayDeviceConfig.PowerThrottlingData(defaultThrottlingLevels); + +        List<DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel> +                concurrentThrottlingLevels = new ArrayList<>(); +        concurrentThrottlingLevels.add( +                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( +                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 800f +                )); +        concurrentThrottlingLevels.add( +                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( +                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 600f +                )); +        concurrentThrottlingLevels.add( +                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( +                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 400f +                )); +        concurrentThrottlingLevels.add( +                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( +                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 200f +                )); +        concurrentThrottlingLevels.add( +                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( +                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 100f +                )); +        concurrentThrottlingLevels.add( +                new DisplayDeviceConfig.PowerThrottlingData.ThrottlingLevel( +                        DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 50f +                )); +        DisplayDeviceConfig.PowerThrottlingData concurrentThrottlingData = +                new DisplayDeviceConfig.PowerThrottlingData(concurrentThrottlingLevels); + +        HashMap<String, DisplayDeviceConfig.PowerThrottlingData> throttlingDataMap = +                new HashMap<>(2); +        throttlingDataMap.put("default", defaultThrottlingData); +        throttlingDataMap.put("concurrent", concurrentThrottlingData); + +        assertEquals(throttlingDataMap, +                mDisplayDeviceConfig.getPowerThrottlingDataMapByThrottlingId()); +    } + +    @Test      public void testConfigValuesFromConfigResource() {          setupDisplayDeviceConfigFromConfigResourceFile();          verifyConfigValuesFromConfigResource(); @@ -845,6 +928,64 @@ public final class DisplayDeviceConfigTest {                  +   "</screenBrightnessRampSlowIncreaseIdle>\n";      } +    private String getPowerThrottlingConfig() { +        return  "<powerThrottlingConfig >\n" +                +       "<brightnessLowestCapAllowed>0.1</brightnessLowestCapAllowed>\n" +                +       "<pollingWindowMillis>10</pollingWindowMillis>\n" +                +       "<powerThrottlingMap>\n" +                +           "<powerThrottlingPoint>\n" +                +               "<thermalStatus>light</thermalStatus>\n" +                +               "<powerQuotaMilliWatts>800</powerQuotaMilliWatts>\n" +                +        "</powerThrottlingPoint>\n" +                +           "<powerThrottlingPoint>\n" +                +               "<thermalStatus>moderate</thermalStatus>\n" +                +               "<powerQuotaMilliWatts>600</powerQuotaMilliWatts>\n" +                +           "</powerThrottlingPoint>\n" +                +           "<powerThrottlingPoint>\n" +                +               "<thermalStatus>severe</thermalStatus>\n" +                +               "<powerQuotaMilliWatts>400</powerQuotaMilliWatts>\n" +                +           "</powerThrottlingPoint>\n" +                +           "<powerThrottlingPoint>\n" +                +               "<thermalStatus>critical</thermalStatus>\n" +                +               "<powerQuotaMilliWatts>200</powerQuotaMilliWatts>\n" +                +           "</powerThrottlingPoint>\n" +                +           "<powerThrottlingPoint>\n" +                +               "<thermalStatus>emergency</thermalStatus>\n" +                +               "<powerQuotaMilliWatts>100</powerQuotaMilliWatts>\n" +                +           "</powerThrottlingPoint>\n" +                +           "<powerThrottlingPoint>\n" +                +               "<thermalStatus>shutdown</thermalStatus>\n" +                +               "<powerQuotaMilliWatts>50</powerQuotaMilliWatts>\n" +                +           "</powerThrottlingPoint>\n" +                +       "</powerThrottlingMap>\n" +                +       "<powerThrottlingMap id=\"concurrent\">\n" +                +           "<powerThrottlingPoint>\n" +                +               "<thermalStatus>light</thermalStatus>\n" +                +               "<powerQuotaMilliWatts>800</powerQuotaMilliWatts>\n" +                +           "</powerThrottlingPoint>\n" +                +           "<powerThrottlingPoint>\n" +                +               "<thermalStatus>moderate</thermalStatus>\n" +                +               "<powerQuotaMilliWatts>600</powerQuotaMilliWatts>\n" +                +           "</powerThrottlingPoint>\n" +                +           "<powerThrottlingPoint>\n" +                +               "<thermalStatus>severe</thermalStatus>\n" +                +               "<powerQuotaMilliWatts>400</powerQuotaMilliWatts>\n" +                +           "</powerThrottlingPoint>\n" +                +           "<powerThrottlingPoint>\n" +                +               "<thermalStatus>critical</thermalStatus>\n" +                +               "<powerQuotaMilliWatts>200</powerQuotaMilliWatts>\n" +                +           "</powerThrottlingPoint>\n" +                +           "<powerThrottlingPoint>\n" +                +               "<thermalStatus>emergency</thermalStatus>\n" +                +               "<powerQuotaMilliWatts>100</powerQuotaMilliWatts>\n" +                +           "</powerThrottlingPoint>\n" +                +           "<powerThrottlingPoint>\n" +                +               "<thermalStatus>shutdown</thermalStatus>\n" +                +               "<powerQuotaMilliWatts>50</powerQuotaMilliWatts>\n" +                +           "</powerThrottlingPoint>\n" +                +       "</powerThrottlingMap>\n" +                +   "</powerThrottlingConfig>\n"; +    }      private String getScreenBrightnessRampCapsIdle() {          return "<screenBrightnessRampIncreaseMaxIdleMillis>"                  +       "4000" @@ -915,6 +1056,7 @@ public final class DisplayDeviceConfigTest {                  +            "</displayBrightnessPoint>\n"                  +       "</displayBrightnessMapping>\n"                  +   "</autoBrightness>\n" +                +  getPowerThrottlingConfig()                  +   "<highBrightnessMode enabled=\"true\">\n"                  +       "<transitionPoint>" + BRIGHTNESS[1] + "</transitionPoint>\n"                  +       "<minimumLux>10000</minimumLux>\n" diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java index c63fac9832e9..ee187baf524e 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrClamperTest.java @@ -22,6 +22,9 @@ import static junit.framework.Assert.assertTrue;  import static org.mockito.ArgumentMatchers.any;  import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times;  import static org.mockito.Mockito.verify;  import static org.mockito.Mockito.when; @@ -97,6 +100,37 @@ public class HdrClamperTest {      }      @Test +    public void testRegisterHdrListener() { +        verify(mMockHdrInfoListener).register(mMockBinder); +    } + +    @Test +    public void testRegisterOtherHdrListenerWhenCalledWithOtherToken() { +        IBinder otherBinder = mock(IBinder.class); +        mHdrClamper.resetHdrConfig(TEST_HDR_DATA, WIDTH, HEIGHT, MIN_HDR_PERCENT, otherBinder); + +        verify(mMockHdrInfoListener).unregister(mMockBinder); +        verify(mMockHdrInfoListener).register(otherBinder); +    } + +    @Test +    public void testRegisterHdrListenerOnceWhenCalledWithSameToken() { +        mHdrClamper.resetHdrConfig(TEST_HDR_DATA, WIDTH, HEIGHT, MIN_HDR_PERCENT, mMockBinder); + +        verify(mMockHdrInfoListener, never()).unregister(mMockBinder); +        verify(mMockHdrInfoListener, times(1)).register(mMockBinder); +    } + +    @Test +    public void testRegisterNotCalledIfHbmConfigIsMissing() { +        IBinder otherBinder = mock(IBinder.class); +        mHdrClamper.resetHdrConfig(TEST_HDR_DATA, WIDTH, HEIGHT, -1, otherBinder); + +        verify(mMockHdrInfoListener).unregister(mMockBinder); +        verify(mMockHdrInfoListener, never()).register(otherBinder); +    } + +    @Test      public void testClamper_AmbientLuxChangesAboveLimit() {          mHdrClamper.onAmbientLuxChange(500); diff --git a/services/tests/inprocesstests/Android.bp b/services/tests/inprocesstests/Android.bp index 7c237ac6befb..086e84b86aca 100644 --- a/services/tests/inprocesstests/Android.bp +++ b/services/tests/inprocesstests/Android.bp @@ -14,7 +14,7 @@ android_test {          "androidx.test.core",          "androidx.test.rules",          "services.core", -        "truth-prebuilt", +        "truth",          "platform-test-annotations",      ],      test_suites: ["general-tests"], diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp index 101498aef183..063af573e1f3 100644 --- a/services/tests/mockingservicestests/Android.bp +++ b/services/tests/mockingservicestests/Android.bp @@ -46,6 +46,7 @@ android_test {          "androidx.test.espresso.core",          "androidx.test.espresso.contrib",          "androidx.test.ext.truth", +        "flag-junit",          "frameworks-base-testutils",          "hamcrest-library",          "kotlin-test", @@ -67,7 +68,7 @@ android_test {          "servicestests-core-utils",          "servicestests-utils-mockito-extended",          "testables", -        "truth-prebuilt", +        "truth",          // TODO: remove once Android migrates to JUnit 4.12, which provides assertThrows          "testng",          "compatibility-device-util-axt", diff --git a/services/tests/mockingservicestests/jni/Android.bp b/services/tests/mockingservicestests/jni/Android.bp index f1dc1fa1a108..1eb9888489cb 100644 --- a/services/tests/mockingservicestests/jni/Android.bp +++ b/services/tests/mockingservicestests/jni/Android.bp @@ -22,6 +22,7 @@ cc_library_shared {      srcs: [          ":lib_cachedAppOptimizer_native",          ":lib_gameManagerService_native", +        ":lib_oomConnection_native",          "onload.cpp",      ], @@ -42,6 +43,7 @@ cc_library_shared {          "libgui",          "libhidlbase",          "liblog", +        "libmemevents",          "libmeminfo",          "libnativehelper",          "libprocessgroup", diff --git a/services/tests/mockingservicestests/jni/onload.cpp b/services/tests/mockingservicestests/jni/onload.cpp index 23ccb22321b2..fb910513adda 100644 --- a/services/tests/mockingservicestests/jni/onload.cpp +++ b/services/tests/mockingservicestests/jni/onload.cpp @@ -26,6 +26,7 @@  namespace android {  int register_android_server_am_CachedAppOptimizer(JNIEnv* env);  int register_android_server_app_GameManagerService(JNIEnv* env); +int register_android_server_am_OomConnection(JNIEnv* env);  };  using namespace android; @@ -42,6 +43,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)      ALOG_ASSERT(env, "Could not retrieve the env!");      register_android_server_am_CachedAppOptimizer(env);      register_android_server_app_GameManagerService(env); +    register_android_server_am_OomConnection(env);      return JNI_VERSION_1_4;  } diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java index 5b1508b8393b..be29163e7677 100644 --- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java @@ -1290,7 +1290,8 @@ public class DeviceIdleControllerTest {      }      @Test -    public void testLightStepIdleStateIdlingTimeIncreases() { +    public void testLightStepIdleStateIdlingTimeIncreasesExponentially() { +        mConstants.LIGHT_IDLE_INCREASE_LINEARLY = false;          final long maintenanceTimeMs = 60_000L;          mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = maintenanceTimeMs;          mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = maintenanceTimeMs; @@ -1335,13 +1336,88 @@ public class DeviceIdleControllerTest {                  eq(mInjector.nowElapsed + idlingTimeMs),                  anyLong(), anyString(), any(), any(Handler.class)); -        for (int i = 0; i < 2; ++i) { +        for (int i = 0; i < 10; ++i) {              // IDLE->MAINTENANCE alarm              mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();              alarmListener.onAlarm();              verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);              long maintenanceExpiryTime = mInjector.nowElapsed + maintenanceTimeMs;              idlingTimeMs *= mConstants.LIGHT_IDLE_FACTOR; +            idlingTimeMs = Math.min(idlingTimeMs, mConstants.LIGHT_MAX_IDLE_TIMEOUT); +            // Set MAINTENANCE->IDLE +            alarmManagerInOrder.verify(mAlarmManager).setWindow( +                    eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), +                    eq(maintenanceExpiryTime), +                    anyLong(), anyString(), any(), any(Handler.class)); + +            // MAINTENANCE->IDLE alarm +            mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting(); +            alarmListener.onAlarm(); +            verifyLightStateConditions(LIGHT_STATE_IDLE); +            // Set IDLE->MAINTENANCE again +            alarmManagerInOrder.verify(mAlarmManager).setWindow( +                    eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), +                    eq(mInjector.nowElapsed + idlingTimeMs), +                    anyLong(), anyString(), any(), any(Handler.class)); +        } +    } + +    @Test +    public void testLightStepIdleStateIdlingTimeIncreasesLinearly() { +        mConstants.LIGHT_IDLE_INCREASE_LINEARLY = true; +        final long maintenanceTimeMs = 60_000L; +        mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = maintenanceTimeMs; +        mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = maintenanceTimeMs; +        mConstants.LIGHT_IDLE_TIMEOUT = 5 * 60_000L; +        mConstants.LIGHT_MAX_IDLE_TIMEOUT = 30 * 60_000L; +        mConstants.LIGHT_IDLE_FACTOR = 2f; +        mConstants.LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS = 2 * 60_000L; + +        setNetworkConnected(true); +        mDeviceIdleController.setJobsActive(false); +        mDeviceIdleController.setAlarmsActive(false); +        mDeviceIdleController.setActiveIdleOpsForTest(0); + +        InOrder alarmManagerInOrder = inOrder(mAlarmManager); + +        final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor = ArgumentCaptor +                .forClass(AlarmManager.OnAlarmListener.class); +        doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(), +                eq("DeviceIdleController.light"), alarmListenerCaptor.capture(), any()); + +        // Set state to INACTIVE. +        mDeviceIdleController.becomeActiveLocked("testing", 0); +        setChargingOn(false); +        setScreenOn(false); +        verifyLightStateConditions(LIGHT_STATE_INACTIVE); +        long idlingTimeMs = mConstants.LIGHT_IDLE_TIMEOUT; +        final long idleAfterInactiveExpiryTime = +                mInjector.nowElapsed + mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT; +        alarmManagerInOrder.verify(mAlarmManager).setWindow( +                eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), +                eq(idleAfterInactiveExpiryTime), +                anyLong(), anyString(), any(), any(Handler.class)); + +        final AlarmManager.OnAlarmListener alarmListener = +                alarmListenerCaptor.getAllValues().get(0); + +        // INACTIVE -> IDLE alarm +        mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting(); +        alarmListener.onAlarm(); +        verifyLightStateConditions(LIGHT_STATE_IDLE); +        alarmManagerInOrder.verify(mAlarmManager).setWindow( +                eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), +                eq(mInjector.nowElapsed + idlingTimeMs), +                anyLong(), anyString(), any(), any(Handler.class)); + +        for (int i = 0; i < 10; ++i) { +            // IDLE->MAINTENANCE alarm +            mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting(); +            alarmListener.onAlarm(); +            verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE); +            long maintenanceExpiryTime = mInjector.nowElapsed + maintenanceTimeMs; +            idlingTimeMs += mConstants.LIGHT_IDLE_LINEAR_INCREASE_FACTOR_MS; +            idlingTimeMs = Math.min(idlingTimeMs, mConstants.LIGHT_MAX_IDLE_TIMEOUT);              // Set MAINTENANCE->IDLE              alarmManagerInOrder.verify(mAlarmManager).setWindow(                      eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerInternalTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerInternalTest.java index 64cc3979f181..9ba4f5b4fe30 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerInternalTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerInternalTest.java @@ -218,4 +218,9 @@ public class ActivityManagerInternalTest {              assertEquals(errMsg, Thread.State.TERMINATED, getState());          }      } + +    // TODO: [b/302724778] Remove manual JNI load +    static { +        System.loadLibrary("mockingservicestestjni"); +    }  } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java index 2bc66ace454b..40b5458b06b9 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java @@ -1210,4 +1210,9 @@ public class ActivityManagerServiceTest {              return returnValueForstartUserOnSecondaryDisplay;          }      } + +    // TODO: [b/302724778] Remove manual JNI load +    static { +        System.loadLibrary("mockingservicestestjni"); +    }  } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java index 1c0989c4fb65..9391d5bfeed4 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java @@ -338,4 +338,8 @@ public class AppChildProcessTest {          }      } +    // TODO: [b/302724778] Remove manual JNI load +    static { +        System.loadLibrary("mockingservicestestjni"); +    }  } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java index d56229c9681f..e15942bb8f9a 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java @@ -1126,4 +1126,9 @@ public class ApplicationExitInfoTest {              };          }      } + +    // TODO: [b/302724778] Remove manual JNI load +    static { +        System.loadLibrary("mockingservicestestjni"); +    }  } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java index 0abf46b8ee55..596a3f3d0400 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java @@ -284,4 +284,9 @@ public class AsyncProcessStartTest {          return app;      } + +    // TODO: [b/302724778] Remove manual JNI load +    static { +        System.loadLibrary("mockingservicestestjni"); +    }  } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java index 434d20035369..dfb8fda56edf 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java @@ -803,4 +803,9 @@ public class CacheOomRankerTest {              return mHandler;          }      } + +    // TODO: [b/302724778] Remove manual JNI load +    static { +        System.loadLibrary("mockingservicestestjni"); +    }  } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java index fd1b06830a89..7ec27be0bfc3 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ServiceTimeoutTest.java @@ -201,4 +201,9 @@ public final class ServiceTimeoutTest {              return mActiveServices;          }      } + +    // TODO: [b/302724778] Remove manual JNI load +    static { +        System.loadLibrary("mockingservicestestjni"); +    }  } diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java index 2b56ea8bba33..bded9b40e591 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java @@ -34,6 +34,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder;  import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;  import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;  import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; +import static com.android.server.job.Flags.FLAG_RELAX_PREFETCH_CONNECTIVITY_CONSTRAINT_ONLY_ON_CHARGER;  import static com.android.server.job.JobSchedulerService.FREQUENT_INDEX;  import static com.android.server.job.JobSchedulerService.RARE_INDEX;  import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX; @@ -66,6 +67,7 @@ import android.net.NetworkPolicyManager;  import android.os.Build;  import android.os.Looper;  import android.os.SystemClock; +import android.platform.test.flag.junit.SetFlagsRule;  import android.telephony.CellSignalStrength;  import android.telephony.SignalStrength;  import android.telephony.TelephonyCallback; @@ -79,6 +81,7 @@ import com.android.server.job.JobSchedulerService.Constants;  import com.android.server.net.NetworkPolicyManagerInternal;  import org.junit.Before; +import org.junit.Rule;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.mockito.ArgumentCaptor; @@ -107,6 +110,9 @@ public class ConnectivityControllerTest {      @Mock      private PackageManager mPackageManager; +    @Rule +    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); +      private Constants mConstants;      private FlexibilityController mFlexibilityController; @@ -898,7 +904,8 @@ public class ConnectivityControllerTest {              assertTrue(controller.isSatisfied(latePrefetchUnknownUp, net, caps, mConstants));          } -        // Metered network is only when prefetching, late, and in opportunistic quota +        // Metered network is only when prefetching, charging*, late, and in opportunistic quota +        // *Charging only when the flag is enabled          {              final Network net = mock(Network.class);              final NetworkCapabilities caps = createCapabilitiesBuilder() @@ -910,10 +917,27 @@ public class ConnectivityControllerTest {              assertFalse(controller.isSatisfied(latePrefetch, net, caps, mConstants));              assertFalse(controller.isSatisfied(latePrefetchUnknownDown, net, caps, mConstants));              assertFalse(controller.isSatisfied(latePrefetchUnknownUp, net, caps, mConstants)); +            mSetFlagsRule.disableFlags(FLAG_RELAX_PREFETCH_CONNECTIVITY_CONSTRAINT_ONLY_ON_CHARGER); +            when(mService.isBatteryCharging()).thenReturn(false); + +            when(mNetPolicyManagerInternal.getSubscriptionOpportunisticQuota( +                    any(), eq(NetworkPolicyManagerInternal.QUOTA_TYPE_JOBS))) +                    .thenReturn(9876543210L); +            assertTrue(controller.isSatisfied(latePrefetch, net, caps, mConstants)); +            // Only relax restrictions when we at least know the estimated download bytes. +            assertFalse(controller.isSatisfied(latePrefetchUnknownDown, net, caps, mConstants)); +            assertTrue(controller.isSatisfied(latePrefetchUnknownUp, net, caps, mConstants)); +            mSetFlagsRule.enableFlags(FLAG_RELAX_PREFETCH_CONNECTIVITY_CONSTRAINT_ONLY_ON_CHARGER);              when(mNetPolicyManagerInternal.getSubscriptionOpportunisticQuota(                      any(), eq(NetworkPolicyManagerInternal.QUOTA_TYPE_JOBS)))                      .thenReturn(9876543210L); +            assertFalse(controller.isSatisfied(latePrefetch, net, caps, mConstants)); +            // Only relax restrictions when we at least know the estimated download bytes. +            assertFalse(controller.isSatisfied(latePrefetchUnknownDown, net, caps, mConstants)); +            assertFalse(controller.isSatisfied(latePrefetchUnknownUp, net, caps, mConstants)); + +            when(mService.isBatteryCharging()).thenReturn(true);              assertTrue(controller.isSatisfied(latePrefetch, net, caps, mConstants));              // Only relax restrictions when we at least know the estimated download bytes.              assertFalse(controller.isSatisfied(latePrefetchUnknownDown, net, caps, mConstants)); diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java index 6304270f9a76..305569edd2fa 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java @@ -308,7 +308,6 @@ public final class UserManagerServiceTest {          addDefaultProfileAndParent();          mUms.setBootUser(PROFILE_USER_ID); -          // Boot user not switchable so return most recently in foreground.          assertWithMessage("getBootUser")                  .that(mUmi.getBootUser(/* waitUntilSet= */ false)).isEqualTo(OTHER_USER_ID); @@ -523,6 +522,24 @@ public final class UserManagerServiceTest {                  .isFalse();      } +    @Test +    public void testCreateUserWithLongName_TruncatesName() { +        UserInfo user = mUms.createUserWithThrow(generateLongString(), USER_TYPE_FULL_SECONDARY, 0); +        assertThat(user.name.length()).isEqualTo(500); +        UserInfo user1 = mUms.createUserWithThrow("Test", USER_TYPE_FULL_SECONDARY, 0); +        assertThat(user1.name.length()).isEqualTo(4); +    } + +    private String generateLongString() { +        String partialString = "Test Name Test Name Test Name Test Name Test Name Test Name Test " +                + "Name Test Name Test Name Test Name "; //String of length 100 +        StringBuilder resultString = new StringBuilder(); +        for (int i = 0; i < 660; i++) { +            resultString.append(partialString); +        } +        return resultString.toString(); +    } +      private void removeNonSystemUsers() {          for (UserInfo user : mUms.getUsers(true)) {              if (!user.getUserHandle().isSystem()) { diff --git a/services/tests/powerstatstests/Android.bp b/services/tests/powerstatstests/Android.bp index 8ab45070a017..18a4f0068909 100644 --- a/services/tests/powerstatstests/Android.bp +++ b/services/tests/powerstatstests/Android.bp @@ -16,7 +16,7 @@ android_test {          "coretests-aidl",          "platformprotosnano",          "junit", -        "truth-prebuilt", +        "truth",          "androidx.test.runner",          "androidx.test.ext.junit",          "androidx.test.ext.truth", diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp index 20d8a5d1efeb..2ece8c74420c 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -2,6 +2,13 @@  // Build FrameworksServicesTests package  //######################################################################## +java_defaults { +    name: "FrameworksServicesTests-jni-defaults", +    jni_libs: [ +        "libservicestestjni", +    ], +} +  package {      // See: http://go/android-license-faq      // A large-scale-change added 'default_applicable_licenses' to import @@ -13,6 +20,9 @@ package {  android_test {      name: "FrameworksServicesTests", +    defaults: [ +        "FrameworksServicesTests-jni-defaults", +    ],      // Include all test java files.      srcs: [ @@ -51,7 +61,7 @@ android_test {          "mockito-target-minus-junit4",          "platform-test-annotations",          "ShortcutManagerTestUtils", -        "truth-prebuilt", +        "truth",          "testables",          "androidx.test.uiautomator_uiautomator",          "platformprotosnano", @@ -62,7 +72,7 @@ android_test {          // TODO: remove once Android migrates to JUnit 4.12,          // which provides assertThrows          "testng", -        "truth-prebuilt", +        "truth",          "junit",          "junit-params",          "ActivityContext", diff --git a/services/tests/servicestests/jni/Android.bp b/services/tests/servicestests/jni/Android.bp new file mode 100644 index 000000000000..174beb81d3eb --- /dev/null +++ b/services/tests/servicestests/jni/Android.bp @@ -0,0 +1,58 @@ +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"], +} + +cc_library_shared { +    name: "libservicestestjni", + +    defaults: ["android.hardware.graphics.common-ndk_shared"], + +    cflags: [ +        "-Wall", +        "-Werror", +        "-Wno-unused-parameter", +        "-Wthread-safety", +    ], + +    srcs: [ +        ":lib_cachedAppOptimizer_native", +        ":lib_gameManagerService_native", +        ":lib_oomConnection_native", +        "onload.cpp", +    ], + +    include_dirs: [ +        "frameworks/base/libs", +        "frameworks/native/services", +        "frameworks/native/libs/math/include", +        "frameworks/native/libs/ui/include", +        "system/memory/libmeminfo/include", +    ], + +    shared_libs: [ +        "libandroid", +        "libandroid_runtime", +        "libbase", +        "libbinder", +        "libgralloctypes", +        "libgui", +        "libhidlbase", +        "liblog", +        "libmeminfo", +        "libmemevents", +        "libnativehelper", +        "libprocessgroup", +        "libutils", +        "libcutils", +        "android.hardware.graphics.bufferqueue@1.0", +        "android.hardware.graphics.bufferqueue@2.0", +        "android.hardware.graphics.common@1.2", +        "android.hardware.graphics.mapper@4.0", +        "android.hidl.token@1.0-utils", +    ], +}
\ No newline at end of file diff --git a/services/tests/servicestests/jni/onload.cpp b/services/tests/servicestests/jni/onload.cpp new file mode 100644 index 000000000000..f160b3d97367 --- /dev/null +++ b/services/tests/servicestests/jni/onload.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * this is a mini native libaray for cached app optimizer tests to run properly. It + * loads all the native methods necessary. + */ +#include <nativehelper/JNIHelp.h> +#include "jni.h" +#include "utils/Log.h" +#include "utils/misc.h" + +namespace android { +int register_android_server_am_CachedAppOptimizer(JNIEnv* env); +int register_android_server_app_GameManagerService(JNIEnv* env); +int register_android_server_am_OomConnection(JNIEnv* env); +}; + +using namespace android; + +extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) +{ +    JNIEnv* env = NULL; +    jint result = -1; + +    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { +        ALOGE("GetEnv failed!"); +        return result; +    } +    ALOG_ASSERT(env, "Could not retrieve the env!"); +    register_android_server_am_CachedAppOptimizer(env); +    register_android_server_app_GameManagerService(env); +    register_android_server_am_OomConnection(env); +    return JNI_VERSION_1_4; +} diff --git a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java index acdfee9af557..c0051c6c9e17 100644 --- a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java @@ -172,4 +172,9 @@ public class AnrHelperTest {                  anyString(), any(), any(), any(), anyBoolean(), any(), eq(mAuxExecutorService),                  anyBoolean(), anyBoolean(), any());      } + +    // TODO: [b/302724778] Remove manual JNI load +    static { +        System.loadLibrary("servicestestjni"); +    }  } diff --git a/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java b/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java index 9fdbdda38c75..70527ce2ad32 100644 --- a/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java @@ -228,6 +228,7 @@ public class AnrTimerTest {          TestHandler mTestHandler;          TestInjector(int skip, boolean immediate) { +            super(mHandler);              mTracker = new TestTracker(skip);              mImmediate = immediate;          } @@ -249,9 +250,16 @@ public class AnrTimerTest {              return mTestHandler;          } +        @Override          AnrTimer.CpuTracker getTracker() {              return mTracker;          } + +        /** For test purposes, always enable the feature. */ +        @Override +        boolean getFeatureEnabled() { +            return true; +        }      }      // Tests @@ -261,7 +269,6 @@ public class AnrTimerTest {      // 4. Start a couple of timers.  Verify max active timers.  Discard one and verify the active      //    count drops by 1.  Accept one and verify the active count drops by 1. -      @Test      public void testSimpleTimeout() throws Exception {          // Create an immediate TestHandler. diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp index 1d37f9da8d7a..d1f4961ab7e5 100644 --- a/services/tests/uiservicestests/Android.bp +++ b/services/tests/uiservicestests/Android.bp @@ -39,7 +39,7 @@ android_test {          "hamcrest-library",          "servicestests-utils",          "testables", -        "truth-prebuilt", +        "truth",          // TODO: remove once Android migrates to JUnit 4.12,          // which provides assertThrows          "testng", diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationBitmapJobServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationBitmapJobServiceTest.java index 312057ee922d..348d1bfd44df 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationBitmapJobServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationBitmapJobServiceTest.java @@ -44,6 +44,12 @@ import org.mockito.Captor;  import org.mockito.Mock;  import java.lang.reflect.Field; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.time.ZoneId;  @RunWith(AndroidTestingRunner.class)  public class NotificationBitmapJobServiceTest extends UiServiceTestCase { @@ -103,17 +109,39 @@ public class NotificationBitmapJobServiceTest extends UiServiceTestCase {      @Test      public void testGetTimeUntilRemoval_beforeToday2am_returnTimeUntilToday2am() { -        final long timeUntilRemoval = mJobService.getTimeUntilRemoval(/* now= */ 1, -                /* today2AM= */ 2, /* tomorrow2AM= */ 26); +        ZoneId zoneId = ZoneId.systemDefault(); +        ZonedDateTime now = Instant.now().atZone(zoneId); +        LocalDate today = now.toLocalDate(); -        assertThat(timeUntilRemoval).isEqualTo(1); +        LocalTime oneAM = LocalTime.of(/* hour= */ 1, /* minute= */ 0); +        LocalTime twoAM = LocalTime.of(/* hour= */ 2, /* minute= */ 0); + +        ZonedDateTime today1AM = ZonedDateTime.of(today, oneAM, zoneId); +        ZonedDateTime today2AM = ZonedDateTime.of(today, twoAM, zoneId); +        ZonedDateTime tomorrow2AM = today2AM.plusDays(1); + +        final long msUntilRemoval = mJobService.getTimeUntilRemoval( +                /* now= */ today1AM, today2AM, tomorrow2AM); + +        assertThat(msUntilRemoval).isEqualTo(Duration.ofHours(1).toMillis());      }      @Test      public void testGetTimeUntilRemoval_afterToday2am_returnTimeUntilTomorrow2am() { -        final long timeUntilRemoval = mJobService.getTimeUntilRemoval(/* now= */ 3, -                /* today2AM= */ 2, /* tomorrow2AM= */ 26); +        ZoneId zoneId = ZoneId.systemDefault(); +        ZonedDateTime now = Instant.now().atZone(zoneId); +        LocalDate today = now.toLocalDate(); + +        LocalTime threeAM = LocalTime.of(/* hour= */ 3, /* minute= */ 0); +        LocalTime twoAM = LocalTime.of(/* hour= */ 2, /* minute= */ 0); + +        ZonedDateTime today3AM = ZonedDateTime.of(today, threeAM, zoneId); +        ZonedDateTime today2AM = ZonedDateTime.of(today, twoAM, zoneId); +        ZonedDateTime tomorrow2AM = today2AM.plusDays(1); + +        final long msUntilRemoval = mJobService.getTimeUntilRemoval(/* now= */ today3AM, +                today2AM, tomorrow2AM); -        assertThat(timeUntilRemoval).isEqualTo(23); +        assertThat(msUntilRemoval).isEqualTo(Duration.ofHours(23).toMillis());      }  }
\ No newline at end of file diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryJobServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryJobServiceTest.java index d758e71c62a2..3499a12f5954 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryJobServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryJobServiceTest.java @@ -71,10 +71,10 @@ public class NotificationHistoryJobServiceTest extends UiServiceTestCase {      @Before      public void setUp() throws Exception {          mJobService = new NotificationHistoryJobService(); +        mJobService.attachBaseContext(mContext); +        mJobService.onCreate(); +        mJobService.onBind(/* intent= */ null);  // Create JobServiceEngine within JobService. -        final Field field = JobService.class.getDeclaredField("mEngine"); -        field.setAccessible(true); -        field.set(mJobService, mock(JobServiceEngine.class));          mContext.addMockSystemService(JobScheduler.class, mMockJobScheduler);          // add NotificationManagerInternal to LocalServices diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java index 7a55143ba13f..c05f81497e57 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java @@ -462,7 +462,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {      }      private void detailedAssertEquals(NotificationRankingUpdate a, NotificationRankingUpdate b) { -        assertEquals(a.getRankingMap(), b.getRankingMap()); +        detailedAssertEquals(a.getRankingMap(), b.getRankingMap());      }      private void detailedAssertEquals(String comment, Ranking a, Ranking b) { 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 c98d2359b2f9..91129a14ecab 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -91,7 +91,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR  import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;  import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;  import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER; -import static com.android.server.notification.NotificationManagerService.BITMAP_EXPIRATION_TIME_MS; +import static com.android.server.notification.NotificationManagerService.BITMAP_DURATION;  import static com.android.server.notification.NotificationManagerService.DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;  import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED;  import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED; @@ -11381,7 +11381,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {          long timePostedMs = System.currentTimeMillis();          if (isExpired) { -            timePostedMs -= BITMAP_EXPIRATION_TIME_MS; +            timePostedMs -= BITMAP_DURATION.toMillis();          }          StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,                  notification, UserHandle.getUserHandleForUid(mUid), null, timePostedMs); diff --git a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java index a91bd2b55f76..000355598281 100644 --- a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java +++ b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java @@ -16,6 +16,8 @@  package com.android.server.vibrator; +import static android.os.VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY; +import static android.os.VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF;  import static android.os.VibrationEffect.Composition.PRIMITIVE_CLICK;  import static android.os.VibrationEffect.Composition.PRIMITIVE_TICK;  import static android.os.VibrationEffect.EFFECT_TEXTURE_TICK; @@ -24,8 +26,13 @@ import static android.view.HapticFeedbackConstants.CLOCK_TICK;  import static android.view.HapticFeedbackConstants.CONTEXT_CLICK;  import static android.view.HapticFeedbackConstants.SAFE_MODE_ENABLED;  import static android.view.HapticFeedbackConstants.TEXT_HANDLE_MOVE; +import static android.view.HapticFeedbackConstants.SCROLL_ITEM_FOCUS; +import static android.view.HapticFeedbackConstants.SCROLL_LIMIT; +import static android.view.HapticFeedbackConstants.SCROLL_TICK; +  import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage;  import static org.mockito.Mockito.when; @@ -37,6 +44,7 @@ import android.os.VibrationEffect;  import android.os.VibratorInfo;  import android.util.AtomicFile;  import android.util.SparseArray; +import android.view.flags.FeatureFlags;  import androidx.test.InstrumentationRegistry; @@ -59,23 +67,25 @@ public class HapticFeedbackVibrationProviderTest {      private static final VibrationEffect PRIMITIVE_CLICK_EFFECT =              VibrationEffect.startComposition().addPrimitive(PRIMITIVE_CLICK, 0.3497f).compose(); +    private static final int[] SCROLL_FEEDBACK_CONSTANTS = +            new int[] {SCROLL_ITEM_FOCUS, SCROLL_LIMIT, SCROLL_TICK};      private Context mContext = InstrumentationRegistry.getContext();      private VibratorInfo mVibratorInfo = VibratorInfo.EMPTY_VIBRATOR_INFO;      @Mock private Resources mResourcesMock; +    @Mock private FeatureFlags mViewFeatureFlags;      @Test      public void testNonExistentCustomization_useDefault() throws Exception {          // No customization file is set. -        HapticFeedbackVibrationProvider hapticProvider = -                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo); +        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();          assertThat(hapticProvider.getVibrationForHapticFeedback(CONTEXT_CLICK))                  .isEqualTo(VibrationEffect.get(EFFECT_TICK));          // The customization file specifies no customization.          setupCustomizationFile("<haptic-feedback-constants></haptic-feedback-constants>"); -        hapticProvider = new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo); +        hapticProvider = createProviderWithDefaultCustomizations();          assertThat(hapticProvider.getVibrationForHapticFeedback(CONTEXT_CLICK))                  .isEqualTo(VibrationEffect.get(EFFECT_TICK)); @@ -84,8 +94,7 @@ public class HapticFeedbackVibrationProviderTest {      @Test      public void testExceptionParsingCustomizations_useDefault() throws Exception {          setupCustomizationFile("<bad-xml></bad-xml>"); -        HapticFeedbackVibrationProvider hapticProvider = -                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo); +        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();          assertThat(hapticProvider.getVibrationForHapticFeedback(CONTEXT_CLICK))                  .isEqualTo(VibrationEffect.get(EFFECT_TICK)); @@ -97,8 +106,7 @@ public class HapticFeedbackVibrationProviderTest {          SparseArray<VibrationEffect> customizations = new SparseArray<>();          customizations.put(CONTEXT_CLICK, PRIMITIVE_CLICK_EFFECT); -        HapticFeedbackVibrationProvider hapticProvider = -                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo, customizations); +        HapticFeedbackVibrationProvider hapticProvider = createProvider(customizations);          // The override for `CONTEXT_CLICK` is used.          assertThat(hapticProvider.getVibrationForHapticFeedback(CONTEXT_CLICK)) @@ -118,8 +126,7 @@ public class HapticFeedbackVibrationProviderTest {                  + "</haptic-feedback-constants>";          setupCustomizationFile(xml); -        HapticFeedbackVibrationProvider hapticProvider = -                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo); +        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();          // The override for `CONTEXT_CLICK` is not used because the vibration is not supported.          assertThat(hapticProvider.getVibrationForHapticFeedback(CONTEXT_CLICK)) @@ -137,15 +144,12 @@ public class HapticFeedbackVibrationProviderTest {          customizations.put(TEXT_HANDLE_MOVE, PRIMITIVE_CLICK_EFFECT);          // Test with a customization available for `TEXT_HANDLE_MOVE`. -        HapticFeedbackVibrationProvider hapticProvider = -                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo, customizations); +        HapticFeedbackVibrationProvider hapticProvider = createProvider(customizations);          assertThat(hapticProvider.getVibrationForHapticFeedback(TEXT_HANDLE_MOVE)).isNull();          // Test with no customization available for `TEXT_HANDLE_MOVE`. -        hapticProvider = -                new HapticFeedbackVibrationProvider( -                        mResourcesMock, mVibratorInfo, /* hapticCustomizations= */ null); +        hapticProvider = createProvider(/* customizations= */ null);          assertThat(hapticProvider.getVibrationForHapticFeedback(TEXT_HANDLE_MOVE)).isNull();      } @@ -158,16 +162,13 @@ public class HapticFeedbackVibrationProviderTest {          customizations.put(TEXT_HANDLE_MOVE, PRIMITIVE_CLICK_EFFECT);          // Test with a customization available for `TEXT_HANDLE_MOVE`. -        HapticFeedbackVibrationProvider hapticProvider = -                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo, customizations); +        HapticFeedbackVibrationProvider hapticProvider = createProvider(customizations);          assertThat(hapticProvider.getVibrationForHapticFeedback(TEXT_HANDLE_MOVE))                  .isEqualTo(PRIMITIVE_CLICK_EFFECT);          // Test with no customization available for `TEXT_HANDLE_MOVE`. -        hapticProvider = -                new HapticFeedbackVibrationProvider( -                        mResourcesMock, mVibratorInfo, /* hapticCustomizations= */ null); +        hapticProvider = createProvider(/* customizations= */ null);          assertThat(hapticProvider.getVibrationForHapticFeedback(TEXT_HANDLE_MOVE))                  .isEqualTo(VibrationEffect.get(EFFECT_TEXTURE_TICK)); @@ -181,15 +182,13 @@ public class HapticFeedbackVibrationProviderTest {          SparseArray<VibrationEffect> customizations = new SparseArray<>();          customizations.put(SAFE_MODE_ENABLED, PRIMITIVE_CLICK_EFFECT); -        HapticFeedbackVibrationProvider hapticProvider = -                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo, customizations); +        HapticFeedbackVibrationProvider hapticProvider = createProvider(customizations);          assertThat(hapticProvider.getVibrationForHapticFeedback(SAFE_MODE_ENABLED))                  .isEqualTo(PRIMITIVE_CLICK_EFFECT);          mockSafeModeEnabledVibration(null); -        hapticProvider = -                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo, customizations); +        hapticProvider = createProvider(customizations);          assertThat(hapticProvider.getVibrationForHapticFeedback(SAFE_MODE_ENABLED))                  .isEqualTo(PRIMITIVE_CLICK_EFFECT); @@ -199,9 +198,7 @@ public class HapticFeedbackVibrationProviderTest {      public void testNoValidCustomizationPresentForSafeModeEnabled_resourceBasedVibrationUsed()                  throws Exception {          mockSafeModeEnabledVibration(10, 20, 30, 40); -        HapticFeedbackVibrationProvider hapticProvider = -                new HapticFeedbackVibrationProvider( -                        mResourcesMock, mVibratorInfo, /* hapticCustomizations= */ null); +        HapticFeedbackVibrationProvider hapticProvider = createProvider(/* customizations= */ null);          assertThat(hapticProvider.getVibrationForHapticFeedback(SAFE_MODE_ENABLED))                  .isEqualTo(VibrationEffect.createWaveform(new long[] {10, 20, 30, 40}, -1)); @@ -211,35 +208,65 @@ public class HapticFeedbackVibrationProviderTest {      public void testNoValidCustomizationAndResourcePresentForSafeModeEnabled_noVibrationUsed()                  throws Exception {          mockSafeModeEnabledVibration(null); -        HapticFeedbackVibrationProvider hapticProvider = -                new HapticFeedbackVibrationProvider( -                        mResourcesMock, mVibratorInfo, /* hapticCustomizations= */ null); +        HapticFeedbackVibrationProvider hapticProvider = createProvider(/* customizations= */ null);          assertThat(hapticProvider.getVibrationForHapticFeedback(SAFE_MODE_ENABLED)).isNull();      }      @Test      public void testVibrationAttribute_forNotBypassingIntensitySettings() { -        HapticFeedbackVibrationProvider hapticProvider = -                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo); +        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();          VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(                  SAFE_MODE_ENABLED, /* bypassVibrationIntensitySetting= */ false); -        assertThat(attrs.getFlags() & VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF) -                .isEqualTo(0); +        assertThat(attrs.isFlagSet(FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)).isFalse();      }      @Test      public void testVibrationAttribute_forByassingIntensitySettings() { -        HapticFeedbackVibrationProvider hapticProvider = -                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo); +        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();          VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(                  SAFE_MODE_ENABLED, /* bypassVibrationIntensitySetting= */ true); -        assertThat(attrs.getFlags() & VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF) -                .isNotEqualTo(0); +        assertThat(attrs.isFlagSet(FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)).isTrue(); +    } + +    @Test +    public void testVibrationAttribute_scrollFeedback_scrollApiFlagOn_bypassInterruptPolicy() { +        when(mViewFeatureFlags.scrollFeedbackApi()).thenReturn(true); +        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations(); + +        for (int effectId : SCROLL_FEEDBACK_CONSTANTS) { +            VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback( +                    effectId, /* bypassVibrationIntensitySetting= */ false); +            assertWithMessage("Expected FLAG_BYPASS_INTERRUPTION_POLICY for effect " + effectId) +                   .that(attrs.isFlagSet(FLAG_BYPASS_INTERRUPTION_POLICY)).isTrue(); +        } +    } + +    @Test +    public void testVibrationAttribute_scrollFeedback_scrollApiFlagOff_noBypassInterruptPolicy() { +        when(mViewFeatureFlags.scrollFeedbackApi()).thenReturn(false); +        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations(); + +        for (int effectId : SCROLL_FEEDBACK_CONSTANTS) { +            VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback( +                    effectId, /* bypassVibrationIntensitySetting= */ false); +            assertWithMessage("Expected no FLAG_BYPASS_INTERRUPTION_POLICY for effect " + effectId) +                   .that(attrs.isFlagSet(FLAG_BYPASS_INTERRUPTION_POLICY)).isFalse(); +        } +    } + +    private HapticFeedbackVibrationProvider createProviderWithDefaultCustomizations() { +        return createProvider(/* customizations= */ null); +    } + +    private HapticFeedbackVibrationProvider createProvider( +            SparseArray<VibrationEffect> customizations) { +        return new HapticFeedbackVibrationProvider( +            mResourcesMock, mVibratorInfo, customizations, mViewFeatureFlags);      }      private void mockVibratorPrimitiveSupport(int... supportedPrimitives) { 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 0eec9cd93f3b..40e0e84dca59 100644 --- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -31,6 +31,7 @@ import static org.mockito.ArgumentMatchers.anyString;  import static org.mockito.ArgumentMatchers.eq;  import static org.mockito.Mockito.atLeastOnce;  import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing;  import static org.mockito.Mockito.doThrow;  import static org.mockito.Mockito.inOrder;  import static org.mockito.Mockito.mock; @@ -46,6 +47,7 @@ import android.content.ComponentName;  import android.content.ContentResolver;  import android.content.Context;  import android.content.ContextWrapper; +import android.content.pm.PackageManager;  import android.content.pm.PackageManagerInternal;  import android.content.res.Resources;  import android.hardware.input.IInputManager; @@ -87,6 +89,7 @@ import android.util.SparseBooleanArray;  import android.view.Display;  import android.view.HapticFeedbackConstants;  import android.view.InputDevice; +import android.view.flags.FeatureFlags;  import androidx.test.InstrumentationRegistry;  import androidx.test.filters.FlakyTest; @@ -172,6 +175,8 @@ public class VibratorManagerServiceTest {      private VirtualDeviceManagerInternal mVirtualDeviceManagerInternalMock;      @Mock      private AudioManager mAudioManagerMock; +    @Mock +    private FeatureFlags mViewFeatureFlags;      private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>(); @@ -321,7 +326,8 @@ public class VibratorManagerServiceTest {                      HapticFeedbackVibrationProvider createHapticFeedbackVibrationProvider(                              Resources resources, VibratorInfo vibratorInfo) {                          return new HapticFeedbackVibrationProvider( -                                resources, vibratorInfo, mHapticFeedbackVibrationMap); +                                resources, vibratorInfo, mHapticFeedbackVibrationMap, +                                mViewFeatureFlags);                      }                  });          return mService; @@ -649,6 +655,42 @@ public class VibratorManagerServiceTest {      }      @Test +    public void vibrate_withoutBypassFlagsPermissions_bypassFlagsNotApplied() throws Exception { +        denyPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS); +        denyPermission(android.Manifest.permission.MODIFY_PHONE_STATE); +        denyPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING); + +        assertCanVibrateWithBypassFlags(false); +    } + +    @Test +    public void vibrate_withSecureSettingsPermission_bypassFlagsApplied() throws Exception { +        grantPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS); +        denyPermission(android.Manifest.permission.MODIFY_PHONE_STATE); +        denyPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING); + +        assertCanVibrateWithBypassFlags(true); +    } + +    @Test +    public void vibrate_withModifyPhoneStatePermission_bypassFlagsApplied() throws Exception { +        denyPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS); +        grantPermission(android.Manifest.permission.MODIFY_PHONE_STATE); +        denyPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING); + +        assertCanVibrateWithBypassFlags(true); +    } + +    @Test +    public void vibrate_withModifyAudioRoutingPermission_bypassFlagsApplied() throws Exception { +        denyPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS); +        denyPermission(android.Manifest.permission.MODIFY_PHONE_STATE); +        grantPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING); + +        assertCanVibrateWithBypassFlags(true); +    } + +    @Test      public void vibrate_withRingtone_usesRingerModeSettings() throws Exception {          mockVibrators(1);          FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); @@ -1166,7 +1208,7 @@ public class VibratorManagerServiceTest {      }      @Test -    public void vibrate_withTriggerCallback_finishesVibration() throws Exception { +    public void vibrate_withriggerCallback_finishesVibration() throws Exception {          mockCapabilities(IVibratorManager.CAP_SYNC, IVibratorManager.CAP_PREPARE_COMPOSE);          mockVibrators(1, 2);          mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); @@ -1303,10 +1345,18 @@ public class VibratorManagerServiceTest {      }      @Test -    public void performHapticFeedback_doesNotRequirePermission() throws Exception { +    public void performHapticFeedback_doesNotRequireVibrateOrBypassPermissions() throws Exception { +        // Deny permissions that would have been required for regular vibrations, and check that +        // the vibration proceed as expected to verify that haptic feedback does not need these +        // permissions.          denyPermission(android.Manifest.permission.VIBRATE); +        denyPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS); +        denyPermission(android.Manifest.permission.MODIFY_PHONE_STATE); +        denyPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING); +        // Flag override to enable the scroll feedack constants to bypass interruption policies. +        when(mViewFeatureFlags.scrollFeedbackApi()).thenReturn(true);          mHapticFeedbackVibrationMap.put( -                HapticFeedbackConstants.KEYBOARD_TAP, +                HapticFeedbackConstants.SCROLL_TICK,                  VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));          mockVibrators(1);          FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); @@ -1315,13 +1365,16 @@ public class VibratorManagerServiceTest {          HalVibration vibration =                  performHapticFeedbackAndWaitUntilFinished( -                        service, HapticFeedbackConstants.KEYBOARD_TAP, /* always= */ true); +                        service, HapticFeedbackConstants.SCROLL_TICK, /* always= */ true);          List<VibrationEffectSegment> playedSegments = fakeVibrator.getAllEffectSegments();          assertEquals(1, playedSegments.size());          PrebakedSegment segment = (PrebakedSegment) playedSegments.get(0);          assertEquals(VibrationEffect.EFFECT_CLICK, segment.getEffectId()); -        assertEquals(VibrationAttributes.USAGE_TOUCH, vibration.callerInfo.attrs.getUsage()); +        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));      }      @Test @@ -2261,6 +2314,31 @@ public class VibratorManagerServiceTest {          assertNull(metrics.halUnsupportedEffectsUsed);      } +    private void assertCanVibrateWithBypassFlags(boolean expectedCanApplyBypassFlags) +            throws Exception { +        mockVibrators(1); +        mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK); +        VibratorManagerService service = createSystemReadyService(); + +        HalVibration vibration = vibrateAndWaitUntilFinished( +                service, +                VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), +                new VibrationAttributes.Builder() +                        .setUsage(VibrationAttributes.USAGE_TOUCH) +                        .setFlags( +                                VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF +                                        | VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) +                        .build()); + +        VibrationAttributes attrs = vibration.callerInfo.attrs; +        assertEquals( +                expectedCanApplyBypassFlags, +                attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)); +        assertEquals( +                expectedCanApplyBypassFlags, +                attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY)); +    } +      private VibrationEffectSegment expectedPrebaked(int effectId) {          return expectedPrebaked(effectId, VibrationEffect.EFFECT_STRENGTH_MEDIUM);      } @@ -2327,12 +2405,13 @@ public class VibratorManagerServiceTest {          return vib;      } -    private void vibrateAndWaitUntilFinished(VibratorManagerService service, VibrationEffect effect, -            VibrationAttributes attrs) throws InterruptedException { -        vibrateAndWaitUntilFinished(service, CombinedVibration.createParallel(effect), attrs); +    private HalVibration vibrateAndWaitUntilFinished(VibratorManagerService service, +            VibrationEffect effect, VibrationAttributes attrs) throws InterruptedException { +        return vibrateAndWaitUntilFinished( +                service, CombinedVibration.createParallel(effect), attrs);      } -    private void vibrateAndWaitUntilFinished(VibratorManagerService service, +    private HalVibration vibrateAndWaitUntilFinished(VibratorManagerService service,              CombinedVibration effect, VibrationAttributes attrs) throws InterruptedException {          HalVibration vib =                  service.vibrateWithPermissionCheck(UID, Display.DEFAULT_DISPLAY, PACKAGE_NAME, @@ -2340,6 +2419,8 @@ public class VibratorManagerServiceTest {          if (vib != null) {              vib.waitForEnd();          } + +        return vib;      }      private void vibrate(VibratorManagerService service, VibrationEffect effect, @@ -2368,7 +2449,15 @@ public class VibratorManagerServiceTest {          return predicateResult;      } +    private void grantPermission(String permission) { +        when(mContextSpy.checkCallingOrSelfPermission(permission)) +                .thenReturn(PackageManager.PERMISSION_GRANTED); +        doNothing().when(mContextSpy).enforceCallingOrSelfPermission(eq(permission), anyString()); +    } +      private void denyPermission(String permission) { +        when(mContextSpy.checkCallingOrSelfPermission(permission)) +                .thenReturn(PackageManager.PERMISSION_DENIED);          doThrow(new SecurityException()).when(mContextSpy)                  .enforceCallingOrSelfPermission(eq(permission), anyString());      } diff --git a/services/tests/voiceinteractiontests/Android.bp b/services/tests/voiceinteractiontests/Android.bp index e704ebf32270..744cb63f72b3 100644 --- a/services/tests/voiceinteractiontests/Android.bp +++ b/services/tests/voiceinteractiontests/Android.bp @@ -43,7 +43,7 @@ android_test {          "services.soundtrigger",          "servicestests-core-utils",          "servicestests-utils-mockito-extended", -        "truth-prebuilt", +        "truth",      ],      libs: [ diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp index c2812a14a3eb..af39b2f027ee 100644 --- a/services/tests/wmtests/Android.bp +++ b/services/tests/wmtests/Android.bp @@ -57,12 +57,14 @@ android_test {          "platform-test-annotations",          "servicestests-utils",          "testng", -        "truth-prebuilt", +        "truth",          "testables",          "hamcrest-library",          "platform-compat-test-rules",          "CtsSurfaceValidatorLib",          "service-sdksandbox.impl", +        "com.android.window.flags.window-aconfig-java", +        "flag-junit",      ],      libs: [ diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml index 42e3383987d6..762e23c8e288 100644 --- a/services/tests/wmtests/AndroidManifest.xml +++ b/services/tests/wmtests/AndroidManifest.xml @@ -47,6 +47,8 @@      <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>      <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"/> +    <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/> +    <uses-permission android:name="android.permission.MONITOR_INPUT"/>      <!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) -->      <application android:debuggable="true" @@ -104,6 +106,11 @@              android:showWhenLocked="true"              android:turnScreenOn="true" /> +        <activity android:name="android.app.Activity" +            android:exported="true" +            android:showWhenLocked="true" +            android:turnScreenOn="true" /> +          <activity              android:name="androidx.test.core.app.InstrumentationActivityInvoker$EmptyActivity"              android:exported="true"> diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java index 0a7bb00ce1c2..71098aa5e883 100644 --- a/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java @@ -20,6 +20,7 @@ import static com.android.server.policy.PhoneWindowManager.DOUBLE_TAP_HOME_RECEN  import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_ALL_APPS;  import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_ASSIST;  import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_NOTIFICATION_PANEL; +import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL;  import android.platform.test.annotations.Presubmit;  import android.view.KeyEvent; @@ -284,6 +285,16 @@ public class ShortcutLoggingTests extends ShortcutKeyTestBase {                          KeyboardLogEvent.APP_SWITCH, KeyEvent.KEYCODE_H, META_ON}};      } +    @Keep +    private static Object[][] shortPressOnSettingsTestArguments() { +        // testName, testKeys, shortPressOnSettingsBehavior, expectedLogEvent, expectedKey, +        // expectedModifierState +        return new Object[][]{ +                {"SETTINGS key -> Toggle Notification panel", new int[]{KeyEvent.KEYCODE_SETTINGS}, +                        SHORT_PRESS_SETTINGS_NOTIFICATION_PANEL, +                        KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL, KeyEvent.KEYCODE_SETTINGS, 0}}; +    } +      @Before      public void setUp() {          setUpPhoneWindowManager(/*supportSettingsUpdate*/ true); @@ -294,6 +305,7 @@ public class ShortcutLoggingTests extends ShortcutKeyTestBase {          mPhoneWindowManager.overrideEnableBugReportTrigger(true);          mPhoneWindowManager.overrideStatusBarManagerInternal();          mPhoneWindowManager.overrideStartActivity(); +        mPhoneWindowManager.overrideSendBroadcast();          mPhoneWindowManager.overrideUserSetupComplete();          mPhoneWindowManager.setupAssistForLaunch();          mPhoneWindowManager.overrideTogglePanel(); @@ -330,4 +342,15 @@ public class ShortcutLoggingTests extends ShortcutKeyTestBase {          mPhoneWindowManager.assertShortcutLogged(VENDOR_ID, PRODUCT_ID, expectedLogEvent,                  expectedKey, expectedModifierState, "Failed while executing " + testName);      } + +    @Test +    @Parameters(method = "shortPressOnSettingsTestArguments") +    public void testShortPressOnSettings(String testName, int[] testKeys, +            int shortPressOnSettingsBehavior, KeyboardLogEvent expectedLogEvent, int expectedKey, +            int expectedModifierState) { +        mPhoneWindowManager.overrideShortPressOnSettingsBehavior(shortPressOnSettingsBehavior); +        sendKeyCombination(testKeys, 0 /* duration */); +        mPhoneWindowManager.assertShortcutLogged(VENDOR_ID, PRODUCT_ID, expectedLogEvent, +                expectedKey, expectedModifierState, "Failed while executing " + testName); +    }  } diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java index ef28ffa7da8f..2244dbe8af98 100644 --- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java +++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java @@ -375,6 +375,10 @@ class TestPhoneWindowManager {          mPhoneWindowManager.mDoubleTapOnHomeBehavior = behavior;      } +    void overrideShortPressOnSettingsBehavior(int behavior) { +        mPhoneWindowManager.mShortPressOnSettingsBehavior = behavior; +    } +      void overrideCanStartDreaming(boolean canDream) {          doReturn(canDream).when(mDreamManagerInternal).canStartDreaming(anyBoolean());      } @@ -484,6 +488,10 @@ class TestPhoneWindowManager {          doNothing().when(mContext).startActivityAsUser(any(), any(), any());      } +    void overrideSendBroadcast() { +        doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any()); +    } +      void overrideUserSetupComplete() {          doReturn(true).when(mPhoneWindowManager).isUserSetupComplete();      } diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index 3bc6450ae591..c241033c69d3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -549,10 +549,12 @@ public class RootWindowContainerTests extends WindowTestsBase {          // Let's pretend that the app has crashed.          firstActivity.app.setThread(null); -        mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test"); +        final Task finishedTask = mRootWindowContainer.finishTopCrashedActivities( +                firstActivity.app, "test");          // Verify that the root task was removed.          assertEquals(originalRootTaskCount, defaultTaskDisplayArea.getRootTaskCount()); +        assertEquals(rootTask, finishedTask);      }      /** diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java index c1d51474b1cd..8119fd486a87 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java @@ -138,11 +138,11 @@ public class SurfaceControlViewHostTests {          IWindow window = IWindow.Stub.asInterface(mActivity.mSurfaceView.getWindowToken());          WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(window, -                mScvh1.getFocusGrantToken(), true); +                mScvh1.getInputTransferToken(), true);          assertTrue("Failed to gain focus for view1", waitForWindowFocus(mView1, true));          WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(window, -                mScvh2.getFocusGrantToken(), true); +                mScvh2.getInputTransferToken(), true);          assertTrue("Failed to gain focus for view2", waitForWindowFocus(mView2, true));      } diff --git a/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java b/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java new file mode 100644 index 000000000000..ac498397eb39 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java @@ -0,0 +1,217 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.app.Activity; +import android.app.Instrumentation; +import android.os.IBinder; +import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.server.wm.BuildUtils; +import android.server.wm.CtsWindowInfoUtils; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.WindowManager; + +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.window.flags.Flags; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +@Presubmit +public class TrustedOverlayTests { +    private static final String TAG = "TrustedOverlayTests"; +    private static final long TIMEOUT_S = 5L * BuildUtils.HW_TIMEOUT_MULTIPLIER; + +    @Rule +    public final CheckFlagsRule mCheckFlagsRule = +            DeviceFlagsValueProvider.createCheckFlagsRule(); + +    @Rule +    public TestName mName = new TestName(); + +    @Rule +    public final ActivityScenarioRule<Activity> mActivityRule = new ActivityScenarioRule<>( +            Activity.class); + +    private Instrumentation mInstrumentation; +    private Activity mActivity; + +    @Before +    public void setup() { +        mInstrumentation = InstrumentationRegistry.getInstrumentation(); +        mActivityRule.getScenario().onActivity(activity -> { +            mActivity = activity; +        }); +    } + +    @RequiresFlagsDisabled(Flags.FLAG_SURFACE_TRUSTED_OVERLAY) +    @Test +    public void setTrustedOverlayInputWindow() throws InterruptedException { +        testTrustedOverlayChildHelper(false); +    } + +    @Test +    @RequiresFlagsEnabled(Flags.FLAG_SURFACE_TRUSTED_OVERLAY) +    public void setTrustedOverlayChildLayer() throws InterruptedException { +        testTrustedOverlayChildHelper(true); +    } + +    /** +     * b/300659960 where setting spy window and trusted overlay were not happening in the same +     * transaction causing the system to crash. This ensures there are no synchronization issues +     * setting both spy window and trusted overlay. +     */ +    @Test +    public void setSpyWindowDoesntCrash() throws InterruptedException { +        IBinder[] tokens = new IBinder[1]; +        CountDownLatch hostTokenReady = new CountDownLatch(1); +        mInstrumentation.runOnMainSync(() -> { +            WindowManager.LayoutParams params = mActivity.getWindow().getAttributes(); +            params.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_SPY; +            params.privateFlags |= PRIVATE_FLAG_TRUSTED_OVERLAY; +            mActivity.getWindow().setAttributes(params); + +            View rootView = mActivity.getWindow().getDecorView(); +            if (rootView.isAttachedToWindow()) { +                tokens[0] = rootView.getWindowToken(); +                hostTokenReady.countDown(); +            } else { +                rootView.getViewTreeObserver().addOnWindowAttachListener( +                        new ViewTreeObserver.OnWindowAttachListener() { +                            @Override +                            public void onWindowAttached() { +                                tokens[0] = rootView.getWindowToken(); +                                hostTokenReady.countDown(); +                            } + +                            @Override +                            public void onWindowDetached() { +                            } +                        }); +            } +        }); + +        assertTrue("Failed to wait for host to get added", +                hostTokenReady.await(TIMEOUT_S, TimeUnit.SECONDS)); + +        boolean[] foundTrusted = new boolean[1]; +        CtsWindowInfoUtils.waitForWindowInfos( +                windowInfos -> { +                    for (var windowInfo : windowInfos) { +                        if (windowInfo.windowToken == tokens[0] && windowInfo.isTrustedOverlay) { +                            foundTrusted[0] = true; +                            return true; +                        } +                    } +                    return false; +                }, TIMEOUT_S, TimeUnit.SECONDS); + +        if (!foundTrusted[0]) { +            CtsWindowInfoUtils.dumpWindowsOnScreen(TAG, mName.getMethodName()); +        } + +        assertTrue("Failed to find window or was not marked trusted", foundTrusted[0]); +    } + +    private void testTrustedOverlayChildHelper(boolean expectedTrustedChild) +            throws InterruptedException { +        IBinder[] tokens = new IBinder[2]; +        CountDownLatch hostTokenReady = new CountDownLatch(1); +        mInstrumentation.runOnMainSync(() -> { +            mActivity.getWindow().addPrivateFlags(PRIVATE_FLAG_TRUSTED_OVERLAY); +            View rootView = mActivity.getWindow().getDecorView(); +            if (rootView.isAttachedToWindow()) { +                tokens[0] = rootView.getWindowToken(); +                hostTokenReady.countDown(); +            } else { +                rootView.getViewTreeObserver().addOnWindowAttachListener( +                        new ViewTreeObserver.OnWindowAttachListener() { +                            @Override +                            public void onWindowAttached() { +                                tokens[0] = rootView.getWindowToken(); +                                hostTokenReady.countDown(); +                            } + +                            @Override +                            public void onWindowDetached() { +                            } +                        }); +            } +        }); + +        assertTrue("Failed to wait for host to get added", +                hostTokenReady.await(TIMEOUT_S, TimeUnit.SECONDS)); + +        mInstrumentation.runOnMainSync(() -> { +            WindowManager wm = mActivity.getSystemService(WindowManager.class); + +            View childView = new View(mActivity) { +                @Override +                protected void onAttachedToWindow() { +                    super.onAttachedToWindow(); +                    tokens[1] = getWindowToken(); +                } +            }; +            WindowManager.LayoutParams params = new WindowManager.LayoutParams(); +            params.token = tokens[0]; +            params.type = TYPE_APPLICATION_PANEL; +            wm.addView(childView, params); +        }); + +        boolean[] foundTrusted = new boolean[2]; + +        CtsWindowInfoUtils.waitForWindowInfos( +                windowInfos -> { +                    for (var windowInfo : windowInfos) { +                        if (windowInfo.windowToken == tokens[0] +                                && windowInfo.isTrustedOverlay) { +                            foundTrusted[0] = true; +                        } else if (windowInfo.windowToken == tokens[1] +                                && windowInfo.isTrustedOverlay) { +                            foundTrusted[1] = true; +                        } +                    } +                    return foundTrusted[0] && foundTrusted[1]; +                }, TIMEOUT_S, TimeUnit.SECONDS); + +        if (!foundTrusted[0] || !foundTrusted[1]) { +            CtsWindowInfoUtils.dumpWindowsOnScreen(TAG, mName.getMethodName()); +        } + +        assertTrue("Failed to find parent window or was not marked trusted", foundTrusted[0]); +        assertEquals("Failed to find child window or was not marked trusted", expectedTrustedChild, +                foundTrusted[1]); +    } +} diff --git a/services/usage/java/com/android/server/usage/UsageStatsHandlerThread.java b/services/usage/java/com/android/server/usage/UsageStatsHandlerThread.java deleted file mode 100644 index 6801c9402538..000000000000 --- a/services/usage/java/com/android/server/usage/UsageStatsHandlerThread.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.usage; - -import android.os.Handler; -import android.os.HandlerExecutor; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Process; -import android.os.Trace; - -import java.util.concurrent.Executor; - -/** - * Shared singleton default priority thread for usage stats message handling. - * - * @see com.android.internal.os.BackgroundThread - */ -public final class UsageStatsHandlerThread extends HandlerThread { -    private static final long SLOW_DISPATCH_THRESHOLD_MS = 10_000; -    private static final long SLOW_DELIVERY_THRESHOLD_MS = 30_000; -    private static UsageStatsHandlerThread sInstance; -    private static Handler sHandler; -    private static Executor sHandlerExecutor; - -    private UsageStatsHandlerThread() { -        super("usagestats.default", Process.THREAD_PRIORITY_DEFAULT); -    } - -    private static void ensureThreadLocked() { -        if (sInstance == null) { -            sInstance = new UsageStatsHandlerThread(); -            sInstance.start(); -            final Looper looper = sInstance.getLooper(); -            looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); -            looper.setSlowLogThresholdMs( -                    SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS); -            sHandler = new Handler(sInstance.getLooper()); -            sHandlerExecutor = new HandlerExecutor(sHandler); -        } -    } - -    /** Returns the UsageStatsHandlerThread singleton */ -    public static UsageStatsHandlerThread get() { -        synchronized (UsageStatsHandlerThread.class) { -            ensureThreadLocked(); -            return sInstance; -        } -    } - -    /** Returns the singleton handler for UsageStatsHandlerThread */ -    public static Handler getHandler() { -        synchronized (UsageStatsHandlerThread.class) { -            ensureThreadLocked(); -            return sHandler; -        } -    } - -    /** Returns the singleton handler executor for UsageStatsHandlerThread */ -    public static Executor getExecutor() { -        synchronized (UsageStatsHandlerThread.class) { -            ensureThreadLocked(); -            return sHandlerExecutor; -        } -    } -} diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 18c960e3ebbc..f3bf026ddc6e 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -332,8 +332,7 @@ public class UsageStatsService extends SystemService implements          mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);          mPackageManager = getContext().getPackageManager();          mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); - -        mHandler = new H(UsageStatsHandlerThread.get().getLooper()); +        mHandler = new H(BackgroundThread.get().getLooper());          mIoHandler = new Handler(IoThread.get().getLooper(), mIoHandlerCallback);          mAppStandby = mInjector.getAppStandbyController(getContext()); @@ -495,9 +494,12 @@ public class UsageStatsService extends SystemService implements              Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "loadPendingEvents");              loadPendingEventsLocked(userId, pendingEvents);              Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); -            final LinkedList<Event> eventsInMem = mReportedEvents.get(userId); -            if (eventsInMem != null) { -                pendingEvents.addAll(eventsInMem); +            synchronized (mReportedEvents) { +                final LinkedList<Event> eventsInMem = mReportedEvents.get(userId); +                if (eventsInMem != null) { +                    pendingEvents.addAll(eventsInMem); +                    mReportedEvents.remove(userId); +                }              }              boolean needToFlush = !pendingEvents.isEmpty(); @@ -518,8 +520,7 @@ public class UsageStatsService extends SystemService implements              mIoHandler.obtainMessage(MSG_HANDLE_LAUNCH_TIME_ON_USER_UNLOCK,                      userId, 0).sendToTarget(); -            // Remove all the stats stored in memory and in system DE. -            mReportedEvents.remove(userId); +            // Remove all the stats stored in system DE.              deleteRecursively(new File(Environment.getDataSystemDeDirectory(userId), "usagestats"));              // Force a flush to disk for the current user to ensure important events are persisted. @@ -916,6 +917,7 @@ public class UsageStatsService extends SystemService implements          }      } +    @GuardedBy({"mLock", "mReportedEvents"})      private void persistPendingEventsLocked(int userId) {          final LinkedList<Event> pendingEvents = mReportedEvents.get(userId);          if (pendingEvents == null || pendingEvents.isEmpty()) { @@ -1019,7 +1021,7 @@ public class UsageStatsService extends SystemService implements                      + UserUsageStatsService.eventToString(event.mEventType);              Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, traceTag);          } -        synchronized (mLock) { +        synchronized (mReportedEvents) {              LinkedList<Event> events = mReportedEvents.get(userId);              if (events == null) {                  events = new LinkedList<>(); @@ -1943,16 +1945,19 @@ public class UsageStatsService extends SystemService implements                          idpw.println();                      }                  } else { -                    final LinkedList<Event> pendingEvents = mReportedEvents.get(userId); -                    if (pendingEvents != null && !pendingEvents.isEmpty()) { -                        final int eventCount = pendingEvents.size(); -                        idpw.println("Pending events: count=" + eventCount); -                        idpw.increaseIndent(); -                        for (int idx = 0; idx < eventCount; idx++) { -                            UserUsageStatsService.printEvent(idpw, pendingEvents.get(idx), true); +                    synchronized (mReportedEvents) { +                        final LinkedList<Event> pendingEvents = mReportedEvents.get(userId); +                        if (pendingEvents != null && !pendingEvents.isEmpty()) { +                            final int eventCount = pendingEvents.size(); +                            idpw.println("Pending events: count=" + eventCount); +                            idpw.increaseIndent(); +                            for (int idx = 0; idx < eventCount; idx++) { +                                UserUsageStatsService.printEvent(idpw, pendingEvents.get(idx), +                                        true); +                            } +                            idpw.decreaseIndent(); +                            idpw.println();                          } -                        idpw.decreaseIndent(); -                        idpw.println();                      }                  }                  idpw.decreaseIndent(); diff --git a/tests/BatteryStatsPerfTest/Android.bp b/tests/BatteryStatsPerfTest/Android.bp index 5233a5b8654e..c2a70151fa13 100644 --- a/tests/BatteryStatsPerfTest/Android.bp +++ b/tests/BatteryStatsPerfTest/Android.bp @@ -27,7 +27,7 @@ android_test {      static_libs: [          "androidx.test.rules",          "apct-perftests-utils", -        "truth-prebuilt", +        "truth",      ],      platform_apis: true,      certificate: "platform", diff --git a/tests/BinaryTransparencyHostTest/Android.bp b/tests/BinaryTransparencyHostTest/Android.bp index 615990f22e3c..38cb9869f165 100644 --- a/tests/BinaryTransparencyHostTest/Android.bp +++ b/tests/BinaryTransparencyHostTest/Android.bp @@ -30,7 +30,7 @@ java_test_host {          "compatibility-host-util",      ],      static_libs: [ -        "truth-prebuilt", +        "truth",      ],      data: [          ":BinaryTransparencyTestApp", diff --git a/tests/BlobStoreTestUtils/Android.bp b/tests/BlobStoreTestUtils/Android.bp index c4faf7f4fb11..1fb73e2c0967 100644 --- a/tests/BlobStoreTestUtils/Android.bp +++ b/tests/BlobStoreTestUtils/Android.bp @@ -22,12 +22,12 @@ package {  }  java_library { -  name: "BlobStoreTestUtils", -  srcs: ["src/**/*.java"], -  static_libs: [ -    "truth-prebuilt", -    "androidx.test.uiautomator_uiautomator", -    "androidx.test.ext.junit", -  ], -  sdk_version: "test_current", +    name: "BlobStoreTestUtils", +    srcs: ["src/**/*.java"], +    static_libs: [ +        "truth", +        "androidx.test.uiautomator_uiautomator", +        "androidx.test.ext.junit", +    ], +    sdk_version: "test_current",  } diff --git a/tests/ChoreographerTests/Android.bp b/tests/ChoreographerTests/Android.bp index ca3026705c63..5d49120ee702 100644 --- a/tests/ChoreographerTests/Android.bp +++ b/tests/ChoreographerTests/Android.bp @@ -34,7 +34,7 @@ android_test {          "androidx.test.rules",          "compatibility-device-util-axt",          "com.google.android.material_material", -        "truth-prebuilt", +        "truth",      ],      jni_libs: [          "libchoreographertests_jni", diff --git a/tests/CtsSurfaceControlTestsStaging/Android.bp b/tests/CtsSurfaceControlTestsStaging/Android.bp index 680952157fdc..96e4a9ea4300 100644 --- a/tests/CtsSurfaceControlTestsStaging/Android.bp +++ b/tests/CtsSurfaceControlTestsStaging/Android.bp @@ -37,7 +37,7 @@ android_test {          "compatibility-device-util-axt",          "com.google.android.material_material",          "SurfaceFlingerProperties", -        "truth-prebuilt", +        "truth",      ],      resource_dirs: ["src/main/res"],      certificate: "platform", diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.bp b/tests/DynamicCodeLoggerIntegrationTests/Android.bp index 448d46fe5e4e..3f2c80831565 100644 --- a/tests/DynamicCodeLoggerIntegrationTests/Android.bp +++ b/tests/DynamicCodeLoggerIntegrationTests/Android.bp @@ -47,7 +47,7 @@ android_test {      static_libs: [          "androidx.test.rules", -        "truth-prebuilt", +        "truth",      ],      compile_multilib: "both", diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp index a2ae56eaeadc..82aa85d55e4c 100644 --- a/tests/FlickerTests/Android.bp +++ b/tests/FlickerTests/Android.bp @@ -236,7 +236,7 @@ java_library {      static_libs: [          "flickerlib",          "flickerlib-helpers", -        "truth-prebuilt", +        "truth",          "app-helpers-core",      ],  } @@ -255,7 +255,7 @@ java_library {          "flickerlib",          "flickerlib-apphelpers",          "flickerlib-helpers", -        "truth-prebuilt", +        "truth",          "app-helpers-core",          "wm-flicker-window-extensions",      ], diff --git a/tests/FsVerityTest/TEST_MAPPING b/tests/FsVerityTest/TEST_MAPPING index 39944bed3f60..7d59d7765183 100644 --- a/tests/FsVerityTest/TEST_MAPPING +++ b/tests/FsVerityTest/TEST_MAPPING @@ -1,12 +1,7 @@  { -  "postsubmit": [ +  "presubmit": [      {        "name": "FsVerityTest" -    }, -    // nextgen test only runs during postsubmit. -    { -      "name": "FsVerityTest", -      "keywords": ["nextgen"]      }    ]  } diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp index 365e00e2b652..cf2d5d69552f 100644 --- a/tests/Input/Android.bp +++ b/tests/Input/Android.bp @@ -9,6 +9,10 @@ package {  android_test {      name: "InputTests", +    defaults: [ +        // For ExtendedMockito dependencies. +        "modules-utils-testable-device-config-defaults", +    ],      srcs: [          "src/**/*.java",          "src/**/*.kt", @@ -35,7 +39,7 @@ android_test {          "services.core.unboosted",          "testables",          "testng", -        "truth-prebuilt", +        "truth",      ],      libs: [          "android.test.mock", diff --git a/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt b/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt index b64775103ab2..fa86e9c4ec0a 100644 --- a/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt +++ b/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt @@ -32,11 +32,16 @@ import android.os.Bundle  import android.os.test.TestLooper  import android.platform.test.annotations.Presubmit  import android.provider.Settings +import android.util.proto.ProtoOutputStream  import android.view.InputDevice  import android.view.inputmethod.InputMethodInfo  import android.view.inputmethod.InputMethodSubtype  import androidx.test.core.R  import androidx.test.core.app.ApplicationProvider +import com.android.dx.mockito.inline.extended.ExtendedMockito +import com.android.internal.os.KeyboardConfiguredProto +import com.android.internal.util.FrameworkStatsLog +import com.android.modules.utils.testing.ExtendedMockitoRule  import org.junit.After  import org.junit.Assert.assertEquals  import org.junit.Assert.assertNotEquals @@ -46,9 +51,9 @@ import org.junit.Assert.assertThrows  import org.junit.Before  import org.junit.Rule  import org.junit.Test +import org.mockito.ArgumentMatchers  import org.mockito.Mock  import org.mockito.Mockito -import org.mockito.junit.MockitoJUnit  import java.io.FileNotFoundException  import java.io.FileOutputStream  import java.io.IOException @@ -96,6 +101,9 @@ class KeyboardLayoutManagerTests {          private const val ENGLISH_US_LAYOUT_NAME = "keyboard_layout_english_us"          private const val ENGLISH_UK_LAYOUT_NAME = "keyboard_layout_english_uk"          private const val VENDOR_SPECIFIC_LAYOUT_NAME = "keyboard_layout_vendorId:1,productId:1" +        const val LAYOUT_TYPE_QWERTZ = 2 +        const val LAYOUT_TYPE_QWERTY = 1 +        const val LAYOUT_TYPE_DEFAULT = 0      }      private val ENGLISH_US_LAYOUT_DESCRIPTOR = createLayoutDescriptor(ENGLISH_US_LAYOUT_NAME) @@ -103,8 +111,10 @@ class KeyboardLayoutManagerTests {      private val VENDOR_SPECIFIC_LAYOUT_DESCRIPTOR =          createLayoutDescriptor(VENDOR_SPECIFIC_LAYOUT_NAME) -    @get:Rule -    val rule = MockitoJUnit.rule()!! +    @JvmField +    @Rule +    val extendedMockitoRule = ExtendedMockitoRule.Builder(this) +            .mockStatic(FrameworkStatsLog::class.java).build()!!      @Mock      private lateinit var iInputManager: IInputManager @@ -145,7 +155,9 @@ class KeyboardLayoutManagerTests {              override fun finishWrite(fos: FileOutputStream?, success: Boolean) {}          })          testLooper = TestLooper() -        keyboardLayoutManager = KeyboardLayoutManager(context, native, dataStore, testLooper.looper) +        keyboardLayoutManager = Mockito.spy( +            KeyboardLayoutManager(context, native, dataStore, testLooper.looper) +        )          setupInputDevices()          setupBroadcastReceiver()          setupIme() @@ -827,6 +839,100 @@ class KeyboardLayoutManagerTests {          }      } +    @Test +    fun testConfigurationLogged_onInputDeviceAdded_VirtualKeyboardBasedSelection() { +        val imeInfos = listOf( +                KeyboardLayoutManager.ImeInfo(0, imeInfo, +                        createImeSubtypeForLanguageTagAndLayoutType("de-Latn", "qwertz"))) +        Mockito.doReturn(imeInfos).`when`(keyboardLayoutManager).imeInfoListForLayoutMapping +        NewSettingsApiFlag(true).use { +            keyboardLayoutManager.onInputDeviceAdded(keyboardDevice.id) +            ExtendedMockito.verify { +                FrameworkStatsLog.write( +                        ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED), +                        ArgumentMatchers.anyBoolean(), +                        ArgumentMatchers.eq(keyboardDevice.vendorId), +                        ArgumentMatchers.eq(keyboardDevice.productId), +                        ArgumentMatchers.eq(createByteArray( +                                KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG, +                                LAYOUT_TYPE_DEFAULT, +                                "German", +                                KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD, +                                "de-Latn", +                                LAYOUT_TYPE_QWERTZ)) +                ) +            } +        } +    } + +    @Test +    fun testConfigurationLogged_onInputDeviceAdded_DeviceBasedSelection() { +        val imeInfos = listOf( +                KeyboardLayoutManager.ImeInfo(0, imeInfo, +                        createImeSubtypeForLanguageTagAndLayoutType("de-Latn", "qwertz"))) +        Mockito.doReturn(imeInfos).`when`(keyboardLayoutManager).imeInfoListForLayoutMapping +        NewSettingsApiFlag(true).use { +            keyboardLayoutManager.onInputDeviceAdded(englishQwertyKeyboardDevice.id) +            ExtendedMockito.verify { +                FrameworkStatsLog.write( +                        ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED), +                        ArgumentMatchers.anyBoolean(), +                        ArgumentMatchers.eq(englishQwertyKeyboardDevice.vendorId), +                        ArgumentMatchers.eq(englishQwertyKeyboardDevice.productId), +                        ArgumentMatchers.eq(createByteArray( +                                "en", +                                LAYOUT_TYPE_QWERTY, +                                "English (US)", +                                KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEVICE, +                                "de-Latn", +                                LAYOUT_TYPE_QWERTZ)) +                ) +            } +        } +    } + +    @Test +    fun testConfigurationLogged_onInputDeviceAdded_DefaultSelection() { +        val imeInfos = listOf(KeyboardLayoutManager.ImeInfo(0, imeInfo, createImeSubtype())) +        Mockito.doReturn(imeInfos).`when`(keyboardLayoutManager).imeInfoListForLayoutMapping +        NewSettingsApiFlag(true).use { +            keyboardLayoutManager.onInputDeviceAdded(keyboardDevice.id) +            ExtendedMockito.verify { +                FrameworkStatsLog.write( +                        ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED), +                        ArgumentMatchers.anyBoolean(), +                        ArgumentMatchers.eq(keyboardDevice.vendorId), +                        ArgumentMatchers.eq(keyboardDevice.productId), +                        ArgumentMatchers.eq(createByteArray( +                                KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG, +                                LAYOUT_TYPE_DEFAULT, +                                "Default", +                                KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEFAULT, +                                KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG, +                                LAYOUT_TYPE_DEFAULT)) +                ) +            } +        } +    } + +    @Test +    fun testConfigurationNotLogged_onInputDeviceChanged() { +        val imeInfos = listOf(KeyboardLayoutManager.ImeInfo(0, imeInfo, createImeSubtype())) +        Mockito.doReturn(imeInfos).`when`(keyboardLayoutManager).imeInfoListForLayoutMapping +        NewSettingsApiFlag(true).use { +            keyboardLayoutManager.onInputDeviceChanged(keyboardDevice.id) +            ExtendedMockito.verify({ +                FrameworkStatsLog.write( +                        ArgumentMatchers.eq(FrameworkStatsLog.KEYBOARD_CONFIGURED), +                        ArgumentMatchers.anyBoolean(), +                        ArgumentMatchers.anyInt(), +                        ArgumentMatchers.anyInt(), +                        ArgumentMatchers.any(ByteArray::class.java) +                ) +            }, Mockito.times(0)) +        } +    } +      private fun assertCorrectLayout(          device: InputDevice,          imeSubtype: InputMethodSubtype, @@ -842,18 +948,60 @@ class KeyboardLayoutManagerTests {      }      private fun createImeSubtype(): InputMethodSubtype = -        InputMethodSubtype.InputMethodSubtypeBuilder().setSubtypeId(nextImeSubtypeId++).build() +            createImeSubtypeForLanguageTagAndLayoutType(null, null)      private fun createImeSubtypeForLanguageTag(languageTag: String): InputMethodSubtype = -        InputMethodSubtype.InputMethodSubtypeBuilder().setSubtypeId(nextImeSubtypeId++) -            .setLanguageTag(languageTag).build() +            createImeSubtypeForLanguageTagAndLayoutType(languageTag, null)      private fun createImeSubtypeForLanguageTagAndLayoutType( -        languageTag: String, -        layoutType: String -    ): InputMethodSubtype = -        InputMethodSubtype.InputMethodSubtypeBuilder().setSubtypeId(nextImeSubtypeId++) -            .setPhysicalKeyboardHint(ULocale.forLanguageTag(languageTag), layoutType).build() +            languageTag: String?, +            layoutType: String? +    ): InputMethodSubtype { +        val builder = InputMethodSubtype.InputMethodSubtypeBuilder() +                .setSubtypeId(nextImeSubtypeId++) +                .setIsAuxiliary(false) +                .setSubtypeMode("keyboard") +        if (languageTag != null && layoutType != null) { +            builder.setPhysicalKeyboardHint(ULocale.forLanguageTag(languageTag), layoutType) +        } else if (languageTag != null) { +            builder.setLanguageTag(languageTag) +        } +        return builder.build() +    } + +    private fun createByteArray( +            expectedLanguageTag: String, expectedLayoutType: Int, expectedLayoutName: String, +            expectedCriteria: Int, expectedImeLanguageTag: String, expectedImeLayoutType: Int): ByteArray { +        val proto = ProtoOutputStream() +        val keyboardLayoutConfigToken = proto.start( +                KeyboardConfiguredProto.RepeatedKeyboardLayoutConfig.KEYBOARD_LAYOUT_CONFIG) +        proto.write( +                KeyboardConfiguredProto.KeyboardLayoutConfig.KEYBOARD_LANGUAGE_TAG, +                expectedLanguageTag +        ) +        proto.write( +                KeyboardConfiguredProto.KeyboardLayoutConfig.KEYBOARD_LAYOUT_TYPE, +                expectedLayoutType +        ) +        proto.write( +                KeyboardConfiguredProto.KeyboardLayoutConfig.KEYBOARD_LAYOUT_NAME, +                expectedLayoutName +        ) +        proto.write( +                KeyboardConfiguredProto.KeyboardLayoutConfig.LAYOUT_SELECTION_CRITERIA, +                expectedCriteria +        ) +        proto.write( +                KeyboardConfiguredProto.KeyboardLayoutConfig.IME_LANGUAGE_TAG, +                expectedImeLanguageTag +        ) +        proto.write( +                KeyboardConfiguredProto.KeyboardLayoutConfig.IME_LAYOUT_TYPE, +                expectedImeLayoutType +        ) +        proto.end(keyboardLayoutConfigToken); +        return proto.bytes +    }      private fun hasLayout(layoutList: Array<KeyboardLayout>, layoutDesc: String): Boolean {          for (kl in layoutList) { diff --git a/tests/Input/src/com/android/server/input/FocusEventDebugViewTest.java b/tests/Input/src/com/android/server/input/debug/FocusEventDebugViewTest.java index 1b98887199e3..ae7fb3b29f6c 100644 --- a/tests/Input/src/com/android/server/input/FocusEventDebugViewTest.java +++ b/tests/Input/src/com/android/server/input/debug/FocusEventDebugViewTest.java @@ -14,15 +14,16 @@   * limitations under the License.   */ -package com.android.server.input; +package com.android.server.input.debug; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.anyFloat;  import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.anyLong;  import static org.mockito.Mockito.anyString;  import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify;  import static org.mockito.Mockito.when;  import android.content.Context; @@ -31,11 +32,12 @@ import android.view.InputDevice;  import android.view.MotionEvent;  import android.view.MotionEvent.PointerCoords;  import android.view.MotionEvent.PointerProperties; -import android.view.ViewConfiguration;  import androidx.test.InstrumentationRegistry;  import androidx.test.runner.AndroidJUnit4; +import com.android.server.input.InputManagerService; +  import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith; @@ -48,76 +50,50 @@ import org.junit.runner.RunWith;  public class FocusEventDebugViewTest {      private FocusEventDebugView mFocusEventDebugView; -    private FocusEventDebugView.RotaryInputValueView mRotaryInputValueView; -    private FocusEventDebugView.RotaryInputGraphView mRotaryInputGraphView; -    private float mScaledVerticalScrollFactor; +    private RotaryInputValueView mRotaryInputValueView; +    private RotaryInputGraphView mRotaryInputGraphView;      @Before      public void setUp() throws Exception {          Context context = InstrumentationRegistry.getContext(); -        mScaledVerticalScrollFactor = -                ViewConfiguration.get(context).getScaledVerticalScrollFactor();          InputManagerService mockService = mock(InputManagerService.class);          when(mockService.monitorInput(anyString(), anyInt()))                  .thenReturn(InputChannel.openInputChannelPair("FocusEventDebugViewTest")[1]); -        mRotaryInputValueView = new FocusEventDebugView.RotaryInputValueView(context); -        mRotaryInputGraphView = new FocusEventDebugView.RotaryInputGraphView(context); +        mRotaryInputValueView = spy(new RotaryInputValueView(context)); +        mRotaryInputGraphView = spy(new RotaryInputGraphView(context));          mFocusEventDebugView = new FocusEventDebugView(context, mockService,                  () -> mRotaryInputValueView, () -> mRotaryInputGraphView);      }      @Test -    public void startsRotaryInputValueViewWithDefaultValue() { -        assertEquals("+0.0", mRotaryInputValueView.getText()); -    } - -    @Test -    public void startsRotaryInputGraphViewWithDefaultFrameCenter() { -        assertEquals(0, mRotaryInputGraphView.getFrameCenterPosition(), 0.01); -    } - -    @Test -    public void handleRotaryInput_updatesRotaryInputValueViewWithScrollValue() { -        mFocusEventDebugView.handleUpdateShowRotaryInput(true); - -        mFocusEventDebugView.handleRotaryInput(createRotaryMotionEvent(0.5f)); - -        assertEquals(String.format("+%.1f", 0.5f * mScaledVerticalScrollFactor), -                mRotaryInputValueView.getText()); -    } - -    @Test -    public void handleRotaryInput_translatesRotaryInputGraphViewWithHighScrollValue() { +    public void handleRotaryInput_sendsMotionEventWhenEnabled() {          mFocusEventDebugView.handleUpdateShowRotaryInput(true); -        mFocusEventDebugView.handleRotaryInput(createRotaryMotionEvent(1000f)); +        mFocusEventDebugView.handleRotaryInput(createRotaryMotionEvent(0.5f,  10L)); -        assertTrue(mRotaryInputGraphView.getFrameCenterPosition() > 0); +        verify(mRotaryInputGraphView).addValue(0.5f, 10L); +        verify(mRotaryInputValueView).updateValue(0.5f);      }      @Test -    public void updateActivityStatus_setsAndRemovesColorFilter() { -        // It should not be active initially. -        assertNull(mRotaryInputValueView.getBackground().getColorFilter()); +    public void handleRotaryInput_doesNotSendMotionEventWhenDisabled() { +        mFocusEventDebugView.handleUpdateShowRotaryInput(false); -        mRotaryInputValueView.updateActivityStatus(true); -        // It should be active after rotary input. -        assertNotNull(mRotaryInputValueView.getBackground().getColorFilter()); +        mFocusEventDebugView.handleRotaryInput(createRotaryMotionEvent(0.5f, 10L)); -        mRotaryInputValueView.updateActivityStatus(false); -        // It should not be active after waiting for mUpdateActivityStatusCallback. -        assertNull(mRotaryInputValueView.getBackground().getColorFilter()); +        verify(mRotaryInputGraphView, never()).addValue(anyFloat(), anyLong()); +        verify(mRotaryInputValueView, never()).updateValue(anyFloat());      } -    private MotionEvent createRotaryMotionEvent(float scrollAxisValue) { +    private MotionEvent createRotaryMotionEvent(float scrollAxisValue, long eventTime) {          PointerCoords pointerCoords = new PointerCoords();          pointerCoords.setAxisValue(MotionEvent.AXIS_SCROLL, scrollAxisValue);          PointerProperties pointerProperties = new PointerProperties();          return MotionEvent.obtain(                  /* downTime */ 0, -                /* eventTime */ 0, +                /* eventTime */ eventTime,                  /* action */ MotionEvent.ACTION_SCROLL,                  /* pointerCount */ 1,                  /* pointerProperties */ new PointerProperties[] {pointerProperties}, diff --git a/tests/Input/src/com/android/server/input/debug/RotaryInputGraphViewTest.java b/tests/Input/src/com/android/server/input/debug/RotaryInputGraphViewTest.java new file mode 100644 index 000000000000..af6ece414fd1 --- /dev/null +++ b/tests/Input/src/com/android/server/input/debug/RotaryInputGraphViewTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.input.debug; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.content.Context; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Build/Install/Run: + * atest RotaryInputGraphViewTest + */ +@RunWith(AndroidJUnit4.class) +public class RotaryInputGraphViewTest { + +    private RotaryInputGraphView mRotaryInputGraphView; + +    @Before +    public void setUp() throws Exception { +        Context context = InstrumentationRegistry.getContext(); + +        mRotaryInputGraphView = new RotaryInputGraphView(context); +    } + +    @Test +    public void startsWithDefaultFrameCenter() { +        assertEquals(0, mRotaryInputGraphView.getFrameCenterPosition(), 0.01); +    } + +    @Test +    public void addValue_translatesRotaryInputGraphViewWithHighScrollValue() { +        final float scrollAxisValue = 1000f; +        final long eventTime = 0; + +        mRotaryInputGraphView.addValue(scrollAxisValue, eventTime); + +        assertTrue(mRotaryInputGraphView.getFrameCenterPosition() > 0); +    } +} diff --git a/tests/Input/src/com/android/server/input/debug/RotaryInputValueViewTest.java b/tests/Input/src/com/android/server/input/debug/RotaryInputValueViewTest.java new file mode 100644 index 000000000000..e5e3852dc318 --- /dev/null +++ b/tests/Input/src/com/android/server/input/debug/RotaryInputValueViewTest.java @@ -0,0 +1,85 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.input.debug; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import android.content.Context; +import android.view.ViewConfiguration; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Locale; + +/** + * Build/Install/Run: + * atest RotaryInputValueViewTest + */ +@RunWith(AndroidJUnit4.class) +public class RotaryInputValueViewTest { + +    private final Locale mDefaultLocale = Locale.getDefault(); + +    private RotaryInputValueView mRotaryInputValueView; +    private float mScaledVerticalScrollFactor; + +    @Before +    public void setUp() throws Exception { +        Context context = InstrumentationRegistry.getContext(); +        mScaledVerticalScrollFactor = +                ViewConfiguration.get(context).getScaledVerticalScrollFactor(); + +        mRotaryInputValueView = new RotaryInputValueView(context); +    } + +    @Test +    public void startsWithDefaultValue() { +        assertEquals("+0.0", mRotaryInputValueView.getText().toString()); +    } + +    @Test +    public void updateValue_updatesTextWithScrollValue() { +        final float scrollAxisValue = 1000f; +        final String expectedText = String.format(mDefaultLocale, "+%.1f", +                scrollAxisValue * mScaledVerticalScrollFactor); + +        mRotaryInputValueView.updateValue(scrollAxisValue); + +        assertEquals(expectedText, mRotaryInputValueView.getText().toString()); +    } + +    @Test +    public void updateActivityStatus_setsAndRemovesColorFilter() { +        // It should not be active initially. +        assertNull(mRotaryInputValueView.getBackground().getColorFilter()); + +        mRotaryInputValueView.updateActivityStatus(true); +        // It should be active after rotary input. +        assertNotNull(mRotaryInputValueView.getBackground().getColorFilter()); + +        mRotaryInputValueView.updateActivityStatus(false); +        // It should not be active after waiting for mUpdateActivityStatusCallback. +        assertNull(mRotaryInputValueView.getBackground().getColorFilter()); +    } +} diff --git a/tests/InputMethodStressTest/Android.bp b/tests/InputMethodStressTest/Android.bp index 84845c69fb27..58ceb3f3edf4 100644 --- a/tests/InputMethodStressTest/Android.bp +++ b/tests/InputMethodStressTest/Android.bp @@ -26,7 +26,7 @@ android_test {          "compatibility-device-util-axt",          "platform-test-annotations",          "platform-test-rules", -        "truth-prebuilt", +        "truth",      ],      test_suites: [          "general-tests", diff --git a/tests/InputScreenshotTest/Android.bp b/tests/InputScreenshotTest/Android.bp index eee486f99748..15aaa463cce7 100644 --- a/tests/InputScreenshotTest/Android.bp +++ b/tests/InputScreenshotTest/Android.bp @@ -29,7 +29,7 @@ android_test {          "androidx.lifecycle_lifecycle-livedata-ktx",          "androidx.lifecycle_lifecycle-runtime-compose",          "androidx.navigation_navigation-compose", -        "truth-prebuilt", +        "truth",          "androidx.compose.runtime_runtime",          "androidx.test.core",          "androidx.test.ext.junit", @@ -47,7 +47,7 @@ android_test {          "services.core.unboosted",          "testables",          "testng", -        "truth-prebuilt", +        "truth",      ],      libs: [          "android.test.mock", diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp index ef45864dd93b..ddec8fa1d70a 100644 --- a/tests/Internal/Android.bp +++ b/tests/Internal/Android.bp @@ -19,7 +19,7 @@ android_test {          "junit",          "androidx.test.rules",          "mockito-target-minus-junit4", -        "truth-prebuilt", +        "truth",          "platform-test-annotations",      ],      java_resource_dirs: ["res"], diff --git a/tests/LocalizationTest/Android.bp b/tests/LocalizationTest/Android.bp index 4e0b0a89d972..909ca5972552 100644 --- a/tests/LocalizationTest/Android.bp +++ b/tests/LocalizationTest/Android.bp @@ -34,7 +34,7 @@ android_test {          "androidx.test.ext.junit",          "androidx.test.rules",          "mockito-target-extended-minus-junit4", -        "truth-prebuilt", +        "truth",      ],      jni_libs: [          // For mockito extended diff --git a/tests/MidiTests/Android.bp b/tests/MidiTests/Android.bp index 254770d21818..fcacab3fb13c 100644 --- a/tests/MidiTests/Android.bp +++ b/tests/MidiTests/Android.bp @@ -31,7 +31,7 @@ android_test {          "mockito-target-inline-minus-junit4",          "platform-test-annotations",          "services.midi", -        "truth-prebuilt", +        "truth",      ],      jni_libs: ["libdexmakerjvmtiagent"],      certificate: "platform", diff --git a/tests/PackageWatchdog/Android.bp b/tests/PackageWatchdog/Android.bp index 1e1dc8458560..e0e6c4c43b16 100644 --- a/tests/PackageWatchdog/Android.bp +++ b/tests/PackageWatchdog/Android.bp @@ -32,7 +32,7 @@ android_test {          "androidx.test.rules",          "services.core",          "services.net", -        "truth-prebuilt", +        "truth",      ],      libs: ["android.test.runner"],      jni_libs: [ diff --git a/tests/PlatformCompatGating/Android.bp b/tests/PlatformCompatGating/Android.bp index f0f9c4bdd721..fd992cf415cf 100644 --- a/tests/PlatformCompatGating/Android.bp +++ b/tests/PlatformCompatGating/Android.bp @@ -38,7 +38,7 @@ android_test {          "androidx.test.ext.junit",          "mockito-target-minus-junit4",          "testng", -        "truth-prebuilt", +        "truth",          "platform-compat-test-rules",      ],  } diff --git a/tests/PlatformCompatGating/test-rules/Android.bp b/tests/PlatformCompatGating/test-rules/Android.bp index 5f91f9d0e505..f6a41c2f44b7 100644 --- a/tests/PlatformCompatGating/test-rules/Android.bp +++ b/tests/PlatformCompatGating/test-rules/Android.bp @@ -29,7 +29,7 @@ java_library {      static_libs: [          "junit",          "androidx.test.core", -        "truth-prebuilt", -        "core-compat-test-rules" +        "truth", +        "core-compat-test-rules",      ],  } diff --git a/tests/SurfaceViewBufferTests/Android.bp b/tests/SurfaceViewBufferTests/Android.bp index 38313f85c31d..055d6258d1ac 100644 --- a/tests/SurfaceViewBufferTests/Android.bp +++ b/tests/SurfaceViewBufferTests/Android.bp @@ -45,7 +45,7 @@ android_test {          "kotlinx-coroutines-android",          "flickerlib",          "flickerlib-trace_processor_shell", -        "truth-prebuilt", +        "truth",          "cts-wm-util",          "CtsSurfaceValidatorLib",      ], diff --git a/tests/TaskOrganizerTest/Android.bp b/tests/TaskOrganizerTest/Android.bp index bf12f423f145..d2ade34148e2 100644 --- a/tests/TaskOrganizerTest/Android.bp +++ b/tests/TaskOrganizerTest/Android.bp @@ -43,6 +43,6 @@ android_test {          "kotlinx-coroutines-android",          "flickerlib",          "flickerlib-trace_processor_shell", -        "truth-prebuilt", +        "truth",      ],  } diff --git a/tests/TelephonyCommonTests/Android.bp b/tests/TelephonyCommonTests/Android.bp index 81ec265c2c29..b968e5d81148 100644 --- a/tests/TelephonyCommonTests/Android.bp +++ b/tests/TelephonyCommonTests/Android.bp @@ -32,11 +32,11 @@ android_test {      static_libs: [          "mockito-target-extended",          "androidx.test.rules", -        "truth-prebuilt", +        "truth",          "platform-test-annotations",          "androidx.core_core",          "androidx.fragment_fragment", -        "androidx.test.ext.junit" +        "androidx.test.ext.junit",      ],      jni_libs: ["libdexmakerjvmtiagent"], diff --git a/tests/TrustTests/Android.bp b/tests/TrustTests/Android.bp index c216bced81f0..4e75a1d02a41 100644 --- a/tests/TrustTests/Android.bp +++ b/tests/TrustTests/Android.bp @@ -28,7 +28,7 @@ android_test {          "flag-junit",          "mockito-target-minus-junit4",          "servicestests-utils", -        "truth-prebuilt", +        "truth",      ],      libs: [          "android.test.runner", diff --git a/tests/UpdatableSystemFontTest/Android.bp b/tests/UpdatableSystemFontTest/Android.bp index 9bfcc18ee301..ddb3649a8320 100644 --- a/tests/UpdatableSystemFontTest/Android.bp +++ b/tests/UpdatableSystemFontTest/Android.bp @@ -30,7 +30,7 @@ android_test {          "androidx.test.uiautomator_uiautomator",          "compatibility-device-util-axt",          "platform-test-annotations", -        "truth-prebuilt", +        "truth",      ],      test_suites: [          "general-tests", diff --git a/tests/UsbManagerTests/Android.bp b/tests/UsbManagerTests/Android.bp index 97fbf5b32035..c02d8e96abb0 100644 --- a/tests/UsbManagerTests/Android.bp +++ b/tests/UsbManagerTests/Android.bp @@ -31,7 +31,7 @@ android_test {          "androidx.test.rules",          "mockito-target-inline-minus-junit4",          "platform-test-annotations", -        "truth-prebuilt", +        "truth",          "UsbManagerTestLib",      ],      jni_libs: ["libdexmakerjvmtiagent"], diff --git a/tests/UsbManagerTests/lib/Android.bp b/tests/UsbManagerTests/lib/Android.bp index 994484cd63bf..4e5a70fef0ca 100644 --- a/tests/UsbManagerTests/lib/Android.bp +++ b/tests/UsbManagerTests/lib/Android.bp @@ -34,7 +34,7 @@ android_library {          "services.core",          "services.net",          "services.usb", -        "truth-prebuilt", +        "truth",          "androidx.core_core",      ],      libs: [ diff --git a/tests/UsbTests/Android.bp b/tests/UsbTests/Android.bp index c60c519ec4d4..92c271165ad7 100644 --- a/tests/UsbTests/Android.bp +++ b/tests/UsbTests/Android.bp @@ -34,7 +34,7 @@ android_test {          "services.core",          "services.net",          "services.usb", -        "truth-prebuilt", +        "truth",          "UsbManagerTestLib",      ],      jni_libs: [ diff --git a/tests/componentalias/Android.bp b/tests/componentalias/Android.bp index 01d34e4ff645..39037f22fdcb 100644 --- a/tests/componentalias/Android.bp +++ b/tests/componentalias/Android.bp @@ -25,7 +25,7 @@ java_defaults {          "androidx.test.rules",          "compatibility-device-util-axt",          "mockito-target-extended-minus-junit4", -        "truth-prebuilt", +        "truth",      ],      libs: ["android.test.base"],      srcs: [ diff --git a/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp b/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp index e7fb2debfc4e..b71e5c47c70e 100644 --- a/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp +++ b/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp @@ -24,7 +24,7 @@ java_library_host {      ],      static_libs: [          "junit", -        "truth-prebuilt", +        "truth",          "mockito",          // http://cs/h/googleplex-android/platform/superproject/main/+/main:platform_testing/libraries/annotations/src/android/platform/test/annotations/ diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp index 05d6a43cdb0f..f9dc305a4e3e 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp @@ -104,7 +104,7 @@ java_library_host {      ],      static_libs: [          "junit", -        "truth-prebuilt", +        "truth",          // http://cs/h/googleplex-android/platform/superproject/main/+/main:platform_testing/libraries/annotations/src/android/platform/test/annotations/          "platform-test-annotations", diff --git a/tools/processors/immutability/Android.bp b/tools/processors/immutability/Android.bp index a7d69039fcb0..ecc283b0b37e 100644 --- a/tools/processors/immutability/Android.bp +++ b/tools/processors/immutability/Android.bp @@ -50,7 +50,7 @@ java_test_host {      static_libs: [          "compile-testing-prebuilt", -        "truth-prebuilt", +        "truth",          "junit",          "kotlin-reflect",          "ImmutabilityAnnotationProcessorHostLibrary", diff --git a/tools/processors/intdef_mappings/Android.bp b/tools/processors/intdef_mappings/Android.bp index 7059c52ddc76..9c755b7d58c2 100644 --- a/tools/processors/intdef_mappings/Android.bp +++ b/tools/processors/intdef_mappings/Android.bp @@ -38,7 +38,7 @@ java_test_host {      static_libs: [          "compile-testing-prebuilt", -        "truth-prebuilt", +        "truth",          "junit",          "guava",          "libintdef-annotation-processor", diff --git a/wifi/tests/Android.bp b/wifi/tests/Android.bp index 7a299694741a..5a0f742372d7 100644 --- a/wifi/tests/Android.bp +++ b/wifi/tests/Android.bp @@ -40,7 +40,7 @@ android_test {          "frameworks-base-testutils",          "guava",          "mockito-target-minus-junit4", -        "truth-prebuilt", +        "truth",      ],      libs: [  |