summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/uiautomator/cmds/uiautomator/src/com/android/commands/uiautomator/DumpCommand.java2
-rw-r--r--cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java2
-rw-r--r--cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java2
-rw-r--r--core/api/current.txt1
-rw-r--r--core/java/android/app/ActivityManager.java3
-rw-r--r--core/java/android/app/TaskInfo.java2
-rw-r--r--core/java/android/content/AttributionSource.java20
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java6
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java35
-rwxr-xr-xcore/java/android/os/Build.java5
-rw-r--r--core/java/android/service/dreams/DreamActivity.java10
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java2
-rw-r--r--core/java/android/service/quicksettings/TileService.java2
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java166
-rw-r--r--core/java/android/view/ViewRootImpl.java7
-rw-r--r--core/java/android/view/Window.java5
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java35
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java9
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java249
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java31
-rw-r--r--core/java/com/android/internal/protolog/BaseProtoLogImpl.java13
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogImpl.java12
-rw-r--r--core/res/AndroidManifest.xml6
-rw-r--r--core/res/res/values-fa/strings.xml2
-rw-r--r--core/res/res/values-hy/strings.xml2
-rw-r--r--core/res/res/values-it/strings.xml2
-rw-r--r--core/res/res/values-ru/strings.xml4
-rw-r--r--core/res/res/values/config.xml5
-rw-r--r--core/res/res/values/symbols.xml3
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsResetTest.java362
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java8
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java6
-rw-r--r--libs/WindowManager/Shell/res/color-night/taskbar_background.xml (renamed from libs/WindowManager/Shell/res/color/split_divider_background.xml)3
-rw-r--r--libs/WindowManager/Shell/res/color/taskbar_background.xml2
-rw-r--r--libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml2
-rw-r--r--libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml25
-rw-r--r--libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml4
-rw-r--r--libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-night/colors.xml1
-rw-r--r--libs/WindowManager/Shell/res/values/colors.xml6
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml6
-rw-r--r--libs/WindowManager/Shell/res/values/styles.xml12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java112
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java29
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java35
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java211
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java98
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java40
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java14
-rw-r--r--libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java30
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java8
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt247
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java22
-rw-r--r--libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java9
-rw-r--r--libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.java111
-rw-r--r--libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java39
-rw-r--r--libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.java113
-rw-r--r--media/java/android/media/projection/OWNERS2
-rw-r--r--packages/AppPredictionLib/Android.bp2
-rw-r--r--packages/SettingsLib/Android.bp2
-rw-r--r--packages/SettingsLib/DeviceStateRotationLock/OWNERS1
-rw-r--r--packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java46
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java3
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java41
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java25
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java25
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt8
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt2
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt2
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt2
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt4
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ShadeInterpolation.kt2
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt5
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt3
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt2
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/util/AnimatorExtensions.kt80
-rw-r--r--packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt77
-rw-r--r--packages/SystemUI/checks/src/com/android/internal/systemui/lint/DumpableNotRegisteredDetector.kt127
-rw-r--r--packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt4
-rw-r--r--packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetectorTest.kt27
-rw-r--r--packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt151
-rw-r--r--packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DumpableNotRegisteredDetectorTest.kt332
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/SystemUiController.kt18
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt4
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt4
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/pager/Pager.kt34
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/pager/PagerState.kt2
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/pager/SnappingFlingBehavior.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt4
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt7
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt16
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt20
-rw-r--r--packages/SystemUI/ktfmt_includes.txt123
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt16
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt33
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt1
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/util/RingBuffer.kt2
-rw-r--r--packages/SystemUI/res-keyguard/drawable-mdpi/ic_lockscreen_sim.pngbin2602 -> 0 bytes
-rw-r--r--packages/SystemUI/res-keyguard/drawable-xhdpi/ic_lockscreen_sim.pngbin5201 -> 0 bytes
-rw-r--r--packages/SystemUI/res-keyguard/drawable/ic_lockscreen_sim.png (renamed from packages/SystemUI/res-keyguard/drawable-hdpi/ic_lockscreen_sim.png)bin4083 -> 4083 bytes
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml4
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml341
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml301
-rw-r--r--packages/SystemUI/res-keyguard/values/dimens.xml2
-rw-r--r--packages/SystemUI/res-product/values/strings.xml9
-rw-r--r--packages/SystemUI/res/drawable/controls_panel_background.xml2
-rw-r--r--packages/SystemUI/res/drawable/qs_footer_edit_circle.xml36
-rw-r--r--packages/SystemUI/res/drawable/qs_media_rec_scrim.xml25
-rw-r--r--packages/SystemUI/res/layout/controls_fullscreen.xml12
-rw-r--r--packages/SystemUI/res/layout/controls_with_favorites.xml140
-rw-r--r--packages/SystemUI/res/layout/media_recommendation_view.xml3
-rw-r--r--packages/SystemUI/res/layout/qs_footer_impl.xml2
-rw-r--r--packages/SystemUI/res/values-af/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml20
-rw-r--r--packages/SystemUI/res/values-as/strings.xml3
-rw-r--r--packages/SystemUI/res/values-az/strings.xml3
-rw-r--r--packages/SystemUI/res/values-be/strings.xml18
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml3
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml18
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml18
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml3
-rw-r--r--packages/SystemUI/res/values-da/strings.xml18
-rw-r--r--packages/SystemUI/res/values-de/strings.xml3
-rw-r--r--packages/SystemUI/res/values-el/strings.xml3
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml18
-rw-r--r--packages/SystemUI/res/values-es/strings.xml20
-rw-r--r--packages/SystemUI/res/values-et/strings.xml18
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml9
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml3
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml3
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml9
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml18
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml18
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml18
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml3
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml18
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml18
-rw-r--r--packages/SystemUI/res/values-in/strings.xml18
-rw-r--r--packages/SystemUI/res/values-is/strings.xml18
-rw-r--r--packages/SystemUI/res/values-it/strings.xml15
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml3
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml18
-rw-r--r--packages/SystemUI/res/values-km/strings.xml3
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml27
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml3
-rw-r--r--packages/SystemUI/res/values-land/dimens.xml3
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml3
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml3
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml18
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml18
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml3
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml3
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml18
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml3
-rw-r--r--packages/SystemUI/res/values-my/strings.xml3
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml3
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml3
-rw-r--r--packages/SystemUI/res/values-or/strings.xml3
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml18
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml18
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml3
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml3
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml3
-rw-r--r--packages/SystemUI/res/values-si/strings.xml3
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml3
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml3
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml3
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml3
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml18
-rw-r--r--packages/SystemUI/res/values-sw600dp/dimens.xml3
-rw-r--r--packages/SystemUI/res/values-sw720dp-land/dimens.xml2
-rw-r--r--packages/SystemUI/res/values-sw720dp-port/dimens.xml2
-rw-r--r--packages/SystemUI/res/values-sw720dp/dimens.xml3
-rw-r--r--packages/SystemUI/res/values-te/strings.xml3
-rw-r--r--packages/SystemUI/res/values-th/strings.xml15
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml3
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml3
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml18
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml3
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml18
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml5
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml3
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml3
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml18
-rw-r--r--packages/SystemUI/res/values/config.xml2
-rw-r--r--packages/SystemUI/res/values/dimens.xml15
-rw-r--r--packages/SystemUI/res/values/flags.xml3
-rw-r--r--packages/SystemUI/res/values/strings.xml14
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt33
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/condition/Evaluator.kt2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java15
-rw-r--r--packages/SystemUI/src/com/android/keyguard/EmergencyButton.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java114
-rw-r--r--packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt1
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java27
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java10
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java40
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java7
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java156
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java10
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java21
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadKey.java3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt31
-rw-r--r--packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt26
-rw-r--r--packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt646
-rw-r--r--packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/coroutine/ChannelExt.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepository.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepository.kt64
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt95
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/start/ControlsStartable.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialogsFactory.kt49
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt97
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/demomode/DemoModeController.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt92
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerScrimController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt59
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt41
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt59
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt72
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shared/model/BacklightModel.kt (renamed from packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt)2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DevicePostureRepository.kt58
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt74
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt42
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/shared/model/DevicePosture.kt41
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt69
-rw-r--r--packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/DeviceStateAutoRotationLog.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLockscreenLog.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaData.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/AnimationBindHandler.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java100
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSHost.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java68
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/WorkProfileMessageController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java140
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java88
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java101
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt44
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/MobileViewLog.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/VerboseMobileViewLog.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt (renamed from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLogger.kt)24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/DataConnectionState.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt176
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt57
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt231
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt72
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt83
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt151
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt165
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt68
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt118
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt76
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/ModernStatusBarViewBinding.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java81
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt140
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/TouchableRegionViewController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/FoldStateLoggingProviderImpl.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt112
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt20
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java43
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java323
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt91
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java116
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/panels/FakeSelectedComponentRepository.kt42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt163
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt70
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsDialogsFactoryTest.kt89
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt165
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt66
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt73
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt102
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt52
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt80
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt103
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt109
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt119
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt71
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt41
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt74
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java129
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt41
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceRequestControllerTest.kt28
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java70
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt66
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/OneHandedModeTileTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java754
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java753
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt179
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt135
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt111
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt163
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java149
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java66
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java81
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt44
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLoggerTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLoggerTest.kt)7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModelTest.kt106
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt63
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt106
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt213
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt228
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt173
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt100
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt80
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt124
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java14
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/Flow.kt1
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt41
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDevicePostureRepository.kt31
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt17
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSystemUIDialogController.kt86
-rw-r--r--packages/SystemUI/unfold/Android.bp1
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt9
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt12
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt12
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt26
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt64
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateProvider.kt13
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt48
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt3
-rw-r--r--packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt1
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java45
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java55
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java5
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java7
-rw-r--r--services/core/java/com/android/server/display/DisplayDevice.java7
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java2
-rw-r--r--services/core/java/com/android/server/dreams/DreamController.java16
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java116
-rw-r--r--services/core/java/com/android/server/media/MediaSessionStack.java14
-rw-r--r--services/core/java/com/android/server/media/projection/OWNERS3
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java99
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java25
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java14
-rw-r--r--services/core/java/com/android/server/wm/ActivityClientController.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java53
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java41
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java69
-rw-r--r--services/core/java/com/android/server/wm/EventLogTags.logtags6
-rw-r--r--services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java4
-rw-r--r--services/core/java/com/android/server/wm/LetterboxUiController.java16
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/media/projection/OWNERS1
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java163
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java158
-rw-r--r--telecomm/java/android/telecom/PhoneAccount.java19
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt16
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt16
-rw-r--r--tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java2
-rw-r--r--tools/aapt2/SdkConstants.cpp2
660 files changed, 13469 insertions, 6693 deletions
diff --git a/cmds/uiautomator/cmds/uiautomator/src/com/android/commands/uiautomator/DumpCommand.java b/cmds/uiautomator/cmds/uiautomator/src/com/android/commands/uiautomator/DumpCommand.java
index 3b14be7327f7..24727c5f2448 100644
--- a/cmds/uiautomator/cmds/uiautomator/src/com/android/commands/uiautomator/DumpCommand.java
+++ b/cmds/uiautomator/cmds/uiautomator/src/com/android/commands/uiautomator/DumpCommand.java
@@ -107,7 +107,7 @@ public class DumpCommand extends Command {
DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
int rotation = display.getRotation();
Point size = new Point();
- display.getSize(size);
+ display.getRealSize(size);
AccessibilityNodeInfoDumper.dumpWindowToFile(info, dumpFile, rotation, size.x,
size.y);
}
diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
index ab198b319e27..488292d68620 100644
--- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
+++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
@@ -139,7 +139,7 @@ public class AccessibilityNodeInfoDumper {
serializer.attribute("", "id", Integer.toString(displayId));
int rotation = display.getRotation();
Point size = new Point();
- display.getSize(size);
+ display.getRealSize(size);
for (int i = 0, n = windows.size(); i < n; ++i) {
dumpWindowRec(windows.get(i), serializer, i, size.x, size.y, rotation);
}
diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java
index 6fd2bf250e2c..1bcd343e5668 100644
--- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java
+++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java
@@ -767,7 +767,7 @@ public class UiDevice {
if(root != null) {
Display display = getAutomatorBridge().getDefaultDisplay();
Point size = new Point();
- display.getSize(size);
+ display.getRealSize(size);
AccessibilityNodeInfoDumper.dumpWindowToFile(root,
new File(new File(Environment.getDataDirectory(), "local/tmp"), fileName),
display.getRotation(), size.x, size.y);
diff --git a/core/api/current.txt b/core/api/current.txt
index c451049cf591..487e57d114c9 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -30978,7 +30978,6 @@ package android.os {
field public static final int S = 31; // 0x1f
field public static final int S_V2 = 32; // 0x20
field public static final int TIRAMISU = 33; // 0x21
- field public static final int UPSIDE_DOWN_CAKE = 10000; // 0x2710
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 449729e18376..48df9e66be70 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3933,6 +3933,9 @@ public class ActivityManager {
* processes to reclaim memory; the system will take care of restarting
* these processes in the future as needed.
*
+ * <p class="note">Third party applications can only use this API to kill their own processes.
+ * </p>
+ *
* @param packageName The name of the package whose processes are to
* be killed.
*/
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 3bf3067f8410..8ee23aa8e67b 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -444,6 +444,7 @@ public class TaskInfo {
&& Objects.equals(shouldDockBigOverlays, that.shouldDockBigOverlays)
&& Objects.equals(displayCutoutInsets, that.displayCutoutInsets)
&& getWindowingMode() == that.getWindowingMode()
+ && configuration.uiMode == that.configuration.uiMode
&& Objects.equals(taskDescription, that.taskDescription)
&& isFocused == that.isFocused
&& isVisible == that.isVisible
@@ -472,6 +473,7 @@ public class TaskInfo {
.equals(that.configuration.windowConfiguration.getBounds()))
&& (!hasCompatUI() || configuration.getLayoutDirection()
== that.configuration.getLayoutDirection())
+ && (!hasCompatUI() || configuration.uiMode == that.configuration.uiMode)
&& (!hasCompatUI() || isVisible == that.isVisible);
}
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index 3f2fa2188d24..16b18c85e790 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -31,6 +31,7 @@ import android.os.Parcelable;
import android.os.Process;
import android.permission.PermissionManager;
import android.util.ArraySet;
+import android.util.Log;
import com.android.internal.annotations.Immutable;
@@ -87,6 +88,8 @@ import java.util.Set;
*/
@Immutable
public final class AttributionSource implements Parcelable {
+ private static final String TAG = "AttributionSource";
+
private static final String DESCRIPTOR = "android.content.AttributionSource";
private static final Binder sDefaultToken = new Binder(DESCRIPTOR);
@@ -154,9 +157,20 @@ public final class AttributionSource implements Parcelable {
AttributionSource(@NonNull Parcel in) {
this(AttributionSourceState.CREATOR.createFromParcel(in));
- // Since we just unpacked this object as part of it transiting a Binder
- // call, this is the perfect time to enforce that its UID and PID can be trusted
- enforceCallingUidAndPid();
+ if (!Binder.isDirectlyHandlingTransaction()) {
+ Log.e(TAG, "Unable to verify calling UID #" + mAttributionSourceState.uid + " PID #"
+ + mAttributionSourceState.pid + " when not handling Binder transaction; "
+ + "clearing.");
+ mAttributionSourceState.pid = -1;
+ mAttributionSourceState.uid = -1;
+ mAttributionSourceState.packageName = null;
+ mAttributionSourceState.attributionTag = null;
+ mAttributionSourceState.next = null;
+ } else {
+ // Since we just unpacked this object as part of it transiting a Binder
+ // call, this is the perfect time to enforce that its UID and PID can be trusted
+ enforceCallingUidAndPid();
+ }
}
/** @hide */
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 14d0a563f2ca..9d624b6c0ed8 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -3517,7 +3517,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p>An array of mandatory stream combinations which are applicable when device support the
* 10-bit output capability
* {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT }
- * This is an app-readable conversion of the maximum resolution mandatory stream combination
+ * This is an app-readable conversion of the 10 bit output mandatory stream combination
* {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
* <p>The array of
* {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
@@ -3542,8 +3542,8 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
/**
* <p>An array of mandatory stream combinations which are applicable when device lists
* {@code PREVIEW_STABILIZATION} in {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES android.control.availableVideoStabilizationModes}.
- * This is an app-readable conversion of the maximum resolution mandatory stream combination
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
+ * This is an app-readable conversion of the preview stabilization mandatory stream
+ * combination {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
* <p>The array of
* {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
* generated according to the documented
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index c67a560b5885..7055c9c6aa4d 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1000,24 +1000,25 @@ public abstract class CameraMetadata<TKey> {
* camera's crop region is set to maximum size, the FOV of the physical streams for the
* ultrawide lens will be the same as the logical stream, by making the crop region
* smaller than its active array size to compensate for the smaller focal length.</p>
- * <p>There are two ways for the application to capture RAW images from a logical camera
- * with RAW capability:</p>
+ * <p>For a logical camera, typically the underlying physical cameras have different RAW
+ * capabilities (such as resolution or CFA pattern). There are two ways for the
+ * application to capture RAW images from the logical camera:</p>
* <ul>
- * <li>Because the underlying physical cameras may have different RAW capabilities (such
- * as resolution or CFA pattern), to maintain backward compatibility, when a RAW stream
- * is configured, the camera device makes sure the default active physical camera remains
- * active and does not switch to other physical cameras. (One exception is that, if the
- * logical camera consists of identical image sensors and advertises multiple focalLength
- * due to different lenses, the camera device may generate RAW images from different
- * physical cameras based on the focalLength being set by the application.) This
- * backward-compatible approach usually results in loss of optical zoom, to telephoto
- * lens or to ultrawide lens.</li>
- * <li>Alternatively, to take advantage of the full zoomRatio range of the logical camera,
- * the application should use {@link android.hardware.camera2.MultiResolutionImageReader }
- * to capture RAW images from the currently active physical camera. Because different
- * physical camera may have different RAW characteristics, the application needs to use
- * the characteristics and result metadata of the active physical camera for the
- * relevant RAW metadata.</li>
+ * <li>If the logical camera has RAW capability, the application can create and use RAW
+ * streams in the same way as before. In case a RAW stream is configured, to maintain
+ * backward compatibility, the camera device makes sure the default active physical
+ * camera remains active and does not switch to other physical cameras. (One exception
+ * is that, if the logical camera consists of identical image sensors and advertises
+ * multiple focalLength due to different lenses, the camera device may generate RAW
+ * images from different physical cameras based on the focalLength being set by the
+ * application.) This backward-compatible approach usually results in loss of optical
+ * zoom, to telephoto lens or to ultrawide lens.</li>
+ * <li>Alternatively, if supported by the device,
+ * {@link android.hardware.camera2.MultiResolutionImageReader }
+ * can be used to capture RAW images from one of the underlying physical cameras (
+ * depending on current zoom level). Because different physical cameras may have
+ * different RAW characteristics, the application needs to use the characteristics
+ * and result metadata of the active physical camera for the relevant RAW metadata.</li>
* </ul>
* <p>The capture request and result metadata tags required for backward compatible camera
* functionalities will be solely based on the logical camera capability. On the other
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index dbd602f27c11..0b956f8bf9e0 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1167,11 +1167,6 @@ public class Build {
* Tiramisu.
*/
public static final int TIRAMISU = 33;
-
- /**
- * Upside Down Cake.
- */
- public static final int UPSIDE_DOWN_CAKE = CUR_DEVELOPMENT;
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/service/dreams/DreamActivity.java b/core/java/android/service/dreams/DreamActivity.java
index a2fa1392b079..a3892238f1e6 100644
--- a/core/java/android/service/dreams/DreamActivity.java
+++ b/core/java/android/service/dreams/DreamActivity.java
@@ -58,11 +58,13 @@ public class DreamActivity extends Activity {
setTitle(title);
}
- final Bundle extras = getIntent().getExtras();
- mCallback = (DreamService.DreamActivityCallbacks) extras.getBinder(EXTRA_CALLBACK);
-
- if (mCallback != null) {
+ final Object callback = getIntent().getExtras().getBinder(EXTRA_CALLBACK);
+ if (callback instanceof DreamService.DreamActivityCallbacks) {
+ mCallback = (DreamService.DreamActivityCallbacks) callback;
mCallback.onActivityCreated(this);
+ } else {
+ mCallback = null;
+ finishAndRemoveTask();
}
}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index e285b1c77122..9d8c963e2f8b 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -953,7 +953,7 @@ public class ZenModeConfig implements Parcelable {
private static Uri safeUri(TypedXmlPullParser parser, String att) {
final String val = parser.getAttributeValue(null, att);
- if (TextUtils.isEmpty(val)) return null;
+ if (val == null) return null;
return Uri.parse(val);
}
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 506b3b81eb9a..81c5796374af 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -506,7 +506,7 @@ public class TileService extends Service {
* the calling package or if the calling user cannot act on behalf of the user from the
* {@code context}.</li>
* <li> {@link IllegalArgumentException} if the user of the {@code context} is not the
- * current user.</li>
+ * current user. Only thrown for apps targeting {@link Build.VERSION_CODES#TIRAMISU}</li>
* </ul>
*/
public static final void requestListeningState(Context context, ComponentName component) {
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index d53ad17f07ef..e27af17ebc3d 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -61,7 +61,6 @@ import android.hardware.display.DisplayManager.DisplayListener;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -181,9 +180,6 @@ public abstract class WallpaperService extends Service {
private final ArrayList<Engine> mActiveEngines
= new ArrayList<Engine>();
- private Handler mBackgroundHandler;
- private HandlerThread mBackgroundThread;
-
static final class WallpaperCommand {
String action;
int x;
@@ -202,6 +198,14 @@ public abstract class WallpaperService extends Service {
*/
public class Engine {
IWallpaperEngineWrapper mIWallpaperEngine;
+ final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4);
+ final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4);
+
+ // 2D matrix [x][y] to represent a page of a portion of a window
+ EngineWindowPage[] mWindowPages = new EngineWindowPage[0];
+ Bitmap mLastScreenshot;
+ int mLastWindowPage = -1;
+ private boolean mResetWindowPages;
// Copies from mIWallpaperEngine.
HandlerCaller mCaller;
@@ -263,27 +267,11 @@ public abstract class WallpaperService extends Service {
final Object mLock = new Object();
boolean mOffsetMessageEnqueued;
-
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
float mPendingXOffset;
float mPendingYOffset;
float mPendingXOffsetStep;
float mPendingYOffsetStep;
-
- /**
- * local color extraction related fields
- * to be used by the background thread only (except the atomic boolean)
- */
- final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4);
- final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4);
- private long mLastProcessLocalColorsTimestamp;
- private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false);
- private int mPixelCopyCount = 0;
- // 2D matrix [x][y] to represent a page of a portion of a window
- EngineWindowPage[] mWindowPages = new EngineWindowPage[0];
- Bitmap mLastScreenshot;
- private boolean mResetWindowPages;
-
boolean mPendingSync;
MotionEvent mPendingMove;
boolean mIsInAmbientMode;
@@ -292,8 +280,12 @@ public abstract class WallpaperService extends Service {
private long mLastColorInvalidation;
private final Runnable mNotifyColorsChanged = this::notifyColorsChanged;
+ // used to throttle processLocalColors
+ private long mLastProcessLocalColorsTimestamp;
+ private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false);
private final Supplier<Long> mClockFunction;
private final Handler mHandler;
+
private Display mDisplay;
private Context mDisplayContext;
private int mDisplayState;
@@ -833,7 +825,7 @@ public abstract class WallpaperService extends Service {
+ "was not established.");
}
mResetWindowPages = true;
- processLocalColors();
+ processLocalColors(mPendingXOffset, mPendingXOffsetStep);
} catch (RemoteException e) {
Log.w(TAG, "Can't notify system because wallpaper connection was lost.", e);
}
@@ -1372,7 +1364,7 @@ public abstract class WallpaperService extends Service {
resetWindowPages();
mSession.finishDrawing(mWindow, null /* postDrawTransaction */,
Integer.MAX_VALUE);
- processLocalColors();
+ processLocalColors(mPendingXOffset, mPendingXOffsetStep);
}
reposition();
reportEngineShown(shouldWaitForEngineShown());
@@ -1517,7 +1509,7 @@ public abstract class WallpaperService extends Service {
if (!mDestroyed) {
mVisible = visible;
reportVisibility();
- if (mReportedVisible) processLocalColors();
+ if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep);
} else {
AnimationHandler.requestAnimatorsEnabled(visible, this);
}
@@ -1601,41 +1593,31 @@ public abstract class WallpaperService extends Service {
}
// setup local color extraction data
- processLocalColors();
+ processLocalColors(xOffset, xOffsetStep);
}
/**
* Thread-safe util to call {@link #processLocalColorsInternal} with a minimum interval of
* {@link #PROCESS_LOCAL_COLORS_INTERVAL_MS} between two calls.
*/
- private void processLocalColors() {
+ private void processLocalColors(float xOffset, float xOffsetStep) {
if (mProcessLocalColorsPending.compareAndSet(false, true)) {
final long now = mClockFunction.get();
final long timeSinceLastColorProcess = now - mLastProcessLocalColorsTimestamp;
final long timeToWait = Math.max(0,
PROCESS_LOCAL_COLORS_INTERVAL_MS - timeSinceLastColorProcess);
- mBackgroundHandler.postDelayed(() -> {
+ mHandler.postDelayed(() -> {
mLastProcessLocalColorsTimestamp = now + timeToWait;
mProcessLocalColorsPending.set(false);
- processLocalColorsInternal();
+ processLocalColorsInternal(xOffset, xOffsetStep);
}, timeToWait);
}
}
- private void processLocalColorsInternal() {
+ private void processLocalColorsInternal(float xOffset, float xOffsetStep) {
// implemented by the wallpaper
if (supportsLocalColorExtraction()) return;
- assertBackgroundThread();
- float xOffset;
- float xOffsetStep;
- float wallpaperDimAmount;
- synchronized (mLock) {
- xOffset = mPendingXOffset;
- xOffsetStep = mPendingXOffsetStep;
- wallpaperDimAmount = mWallpaperDimAmount;
- }
-
if (DEBUG) {
Log.d(TAG, "processLocalColors " + xOffset + " of step "
+ xOffsetStep);
@@ -1698,7 +1680,7 @@ public abstract class WallpaperService extends Service {
xPage = mWindowPages.length - 1;
}
current = mWindowPages[xPage];
- updatePage(current, xPage, xPages, wallpaperDimAmount);
+ updatePage(current, xPage, xPages, finalXOffsetStep);
Trace.endSection();
}
@@ -1718,23 +1700,16 @@ public abstract class WallpaperService extends Service {
}
}
- /**
- * Must be called with the surface lock held.
- * Must not be called if the surface is not valid.
- * Will unlock the surface when done using it.
- */
void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages,
- float wallpaperDimAmount) {
-
- assertBackgroundThread();
-
+ float xOffsetStep) {
// in case the clock is zero, we start with negative time
long current = SystemClock.elapsedRealtime() - DEFAULT_UPDATE_SCREENSHOT_DURATION;
long lapsed = current - currentPage.getLastUpdateTime();
// Always update the page when the last update time is <= 0
// This is important especially when the device first boots
- if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) return;
-
+ if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) {
+ return;
+ }
Surface surface = mSurfaceHolder.getSurface();
if (!surface.isValid()) return;
boolean widthIsLarger = mSurfaceSize.x > mSurfaceSize.y;
@@ -1750,42 +1725,33 @@ public abstract class WallpaperService extends Service {
Bitmap screenShot = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
final Bitmap finalScreenShot = screenShot;
- final String pixelCopySectionName = "WallpaperService#pixelCopy";
- final int pixelCopyCount = mPixelCopyCount++;
- Trace.beginAsyncSection(pixelCopySectionName, pixelCopyCount);
- try {
- PixelCopy.request(surface, screenShot, (res) -> {
- Trace.endAsyncSection(pixelCopySectionName, pixelCopyCount);
- if (DEBUG) Log.d(TAG, "result of pixel copy is " + res);
- if (res != PixelCopy.SUCCESS) {
- Bitmap lastBitmap = currentPage.getBitmap();
- // assign the last bitmap taken for now
- currentPage.setBitmap(mLastScreenshot);
- Bitmap lastScreenshot = mLastScreenshot;
- if (lastScreenshot != null && !lastScreenshot.isRecycled()
- && !Objects.equals(lastBitmap, lastScreenshot)) {
- updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount);
- }
- } else {
- mLastScreenshot = finalScreenShot;
- // going to hold this lock for a while
- currentPage.setBitmap(finalScreenShot);
- currentPage.setLastUpdateTime(current);
- updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount);
+ Trace.beginSection("WallpaperService#pixelCopy");
+ PixelCopy.request(surface, screenShot, (res) -> {
+ Trace.endSection();
+ if (DEBUG) Log.d(TAG, "result of pixel copy is " + res);
+ if (res != PixelCopy.SUCCESS) {
+ Bitmap lastBitmap = currentPage.getBitmap();
+ // assign the last bitmap taken for now
+ currentPage.setBitmap(mLastScreenshot);
+ Bitmap lastScreenshot = mLastScreenshot;
+ if (lastScreenshot != null && !lastScreenshot.isRecycled()
+ && !Objects.equals(lastBitmap, lastScreenshot)) {
+ updatePageColors(currentPage, pageIndx, numPages, xOffsetStep);
}
- }, mBackgroundHandler);
- } catch (IllegalArgumentException e) {
- // this can potentially happen if the surface is invalidated right between the
- // surface.isValid() check and the PixelCopy operation.
- // in this case, stop: we'll compute colors on the next processLocalColors call.
- Log.i(TAG, "Cancelling processLocalColors: exception caught during PixelCopy");
- }
+ } else {
+ mLastScreenshot = finalScreenShot;
+ // going to hold this lock for a while
+ currentPage.setBitmap(finalScreenShot);
+ currentPage.setLastUpdateTime(current);
+ updatePageColors(currentPage, pageIndx, numPages, xOffsetStep);
+ }
+ }, mHandler);
+
}
// locked by the passed page
- private void updatePageColors(
- EngineWindowPage page, int pageIndx, int numPages, float wallpaperDimAmount) {
+ private void updatePageColors(EngineWindowPage page, int pageIndx, int numPages,
+ float xOffsetStep) {
if (page.getBitmap() == null) return;
- assertBackgroundThread();
Trace.beginSection("WallpaperService#updatePageColors");
if (DEBUG) {
Log.d(TAG, "updatePageColorsLocked for page " + pageIndx + " with areas "
@@ -1807,7 +1773,7 @@ public abstract class WallpaperService extends Service {
Log.e(TAG, "Error creating page local color bitmap", e);
continue;
}
- WallpaperColors color = WallpaperColors.fromBitmap(target, wallpaperDimAmount);
+ WallpaperColors color = WallpaperColors.fromBitmap(target, mWallpaperDimAmount);
target.recycle();
WallpaperColors currentColor = page.getColors(area);
@@ -1824,26 +1790,17 @@ public abstract class WallpaperService extends Service {
+ " local color callback for area" + area + " for page " + pageIndx
+ " of " + numPages);
}
- mHandler.post(() -> {
- try {
- mConnection.onLocalWallpaperColorsChanged(area, color,
- mDisplayContext.getDisplayId());
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e);
- }
- });
+ try {
+ mConnection.onLocalWallpaperColorsChanged(area, color,
+ mDisplayContext.getDisplayId());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e);
+ }
}
}
Trace.endSection();
}
- private void assertBackgroundThread() {
- if (!mBackgroundHandler.getLooper().isCurrentThread()) {
- throw new IllegalStateException(
- "ProcessLocalColors should be called from the background thread");
- }
- }
-
private RectF generateSubRect(RectF in, int pageInx, int numPages) {
float minLeft = (float) (pageInx) / (float) (numPages);
float maxRight = (float) (pageInx + 1) / (float) (numPages);
@@ -1868,6 +1825,7 @@ public abstract class WallpaperService extends Service {
if (supportsLocalColorExtraction()) return;
if (!mResetWindowPages) return;
mResetWindowPages = false;
+ mLastWindowPage = -1;
for (int i = 0; i < mWindowPages.length; i++) {
mWindowPages[i].setLastUpdateTime(0L);
}
@@ -1893,10 +1851,12 @@ public abstract class WallpaperService extends Service {
if (DEBUG) {
Log.d(TAG, "addLocalColorsAreas adding local color areas " + regions);
}
- mBackgroundHandler.post(() -> {
+ mHandler.post(() -> {
mLocalColorsToAdd.addAll(regions);
- processLocalColors();
+ processLocalColors(mPendingXOffset, mPendingYOffset);
});
+
+
}
/**
@@ -1906,7 +1866,7 @@ public abstract class WallpaperService extends Service {
*/
public void removeLocalColorsAreas(@NonNull List<RectF> regions) {
if (supportsLocalColorExtraction()) return;
- mBackgroundHandler.post(() -> {
+ mHandler.post(() -> {
float step = mPendingXOffsetStep;
mLocalColorsToAdd.removeAll(regions);
mLocalColorAreas.removeAll(regions);
@@ -2537,9 +2497,6 @@ public abstract class WallpaperService extends Service {
@Override
public void onCreate() {
Trace.beginSection("WPMS.onCreate");
- mBackgroundThread = new HandlerThread("DefaultWallpaperLocalColorExtractor");
- mBackgroundThread.start();
- mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
super.onCreate();
Trace.endSection();
}
@@ -2552,7 +2509,6 @@ public abstract class WallpaperService extends Service {
mActiveEngines.get(i).detach();
}
mActiveEngines.clear();
- mBackgroundThread.quitSafely();
Trace.endSection();
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 953f17a3a827..f9e84114a7da 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -9883,9 +9883,12 @@ public final class ViewRootImpl implements ViewParent,
}
void checkThread() {
- if (mThread != Thread.currentThread()) {
+ Thread current = Thread.currentThread();
+ if (mThread != current) {
throw new CalledFromWrongThreadException(
- "Only the original thread that created a view hierarchy can touch its views.");
+ "Only the original thread that created a view hierarchy can touch its views."
+ + " Expected: " + mThread.getName()
+ + " Calling: " + current.getName());
}
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 02027e4a3969..293f9082670d 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -823,6 +823,11 @@ public abstract class Window {
/** @hide */
public final void destroy() {
mDestroyed = true;
+ onDestroy();
+ }
+
+ /** @hide */
+ protected void onDestroy() {
}
/** @hide */
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 011232fe1915..cef5120bc0b7 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -21,6 +21,7 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT
import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_SHARE_WITH_PERSONAL;
import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_SHARE_WITH_WORK;
import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE;
+import static android.content.ContentProvider.getUserIdFromUri;
import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL;
import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK;
@@ -161,6 +162,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
+import java.util.stream.Collectors;
/**
* The Chooser Activity handles intent resolution specifically for sharing intents -
@@ -1424,7 +1426,11 @@ public class ChooserActivity extends ResolverActivity implements
String action = targetIntent.getAction();
if (Intent.ACTION_SEND.equals(action)) {
- Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
+ Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM, android.net.Uri.class);
+ if (!validForContentPreview(uri)) {
+ contentPreviewLayout.setVisibility(View.GONE);
+ return contentPreviewLayout;
+ }
imagePreview.findViewById(R.id.content_preview_image_1_large)
.setTransitionName(ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME);
mPreviewCoord.loadUriIntoView(R.id.content_preview_image_1_large, uri, 0);
@@ -1434,7 +1440,7 @@ public class ChooserActivity extends ResolverActivity implements
List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
List<Uri> imageUris = new ArrayList<>();
for (Uri uri : uris) {
- if (isImageType(resolver.getType(uri))) {
+ if (validForContentPreview(uri) && isImageType(resolver.getType(uri))) {
imageUris.add(uri);
}
}
@@ -1544,9 +1550,16 @@ public class ChooserActivity extends ResolverActivity implements
String action = targetIntent.getAction();
if (Intent.ACTION_SEND.equals(action)) {
Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
+ if (!validForContentPreview(uri)) {
+ contentPreviewLayout.setVisibility(View.GONE);
+ return contentPreviewLayout;
+ }
loadFileUriIntoView(uri, contentPreviewLayout);
} else {
List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+ uris = uris.stream()
+ .filter(ChooserActivity::validForContentPreview)
+ .collect(Collectors.toList());
int uriCount = uris.size();
if (uriCount == 0) {
@@ -1605,6 +1618,24 @@ public class ChooserActivity extends ResolverActivity implements
}
}
+ /**
+ * Indicate if the incoming content URI should be allowed.
+ *
+ * @param uri the uri to test
+ * @return true if the URI is allowed for content preview
+ */
+ private static boolean validForContentPreview(Uri uri) throws SecurityException {
+ if (uri == null) {
+ return false;
+ }
+ int userId = getUserIdFromUri(uri, UserHandle.USER_CURRENT);
+ if (userId != UserHandle.USER_CURRENT && userId != UserHandle.myUserId()) {
+ Log.e(TAG, "dropped invalid content URI belonging to user " + userId);
+ return false;
+ }
+ return true;
+ }
+
@VisibleForTesting
protected boolean isImageType(String mimeType) {
return mimeType != null && mimeType.startsWith("image/");
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index d8afe50d3af3..e7217def7689 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -33,6 +33,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OPEN_ALL_APPS;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_QUICK_SWITCH;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_UNLOCK_ENTRANCE_ANIMATION;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_CLOCK_MOVE_ANIMATION;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_LAUNCH_CAMERA;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_OCCLUSION;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PASSWORD_APPEAR;
@@ -231,6 +232,7 @@ public class InteractionJankMonitor {
public static final int CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS = 66;
public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE = 67;
public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME = 68;
+ public static final int CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION = 70;
private static final int NO_STATSD_LOGGING = -1;
@@ -308,6 +310,8 @@ public class InteractionJankMonitor {
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_SWIPE_TO_RECENTS,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_SWIPE,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_TO_HOME,
+ NO_STATSD_LOGGING,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_CLOCK_MOVE_ANIMATION,
};
private static volatile InteractionJankMonitor sInstance;
@@ -396,7 +400,8 @@ public class InteractionJankMonitor {
CUJ_RECENTS_SCROLLING,
CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS,
CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE,
- CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME
+ CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME,
+ CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -917,6 +922,8 @@ public class InteractionJankMonitor {
return "LAUNCHER_CLOSE_ALL_APPS_SWIPE";
case CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME:
return "LAUNCHER_CLOSE_ALL_APPS_TO_HOME";
+ case CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION:
+ return "LOCKSCREEN_CLOCK_MOVE_ANIMATION";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 3a0e09d1fc77..6fed26c4a81d 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -81,7 +81,6 @@ import android.telephony.ServiceState.RegState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
-import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -202,7 +201,6 @@ public class BatteryStatsImpl extends BatteryStats {
public static final int RESET_REASON_ADB_COMMAND = 2;
public static final int RESET_REASON_FULL_CHARGE = 3;
public static final int RESET_REASON_MEASURED_ENERGY_BUCKETS_CHANGE = 4;
- public static final int RESET_REASON_PLUGGED_IN_FOR_LONG_DURATION = 5;
protected Clock mClock;
@@ -389,89 +387,6 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
- /** Provide BatteryStatsImpl configuration choices */
- public static class BatteryStatsConfig {
- static final int RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG = 1 << 0;
- static final int RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG = 1 << 1;
-
- private final int mFlags;
-
- private BatteryStatsConfig(Builder builder) {
- int flags = 0;
- if (builder.mResetOnUnplugHighBatteryLevel) {
- flags |= RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG;
- }
- if (builder.mResetOnUnplugAfterSignificantCharge) {
- flags |= RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG;
- }
- mFlags = flags;
- }
-
- /**
- * Returns whether a BatteryStats reset should occur on unplug when the battery level is
- * high.
- */
- boolean shouldResetOnUnplugHighBatteryLevel() {
- return (mFlags & RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG)
- == RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG;
- }
-
- /**
- * Returns whether a BatteryStats reset should occur on unplug if the battery charge a
- * significant amount since it has been plugged in.
- */
- boolean shouldResetOnUnplugAfterSignificantCharge() {
- return (mFlags & RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG)
- == RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG;
- }
-
- /**
- * Builder for BatteryStatsConfig
- */
- public static class Builder {
- private boolean mResetOnUnplugHighBatteryLevel;
- private boolean mResetOnUnplugAfterSignificantCharge;
- public Builder() {
- mResetOnUnplugHighBatteryLevel = true;
- mResetOnUnplugAfterSignificantCharge = true;
- }
-
- /**
- * Build the BatteryStatsConfig.
- */
- public BatteryStatsConfig build() {
- return new BatteryStatsConfig(this);
- }
-
- /**
- * Set whether a BatteryStats reset should occur on unplug when the battery level is
- * high.
- */
- public Builder setResetOnUnplugHighBatteryLevel(boolean reset) {
- mResetOnUnplugHighBatteryLevel = reset;
- return this;
- }
-
- /**
- * Set whether a BatteryStats reset should occur on unplug if the battery charge a
- * significant amount since it has been plugged in.
- */
- public Builder setResetOnUnplugAfterSignificantCharge(boolean reset) {
- mResetOnUnplugAfterSignificantCharge = reset;
- return this;
- }
- }
-
- }
-
- /** Handles calls to AlarmManager */
- public interface AlarmInterface {
- /** Schedule an RTC alarm */
- void schedule(long rtcTimeMs, long windowLengthMs);
- /** Cancel the previously scheduled alarm */
- void cancel();
- }
-
private final PlatformIdleStateCallback mPlatformIdleStateCallback;
private final Runnable mDeferSetCharging = new Runnable() {
@@ -802,7 +717,6 @@ public class BatteryStatsImpl extends BatteryStats {
protected boolean mHaveBatteryLevel = false;
protected boolean mRecordingHistory = false;
int mNumHistoryItems;
- private long mBatteryPluggedInRealTimeMs = 0;
private static final int HISTORY_TAG_INDEX_LIMIT = 0x7ffe;
private static final int MAX_HISTORY_TAG_STRING_LENGTH = 1024;
@@ -1545,13 +1459,6 @@ public class BatteryStatsImpl extends BatteryStats {
@GuardedBy("this")
protected final Constants mConstants;
- @VisibleForTesting
- @GuardedBy("this")
- protected BatteryStatsConfig mBatteryStatsConfig = new BatteryStatsConfig.Builder().build();
-
- @VisibleForTesting
- protected AlarmInterface mLongPlugInAlarmInterface = null;
-
/*
* Holds a SamplingTimer associated with each Resource Power Manager state and voter,
* recording their times when on-battery (regardless of screen state).
@@ -1718,13 +1625,12 @@ public class BatteryStatsImpl extends BatteryStats {
public BatteryStatsImpl(Clock clock, File historyDirectory) {
init(clock);
mStartClockTimeMs = clock.currentTimeMillis();
+ mCheckinFile = null;
mDailyFile = null;
if (historyDirectory == null) {
- mCheckinFile = null;
mStatsFile = null;
mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer);
} else {
- mCheckinFile = new AtomicFile(new File(historyDirectory, "batterystats-checkin.bin"));
mStatsFile = new AtomicFile(new File(historyDirectory, "batterystats.bin"));
mBatteryStatsHistory = new BatteryStatsHistory(this, historyDirectory, mHistoryBuffer);
}
@@ -12642,27 +12548,6 @@ public class BatteryStatsImpl extends BatteryStats {
}
/**
- * Injects BatteryStatsConfig
- */
- public void setBatteryStatsConfig(BatteryStatsConfig config) {
- synchronized (this) {
- mBatteryStatsConfig = config;
- }
- }
-
- /**
- * Injects a LongPlugInAlarmHandler
- */
- public void setLongPlugInAlarmInterface(AlarmInterface longPlugInAlarmInterface) {
- synchronized (this) {
- mLongPlugInAlarmInterface = longPlugInAlarmInterface;
- if (!mOnBattery) {
- scheduleNextResetWhilePluggedInCheck();
- }
- }
- }
-
- /**
* Starts tracking CPU time-in-state for threads of the system server process,
* keeping a separate account of threads receiving incoming binder calls.
*/
@@ -13134,12 +13019,12 @@ public class BatteryStatsImpl extends BatteryStats {
}
@GuardedBy("this")
- public void resetAllStatsAndHistoryLocked(int reason) {
+ public void resetAllStatsCmdLocked() {
final long mSecUptime = mClock.uptimeMillis();
long uptimeUs = mSecUptime * 1000;
long mSecRealtime = mClock.elapsedRealtime();
long realtimeUs = mSecRealtime * 1000;
- resetAllStatsLocked(mSecUptime, mSecRealtime, reason);
+ resetAllStatsLocked(mSecUptime, mSecRealtime, RESET_REASON_ADB_COMMAND);
mDischargeStartLevel = mHistoryCur.batteryLevel;
pullPendingStateUpdatesLocked();
addHistoryRecordLocked(mSecRealtime, mSecUptime);
@@ -15613,73 +15498,6 @@ public class BatteryStatsImpl extends BatteryStats {
}
/**
- * Might reset battery stats if conditions are met. Assumed the device is currently plugged in.
- */
- @GuardedBy("this")
- public void maybeResetWhilePluggedInLocked() {
- final long elapsedRealtimeMs = mClock.elapsedRealtime();
- if (shouldResetWhilePluggedInLocked(elapsedRealtimeMs)) {
- Slog.i(TAG,
- "Resetting due to long plug in duration. elapsed time = " + elapsedRealtimeMs
- + " ms, last plug in time = " + mBatteryPluggedInRealTimeMs
- + " ms, last reset time = " + mRealtimeStartUs / 1000);
- resetAllStatsAndHistoryLocked(RESET_REASON_PLUGGED_IN_FOR_LONG_DURATION);
- }
-
- scheduleNextResetWhilePluggedInCheck();
- }
-
- @GuardedBy("this")
- private void scheduleNextResetWhilePluggedInCheck() {
- if (mLongPlugInAlarmInterface != null) {
- final long timeoutMs = mClock.currentTimeMillis()
- + mConstants.RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS
- * DateUtils.HOUR_IN_MILLIS;
- Calendar nextAlarm = Calendar.getInstance();
- nextAlarm.setTimeInMillis(timeoutMs);
-
- // Find the 2 AM the same day as the end of the minimum duration.
- // This logic does not handle a Daylight Savings transition, or a timezone change
- // while the alarm has been set. The need to reset after a long period while plugged
- // in is not strict enough to warrant a well architected out solution.
- nextAlarm.set(Calendar.MILLISECOND, 0);
- nextAlarm.set(Calendar.SECOND, 0);
- nextAlarm.set(Calendar.MINUTE, 0);
- nextAlarm.set(Calendar.HOUR_OF_DAY, 2);
- long nextTimeMs = nextAlarm.getTimeInMillis();
- if (nextTimeMs < timeoutMs) {
- // The 2AM on the day of the timeout, move on the next day.
- nextTimeMs += DateUtils.DAY_IN_MILLIS;
- }
- mLongPlugInAlarmInterface.schedule(nextTimeMs, DateUtils.HOUR_IN_MILLIS);
- }
- }
-
-
- @GuardedBy("this")
- private boolean shouldResetWhilePluggedInLocked(long elapsedRealtimeMs) {
- if (mNoAutoReset) return false;
- if (!mSystemReady) return false;
-
- final long pluggedInThresholdMs = mBatteryPluggedInRealTimeMs
- + mConstants.RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS
- * DateUtils.HOUR_IN_MILLIS;
- if (elapsedRealtimeMs >= pluggedInThresholdMs) {
- // The device has been plugged in for a long time.
- final long resetThresholdMs = mRealtimeStartUs / 1000
- + mConstants.RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS
- * DateUtils.HOUR_IN_MILLIS;
- if (elapsedRealtimeMs >= resetThresholdMs) {
- // And it has been a long time since the last reset.
- return true;
- }
- }
-
- return false;
- }
-
-
- /**
* Notifies BatteryStatsImpl that the system server is ready.
*/
public void onSystemReady() {
@@ -15687,32 +15505,6 @@ public class BatteryStatsImpl extends BatteryStats {
}
@GuardedBy("this")
- private boolean shouldResetOnUnplugLocked(int batteryStatus, int batteryLevel) {
- if (mNoAutoReset) return false;
- if (!mSystemReady) return false;
- if (mBatteryStatsConfig.shouldResetOnUnplugHighBatteryLevel()) {
- // Allow resetting due to currently being at high battery level
- if (batteryStatus == BatteryManager.BATTERY_STATUS_FULL) return true;
- if (batteryLevel >= 90) return true;
- }
- if (mBatteryStatsConfig.shouldResetOnUnplugAfterSignificantCharge()) {
- // Allow resetting after a significant charge (from a very low level to a now very
- // high level).
- if (mDischargePlugLevel < 20 && batteryLevel >= 80) return true;
- }
- if (getHighDischargeAmountSinceCharge() >= 200) {
- // Reset the stats if battery got partially charged and discharged repeatedly without
- // ever reaching the full charge.
- // This reset is done in order to prevent stats sessions from going on forever.
- // Exceedingly long battery sessions would lead to an overflow of
- // data structures such as mWakeupReasonStats.
- return true;
- }
-
- return false;
- }
-
- @GuardedBy("this")
protected void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime,
final boolean onBattery, final int oldStatus, final int level, final int chargeUah) {
boolean doWrite = false;
@@ -15724,10 +15516,23 @@ public class BatteryStatsImpl extends BatteryStats {
final long realtimeUs = mSecRealtime * 1000;
final int screenState = mScreenState;
if (onBattery) {
+ // We will reset our status if we are unplugging after the
+ // battery was last full, or the level is at 100, or
+ // we have gone through a significant charge (from a very low
+ // level to a now very high level).
+ // Also, we will reset the stats if battery got partially charged
+ // and discharged repeatedly without ever reaching the full charge.
+ // This reset is done in order to prevent stats sessions from going on forever.
+ // Exceedingly long battery sessions would lead to an overflow of
+ // data structures such as mWakeupReasonStats.
boolean reset = false;
- if (shouldResetOnUnplugLocked(oldStatus, level)) {
+ if (!mNoAutoReset && mSystemReady
+ && (oldStatus == BatteryManager.BATTERY_STATUS_FULL
+ || level >= 90
+ || (mDischargeCurrentLevel < 20 && level >= 80)
+ || getHighDischargeAmountSinceCharge() >= 200)) {
Slog.i(TAG, "Resetting battery stats: level=" + level + " status=" + oldStatus
- + " dischargeLevel=" + mDischargePlugLevel
+ + " dischargeLevel=" + mDischargeCurrentLevel
+ " lowAmount=" + getLowDischargeAmountSinceCharge()
+ " highAmount=" + getHighDischargeAmountSinceCharge());
// Before we write, collect a snapshot of the final aggregated
@@ -15784,9 +15589,6 @@ public class BatteryStatsImpl extends BatteryStats {
mInitStepMode = mCurStepMode;
mModStepMode = 0;
pullPendingStateUpdatesLocked();
- if (mLongPlugInAlarmInterface != null) {
- mLongPlugInAlarmInterface.cancel();
- }
mHistoryCur.batteryLevel = (byte)level;
mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
@@ -15818,7 +15620,6 @@ public class BatteryStatsImpl extends BatteryStats {
mLastChargingStateLevel = level;
mOnBattery = mOnBatteryInternal = false;
pullPendingStateUpdatesLocked();
- mBatteryPluggedInRealTimeMs = mSecRealtime;
mHistoryCur.batteryLevel = (byte)level;
mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
@@ -15836,7 +15637,6 @@ public class BatteryStatsImpl extends BatteryStats {
mMaxChargeStepLevel = level;
mInitStepMode = mCurStepMode;
mModStepMode = 0;
- scheduleNextResetWhilePluggedInCheck();
}
if (doWrite || (mLastWriteTimeMs + (60 * 1000)) < mSecRealtime) {
if (mStatsFile != null && mBatteryStatsHistory.getActiveFile() != null) {
@@ -16851,8 +16651,6 @@ public class BatteryStatsImpl extends BatteryStats {
public static final String KEY_MAX_HISTORY_BUFFER_KB = "max_history_buffer_kb";
public static final String KEY_BATTERY_CHARGED_DELAY_MS =
"battery_charged_delay_ms";
- public static final String KEY_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS =
- "reset_while_plugged_in_minimum_duration_hours";
private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true;
private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 1_000;
@@ -16865,8 +16663,6 @@ public class BatteryStatsImpl extends BatteryStats {
private static final int DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE = 64;
private static final int DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB = 64; /*Kilo Bytes*/
private static final int DEFAULT_BATTERY_CHARGED_DELAY_MS = 900000; /* 15 min */
- // Little less than 2 days
- private static final int DEFAULT_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS = 47;
public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME;
/* Do not set default value for KERNEL_UID_READERS_THROTTLE_TIME. Need to trigger an
@@ -16882,8 +16678,6 @@ public class BatteryStatsImpl extends BatteryStats {
public int MAX_HISTORY_FILES;
public int MAX_HISTORY_BUFFER; /*Bytes*/
public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS;
- public int RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS =
- DEFAULT_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -16960,11 +16754,6 @@ public class BatteryStatsImpl extends BatteryStats {
DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB
: DEFAULT_MAX_HISTORY_BUFFER_KB)
* 1024;
-
- RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS = mParser.getInt(
- KEY_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS,
- DEFAULT_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS);
-
updateBatteryChargedDelayMsLocked();
}
}
@@ -17019,8 +16808,6 @@ public class BatteryStatsImpl extends BatteryStats {
pw.println(MAX_HISTORY_BUFFER/1024);
pw.print(KEY_BATTERY_CHARGED_DELAY_MS); pw.print("=");
pw.println(BATTERY_CHARGED_DELAY_MS);
- pw.print(KEY_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS); pw.print("=");
- pw.println(RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS);
}
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index bb69192f187f..e603e2ed57f1 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -295,6 +295,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private boolean mClosingActionMenu;
private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
+ private int mAudioMode = AudioManager.MODE_NORMAL;
private MediaController mMediaController;
private AudioManager mAudioManager;
@@ -317,6 +318,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
};
+ private AudioManager.OnModeChangedListener mOnModeChangedListener;
+
private Transition mEnterTransition = null;
private Transition mReturnTransition = USE_DEFAULT_TRANSITION;
private Transition mExitTransition = null;
@@ -1950,9 +1953,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
- // If we have a session send it the volume command, otherwise
- // use the suggested stream.
- if (mMediaController != null) {
+ // If we have a session and no active phone call send it the volume command,
+ // otherwise use the suggested stream.
+ if (mMediaController != null && !isActivePhoneCallOngoing()) {
getMediaSessionManager().dispatchVolumeKeyEventToSessionAsSystemService(event,
mMediaController.getSessionToken());
} else {
@@ -2003,6 +2006,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
return false;
}
+ private boolean isActivePhoneCallOngoing() {
+ return mAudioMode == AudioManager.MODE_IN_CALL
+ || mAudioMode == AudioManager.MODE_IN_COMMUNICATION;
+ }
+
private KeyguardManager getKeyguardManager() {
if (mKeyguardManager == null) {
mKeyguardManager = (KeyguardManager) getContext().getSystemService(
@@ -2326,6 +2334,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
+ @Override
+ protected void onDestroy() {
+ if (mOnModeChangedListener != null) {
+ getAudioManager().removeOnModeChangedListener(mOnModeChangedListener);
+ mOnModeChangedListener = null;
+ }
+ }
+
private class PanelMenuPresenterCallback implements MenuPresenter.Callback {
@Override
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
@@ -3208,6 +3224,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
public void setMediaController(MediaController controller) {
mMediaController = controller;
+ if (controller != null && mOnModeChangedListener == null) {
+ mAudioMode = getAudioManager().getMode();
+ mOnModeChangedListener = mode -> mAudioMode = mode;
+ getAudioManager().addOnModeChangedListener(getContext().getMainExecutor(),
+ mOnModeChangedListener);
+ } else if (mOnModeChangedListener != null) {
+ getAudioManager().removeOnModeChangedListener(mOnModeChangedListener);
+ mOnModeChangedListener = null;
+ }
}
@Override
diff --git a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java
index 83309fc61009..ac9188a0debc 100644
--- a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java
@@ -72,11 +72,13 @@ public class BaseProtoLogImpl {
private static final String TAG = "ProtoLog";
private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
static final String PROTOLOG_VERSION = "1.0.0";
+ private static final int DEFAULT_PER_CHUNK_SIZE = 0;
private final File mLogFile;
private final String mViewerConfigFilename;
private final TraceBuffer mBuffer;
protected final ProtoLogViewerConfigReader mViewerConfig;
+ private final int mPerChunkSize;
private boolean mProtoLogEnabled;
private boolean mProtoLogEnabledLockFree;
@@ -156,7 +158,7 @@ public class BaseProtoLogImpl {
return;
}
try {
- ProtoOutputStream os = new ProtoOutputStream();
+ ProtoOutputStream os = new ProtoOutputStream(mPerChunkSize);
long token = os.start(LOG);
os.write(MESSAGE_HASH, messageHash);
os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
@@ -215,10 +217,16 @@ public class BaseProtoLogImpl {
public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
ProtoLogViewerConfigReader viewerConfig) {
+ this(file, viewerConfigFilename, bufferCapacity, viewerConfig, DEFAULT_PER_CHUNK_SIZE);
+ }
+
+ public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
+ ProtoLogViewerConfigReader viewerConfig, int perChunkSize) {
mLogFile = file;
mBuffer = new TraceBuffer(bufferCapacity);
mViewerConfigFilename = viewerConfigFilename;
mViewerConfig = viewerConfig;
+ mPerChunkSize = perChunkSize;
}
/**
@@ -255,6 +263,7 @@ public class BaseProtoLogImpl {
if (writeToFile) {
writeProtoLogToFileLocked();
logAndPrintln(pw, "Log written to " + mLogFile + ".");
+ mBuffer.resetBuffer();
}
if (mProtoLogEnabled) {
logAndPrintln(pw, "ERROR: logging was re-enabled while waiting for flush.");
@@ -363,7 +372,7 @@ public class BaseProtoLogImpl {
try {
long offset =
(System.currentTimeMillis() - (SystemClock.elapsedRealtimeNanos() / 1000000));
- ProtoOutputStream proto = new ProtoOutputStream();
+ ProtoOutputStream proto = new ProtoOutputStream(mPerChunkSize);
proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
proto.write(VERSION, PROTOLOG_VERSION);
proto.write(REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS, offset);
diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java
index 353c6c083d9d..527cfddf6d8e 100644
--- a/core/java/com/android/internal/protolog/ProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java
@@ -30,6 +30,7 @@ public class ProtoLogImpl extends BaseProtoLogImpl {
private static final int BUFFER_CAPACITY = 1024 * 1024;
private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.winscope";
private static final String VIEWER_CONFIG_FILENAME = "/system/etc/protolog.conf.json.gz";
+ private static final int PER_CHUNK_SIZE = 1024;
private static ProtoLogImpl sServiceInstance = null;
@@ -94,7 +95,10 @@ public class ProtoLogImpl extends BaseProtoLogImpl {
public static synchronized ProtoLogImpl getSingleInstance() {
if (sServiceInstance == null) {
sServiceInstance = new ProtoLogImpl(
- new File(LOG_FILENAME), BUFFER_CAPACITY, new ProtoLogViewerConfigReader());
+ new File(LOG_FILENAME)
+ , BUFFER_CAPACITY
+ , new ProtoLogViewerConfigReader()
+ , PER_CHUNK_SIZE);
}
return sServiceInstance;
}
@@ -105,8 +109,8 @@ public class ProtoLogImpl extends BaseProtoLogImpl {
}
public ProtoLogImpl(File logFile, int bufferCapacity,
- ProtoLogViewerConfigReader viewConfigReader) {
- super(logFile, VIEWER_CONFIG_FILENAME, bufferCapacity, viewConfigReader);
- }
+ ProtoLogViewerConfigReader viewConfigReader, int perChunkSize) {
+ super(logFile, VIEWER_CONFIG_FILENAME, bufferCapacity, viewConfigReader, perChunkSize);
+ }
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 31903e25f8fd..0e95e30a99b8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3154,7 +3154,11 @@
android:protectionLevel="normal" />
<!-- Allows an application to call
- {@link android.app.ActivityManager#killBackgroundProcesses}.
+ {@link android.app.ActivityManager#killBackgroundProcesses}.
+
+ <p class="note">Third party applications can only use this API to kill their own
+ processes.</p>
+
<p>Protection level: normal
-->
<permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 9491f22e5953..627911b07cb5 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -297,7 +297,7 @@
<string name="safeMode" msgid="8974401416068943888">"حالت ایمن"</string>
<string name="android_system_label" msgid="5974767339591067210">"‏سیستم Android"</string>
<string name="user_owner_label" msgid="8628726904184471211">"جابه‌جا شدن به نمایه شخصی"</string>
- <string name="managed_profile_label" msgid="7316778766973512382">"جابه‌جا شدن به نمایه کاری"</string>
+ <string name="managed_profile_label" msgid="7316778766973512382">"رفتن به نمایه کاری"</string>
<string name="permgrouplab_contacts" msgid="4254143639307316920">"مخاطبین"</string>
<string name="permgroupdesc_contacts" msgid="9163927941244182567">"دسترسی به مخاطبین شما"</string>
<string name="permgrouplab_location" msgid="1858277002233964394">"مکان"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 1226661b1896..8392df33c19f 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1947,7 +1947,7 @@
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>՝ անհասանելի է"</string>
<string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Անհրաժեշտ է թույլտվություն"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Տեսախցիկն անհասանելի է"</string>
- <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Շարունակեք հեռախոսով"</string>
+ <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Շարու­նակեք հեռախոսով"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Խոսափողն անհասանելի է"</string>
<string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Խանութը հասանելի չէ"</string>
<string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Android TV-ի կարգավորումներն անհասանելի են"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 7060eeff4671..403afade6f59 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1972,7 +1972,7 @@
<string name="profile_encrypted_message" msgid="1128512616293157802">"Tocca per sbloc. prof. di lav."</string>
<string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"Connesso a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Tocca per visualizzare i file"</string>
- <string name="pin_target" msgid="8036028973110156895">"Blocca"</string>
+ <string name="pin_target" msgid="8036028973110156895">"Fissa"</string>
<string name="pin_specific_target" msgid="7824671240625957415">"Blocca <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="unpin_target" msgid="3963318576590204447">"Sgancia"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Sblocca <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index b3bfebbb59c2..a2df4637fd22 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1169,8 +1169,8 @@
<string name="no" msgid="5122037903299899715">"Отмена"</string>
<string name="dialog_alert_title" msgid="651856561974090712">"Внимание!"</string>
<string name="loading" msgid="3138021523725055037">"Загрузка…"</string>
- <string name="capital_on" msgid="2770685323900821829">"I"</string>
- <string name="capital_off" msgid="7443704171014626777">"O"</string>
+ <string name="capital_on" msgid="2770685323900821829">"Включено"</string>
+ <string name="capital_off" msgid="7443704171014626777">"Выключено"</string>
<string name="checked" msgid="9179896827054513119">"отмечено"</string>
<string name="not_checked" msgid="7972320087569023342">"не отмечено"</string>
<string name="selected" msgid="6614607926197755875">"выбрано"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 58c8b29dfad6..dafa0ad7989f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -6092,9 +6092,4 @@
<!-- Whether to show weather on the lock screen by default. -->
<bool name="config_lockscreenWeatherEnabledByDefault">false</bool>
-
- <!-- Whether to reset Battery Stats on unplug when the battery level is high. -->
- <bool name="config_batteryStatsResetOnUnplugHighBatteryLevel">true</bool>
- <!-- Whether to reset Battery Stats on unplug if the battery was significantly charged -->
- <bool name="config_batteryStatsResetOnUnplugAfterSignificantCharge">true</bool>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8addca27a7bb..591ba5feeee9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4903,7 +4903,4 @@
<!-- Whether to show weather on the lockscreen by default. -->
<java-symbol type="bool" name="config_lockscreenWeatherEnabledByDefault" />
-
- <java-symbol type="bool" name="config_batteryStatsResetOnUnplugHighBatteryLevel" />
- <java-symbol type="bool" name="config_batteryStatsResetOnUnplugAfterSignificantCharge" />
</resources>
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsResetTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsResetTest.java
deleted file mode 100644
index 9c2d332a7c70..000000000000
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsResetTest.java
+++ /dev/null
@@ -1,362 +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.internal.os;
-
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.os.BatteryManager;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class BatteryStatsResetTest {
-
- private static final int BATTERY_NOMINAL_VOLTAGE_MV = 3700;
- private static final int BATTERY_CAPACITY_UAH = 4_000_000;
- private static final int BATTERY_CHARGE_RATE_SECONDS_PER_LEVEL = 100;
-
- private MockClock mMockClock;
- private MockBatteryStatsImpl mBatteryStatsImpl;
-
-
- /**
- * Battery status. Must be one of the following:
- * {@link BatteryManager#BATTERY_STATUS_UNKNOWN}
- * {@link BatteryManager#BATTERY_STATUS_CHARGING}
- * {@link BatteryManager#BATTERY_STATUS_DISCHARGING}
- * {@link BatteryManager#BATTERY_STATUS_NOT_CHARGING}
- * {@link BatteryManager#BATTERY_STATUS_FULL}
- */
- private int mBatteryStatus;
- /**
- * Battery health. Must be one of the following:
- * {@link BatteryManager#BATTERY_HEALTH_UNKNOWN}
- * {@link BatteryManager#BATTERY_HEALTH_GOOD}
- * {@link BatteryManager#BATTERY_HEALTH_OVERHEAT}
- * {@link BatteryManager#BATTERY_HEALTH_DEAD}
- * {@link BatteryManager#BATTERY_HEALTH_OVER_VOLTAGE}
- * {@link BatteryManager#BATTERY_HEALTH_UNSPECIFIED_FAILURE}
- * {@link BatteryManager#BATTERY_HEALTH_COLD}
- */
- private int mBatteryHealth;
- /**
- * Battery plug type. Can be the union of any number of the following flags:
- * {@link BatteryManager#BATTERY_PLUGGED_AC}
- * {@link BatteryManager#BATTERY_PLUGGED_USB}
- * {@link BatteryManager#BATTERY_PLUGGED_WIRELESS}
- * {@link BatteryManager#BATTERY_PLUGGED_DOCK}
- *
- * Zero means the device is unplugged.
- */
- private int mBatteryPlugType;
- private int mBatteryLevel;
- private int mBatteryTemp;
- private int mBatteryVoltageMv;
- private int mBatteryChargeUah;
- private int mBatteryChargeFullUah;
- private long mBatteryChargeTimeToFullSeconds;
-
- @Before
- public void setUp() {
- final Context context = InstrumentationRegistry.getContext();
-
- mMockClock = new MockClock();
- mBatteryStatsImpl = new MockBatteryStatsImpl(mMockClock, context.getFilesDir());
- mBatteryStatsImpl.onSystemReady();
-
-
- // Set up the battery state. Start off with a fully charged plugged in battery.
- mBatteryStatus = BatteryManager.BATTERY_STATUS_FULL;
- mBatteryHealth = BatteryManager.BATTERY_HEALTH_GOOD;
- mBatteryPlugType = BatteryManager.BATTERY_PLUGGED_USB;
- mBatteryLevel = 100;
- mBatteryTemp = 70; // Arbitrary reasonable temperature.
- mBatteryVoltageMv = BATTERY_NOMINAL_VOLTAGE_MV;
- mBatteryChargeUah = BATTERY_CAPACITY_UAH;
- mBatteryChargeFullUah = BATTERY_CAPACITY_UAH;
- mBatteryChargeTimeToFullSeconds = 0;
- }
-
- @Test
- public void testResetOnUnplug_highBatteryLevel() {
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugHighBatteryLevel(true)
- .build());
-
- long expectedResetTimeUs = 0;
-
- unplugBattery();
- dischargeToLevel(60);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(80);
- unplugBattery();
- // Reset should not occur until battery level above 90.
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(95);
- // Reset should not occur until unplug.
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- unplugBattery();
- // Reset should occur on unplug now that battery level is high (>=90)
- expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000;
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // disable high battery level reset on unplug.
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugHighBatteryLevel(false)
- .build());
-
- dischargeToLevel(60);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(95);
- unplugBattery();
- // Reset should not occur since the high battery level logic has been disabled.
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
- }
-
- @Test
- public void testResetOnUnplug_significantCharge() {
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugAfterSignificantCharge(true)
- .build());
- long expectedResetTimeUs = 0;
-
- unplugBattery();
- // Battery level dropped below 20%.
- dischargeToLevel(15);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(50);
- unplugBattery();
- // Reset should not occur until battery level above 80
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(85);
- unplugBattery();
- // Reset should not occur because the charge session did not go from 20% to 80%
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Battery level dropped below 20%.
- dischargeToLevel(15);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(85);
- unplugBattery();
- // Reset should occur after significant charge amount.
- expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000;
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // disable reset on unplug after significant charge.
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugAfterSignificantCharge(false)
- .build());
-
- // Battery level dropped below 20%.
- dischargeToLevel(15);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(85);
- unplugBattery();
- // Reset should not occur after significant charge amount.
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
- }
-
- @Test
- public void testResetOnUnplug_manyPartialCharges() {
- long expectedResetTimeUs = 0;
-
- unplugBattery();
- // Cumulative battery discharged: 60%.
- dischargeToLevel(40);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(80);
- unplugBattery();
- // Reset should not occur
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Cumulative battery discharged: 100%.
- dischargeToLevel(40);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(80);
- unplugBattery();
- // Reset should not occur
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Cumulative battery discharged: 140%.
- dischargeToLevel(40);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(80);
- unplugBattery();
- // Reset should not occur
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Cumulative battery discharged: 180%.
- dischargeToLevel(40);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(80);
- unplugBattery();
- // Reset should not occur
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Cumulative battery discharged: 220%.
- dischargeToLevel(40);
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- chargeToLevel(80);
- unplugBattery();
- // Should reset after >200% of cumulative battery discharge
- expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000;
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
- }
-
- @Test
- public void testResetWhilePluggedIn_longPlugIn() {
- // disable high battery level reset on unplug.
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugHighBatteryLevel(false)
- .setResetOnUnplugAfterSignificantCharge(false)
- .build());
- long expectedResetTimeUs = 0;
-
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
- mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset should not occur
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Increment time a day
- incTimeMs(24L * 60L * 60L * 1000L);
- mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset should still not occur
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Increment time a day
- incTimeMs(24L * 60L * 60L * 1000L);
- mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset 47 hour threshold crossed, reset should occur.
- expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000;
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Increment time a day
- incTimeMs(24L * 60L * 60L * 1000L);
- mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset should not occur
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Increment time a day
- incTimeMs(24L * 60L * 60L * 1000L);
- mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset another 47 hour threshold crossed, reset should occur.
- expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000;
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Increment time a day
- incTimeMs(24L * 60L * 60L * 1000L);
- mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset should not occur
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- unplugBattery();
- plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
-
- // Increment time a day
- incTimeMs(24L * 60L * 60L * 1000L);
- mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset should not occur, since unplug occurred recently.
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
-
- // Increment time a day
- incTimeMs(24L * 60L * 60L * 1000L);
- mBatteryStatsImpl.maybeResetWhilePluggedInLocked();
- // Reset another 47 hour threshold crossed, reset should occur.
- expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000;
- assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
- }
-
- private void dischargeToLevel(int targetLevel) {
- mBatteryStatus = BatteryManager.BATTERY_STATUS_DISCHARGING;
- for (int level = mBatteryLevel - 1; level >= targetLevel; level--) {
- prepareBatteryLevel(level);
- incTimeMs(5000); // Arbitrary discharge rate.
- updateBatteryState();
- }
- }
-
- private void chargeToLevel(int targetLevel) {
- mBatteryStatus = BatteryManager.BATTERY_STATUS_CHARGING;
- for (int level = mBatteryLevel + 1; level <= targetLevel; level++) {
- if (level >= 100) mBatteryStatus = BatteryManager.BATTERY_STATUS_FULL;
- prepareBatteryLevel(level);
- incTimeMs(BATTERY_CHARGE_RATE_SECONDS_PER_LEVEL * 1000);
- updateBatteryState();
- }
- }
-
- private void unplugBattery() {
- mBatteryPlugType = 0;
- updateBatteryState();
- }
-
- private void plugBattery(int type) {
- mBatteryPlugType |= type;
- updateBatteryState();
- }
-
- private void prepareBatteryLevel(int level) {
- mBatteryLevel = level;
- mBatteryChargeUah = mBatteryLevel * mBatteryChargeFullUah / 100;
- mBatteryChargeTimeToFullSeconds =
- (100 - mBatteryLevel) * BATTERY_CHARGE_RATE_SECONDS_PER_LEVEL;
- }
-
- private void incTimeMs(long milliseconds) {
- mMockClock.realtime += milliseconds;
- mMockClock.uptime += milliseconds / 2; // Arbitrary slower uptime accumulation
- mMockClock.currentTime += milliseconds;
- }
-
- private void updateBatteryState() {
- mBatteryStatsImpl.setBatteryStateLocked(mBatteryStatus, mBatteryHealth, mBatteryPlugType,
- mBatteryLevel, mBatteryTemp, mBatteryVoltageMv, mBatteryChargeUah,
- mBatteryChargeFullUah, mBatteryChargeTimeToFullSeconds,
- mMockClock.elapsedRealtime(), mMockClock.uptimeMillis(),
- mMockClock.currentTimeMillis());
- }
-}
-
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
index ae2d1afe0320..274286135174 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
@@ -342,7 +342,7 @@ public class BatteryUsageStatsProviderTest {
Context context = InstrumentationRegistry.getContext();
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
mStatsRule.setCurrentTime(5 * MINUTE_IN_MS);
- batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ batteryStats.resetAllStatsCmdLocked();
BatteryUsageStatsStore batteryUsageStatsStore = new BatteryUsageStatsStore(context,
batteryStats, new File(context.getCacheDir(), "BatteryUsageStatsProviderTest"),
@@ -357,14 +357,14 @@ public class BatteryUsageStatsProviderTest {
batteryStats.noteFlashlightOffLocked(APP_UID,
20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS);
mStatsRule.setCurrentTime(25 * MINUTE_IN_MS);
- batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ batteryStats.resetAllStatsCmdLocked();
batteryStats.noteFlashlightOnLocked(APP_UID,
30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
batteryStats.noteFlashlightOffLocked(APP_UID,
50 * MINUTE_IN_MS, 50 * MINUTE_IN_MS);
mStatsRule.setCurrentTime(55 * MINUTE_IN_MS);
- batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ batteryStats.resetAllStatsCmdLocked();
// This section should be ignored because the timestamp is out or range
batteryStats.noteFlashlightOnLocked(APP_UID,
@@ -372,7 +372,7 @@ public class BatteryUsageStatsProviderTest {
batteryStats.noteFlashlightOffLocked(APP_UID,
70 * MINUTE_IN_MS, 70 * MINUTE_IN_MS);
mStatsRule.setCurrentTime(75 * MINUTE_IN_MS);
- batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ batteryStats.resetAllStatsCmdLocked();
// This section should be ignored because it represents the current stats session
batteryStats.noteFlashlightOnLocked(APP_UID,
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java
index 11b9047fab7f..c9729fab3b5e 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java
@@ -84,7 +84,7 @@ public class BatteryUsageStatsStoreTest {
mMockClock.realtime = 1_000_000;
mMockClock.uptime = 1_000_000;
- mBatteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ mBatteryStats.resetAllStatsCmdLocked();
final long[] timestamps = mBatteryUsageStatsStore.listBatteryUsageStatsTimestamps();
assertThat(timestamps).hasLength(1);
@@ -114,7 +114,7 @@ public class BatteryUsageStatsStoreTest {
final int numberOfSnapshots =
(int) (MAX_BATTERY_STATS_SNAPSHOT_STORAGE_BYTES / snapshotFileSize);
for (int i = 0; i < numberOfSnapshots + 2; i++) {
- mBatteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ mBatteryStats.resetAllStatsCmdLocked();
mMockClock.realtime += 10_000_000;
mMockClock.uptime += 10_000_000;
@@ -141,7 +141,7 @@ public class BatteryUsageStatsStoreTest {
mMockClock.currentTime += 10_000_000;
prepareBatteryStats();
- mBatteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ mBatteryStats.resetAllStatsCmdLocked();
}
assertThat(getDirectorySize(mStoreDirectory)).isNotEqualTo(0);
diff --git a/libs/WindowManager/Shell/res/color/split_divider_background.xml b/libs/WindowManager/Shell/res/color-night/taskbar_background.xml
index 049980803ee3..9473cdd607d6 100644
--- a/libs/WindowManager/Shell/res/color/split_divider_background.xml
+++ b/libs/WindowManager/Shell/res/color-night/taskbar_background.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2021 The Android Open Source Project
+ ~ 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.
@@ -14,6 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
+<!-- Should be the same as in packages/apps/Launcher3/res/color-night-v31/taskbar_background.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/system_neutral1_500" android:lStar="15" />
</selector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/color/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background.xml
index b3d260299106..0e165fca4fd3 100644
--- a/libs/WindowManager/Shell/res/color/taskbar_background.xml
+++ b/libs/WindowManager/Shell/res/color/taskbar_background.xml
@@ -16,5 +16,5 @@
-->
<!-- Should be the same as in packages/apps/Launcher3/res/color-v31/taskbar_background.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="@android:color/system_neutral1_500" android:lStar="15" />
+ <item android:color="@android:color/system_neutral1_500" android:lStar="95" />
</selector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml
index 9167382d0898..c6e634c6622c 100644
--- a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml
+++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml
@@ -17,6 +17,6 @@
<shape android:shape="rectangle"
xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/white" />
- <corners android:radius="20dp" />
+ <corners android:radius="@dimen/caption_menu_corner_radius" />
<stroke android:width="1dp" android:color="#b3b3b3"/>
</shape>
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml
index f6e3f2edfa14..f9aeb6a8448a 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml
@@ -21,7 +21,6 @@
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@drawable/desktop_mode_decor_menu_background"
- android:elevation="@dimen/caption_menu_elevation"
android:divider="?android:attr/dividerHorizontal"
android:showDividers="middle"
android:dividerPadding="18dip">
@@ -63,38 +62,46 @@
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="0.5" />
- <Button
+ <ImageButton
style="@style/CaptionWindowingButtonStyle"
android:id="@+id/fullscreen_button"
android:contentDescription="@string/fullscreen_text"
- android:background="@drawable/caption_fullscreen_button"/>
+ android:src="@drawable/caption_fullscreen_button"
+ android:scaleType="fitCenter"
+ android:background="?android:selectableItemBackgroundBorderless"/>
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" />
- <Button
+ <ImageButton
style="@style/CaptionWindowingButtonStyle"
android:id="@+id/split_screen_button"
android:contentDescription="@string/split_screen_text"
- android:background="@drawable/caption_split_screen_button"/>
+ android:src="@drawable/caption_split_screen_button"
+ android:scaleType="fitCenter"
+ android:background="?android:selectableItemBackgroundBorderless"/>
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" />
- <Button
+ <ImageButton
style="@style/CaptionWindowingButtonStyle"
android:id="@+id/floating_button"
android:contentDescription="@string/float_button_text"
- android:background="@drawable/caption_floating_button"/>
+ android:src="@drawable/caption_floating_button"
+ android:scaleType="fitCenter"
+ android:background="?android:selectableItemBackgroundBorderless"/>
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" />
- <Button
+ <ImageButton
style="@style/CaptionWindowingButtonStyle"
android:id="@+id/desktop_button"
android:contentDescription="@string/desktop_text"
- android:background="@drawable/caption_desktop_button"/>
+ android:src="@drawable/caption_desktop_button"
+ android:scaleType="fitCenter"
+ android:background="?android:selectableItemBackgroundBorderless"/>
<Space
android:layout_width="0dp"
android:layout_height="1dp"
diff --git a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
index e8edad15dfc3..413cfd78fd91 100644
--- a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
@@ -16,9 +16,7 @@
<com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@android:color/system_neutral1_900">
+ style="@style/LetterboxDialog">
<!-- The background of the top-level layout acts as the background dim. -->
diff --git a/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml
index ba9852c4dd6b..5aff4159e135 100644
--- a/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml
@@ -16,14 +16,10 @@
<com.android.wm.shell.compatui.RestartDialogLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@android:color/system_neutral1_900">
+ style="@style/LetterboxDialog">
<!-- The background of the top-level layout acts as the background dim. -->
- <!--TODO (b/266288912): Resolve overdraw warning -->
-
<!-- Vertical margin will be set dynamically since it depends on task bounds.
Setting the alpha of the dialog container to 0, since it shouldn't be visible until the
enter animation starts. -->
diff --git a/libs/WindowManager/Shell/res/values-night/colors.xml b/libs/WindowManager/Shell/res/values-night/colors.xml
index 83c4d93982f4..5c6bb57a7f1c 100644
--- a/libs/WindowManager/Shell/res/values-night/colors.xml
+++ b/libs/WindowManager/Shell/res/values-night/colors.xml
@@ -15,6 +15,7 @@
-->
<resources>
+ <color name="docked_divider_handle">#ffffff</color>
<!-- Bubbles -->
<color name="bubbles_icon_tint">@color/GM2_grey_200</color>
<!-- Splash screen-->
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index 6e750a3d5e34..6fb70006e67f 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -17,7 +17,8 @@
*/
-->
<resources>
- <color name="docked_divider_handle">#ffffff</color>
+ <color name="docked_divider_handle">#000000</color>
+ <color name="split_divider_background">@color/taskbar_background</color>
<drawable name="forced_resizable_background">#59000000</drawable>
<color name="minimize_dock_shadow_start">#60000000</color>
<color name="minimize_dock_shadow_end">#00000000</color>
@@ -41,6 +42,9 @@
<color name="letterbox_education_accent_primary">@android:color/system_accent1_100</color>
<color name="letterbox_education_text_secondary">@android:color/system_neutral2_200</color>
+ <!-- Letterbox Dialog -->
+ <color name="letterbox_dialog_background">@android:color/system_neutral1_900</color>
+
<!-- GM2 colors -->
<color name="GM2_grey_200">#E8EAED</color>
<color name="GM2_grey_700">#5F6368</color>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 336c156e831a..680ad5101366 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -370,6 +370,10 @@
<dimen name="freeform_resize_corner">44dp</dimen>
- <dimen name="caption_menu_elevation">4dp</dimen>
+ <!-- The radius of the caption menu shadow. -->
+ <dimen name="caption_menu_shadow_radius">4dp</dimen>
+
+ <!-- The radius of the caption menu corners. -->
+ <dimen name="caption_menu_corner_radius">20dp</dimen>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml
index 0a0c49f2d93f..bc2e71d1c013 100644
--- a/libs/WindowManager/Shell/res/values/styles.xml
+++ b/libs/WindowManager/Shell/res/values/styles.xml
@@ -38,11 +38,9 @@
</style>
<style name="CaptionWindowingButtonStyle">
- <item name="android:layout_width">32dp</item>
- <item name="android:layout_height">32dp</item>
+ <item name="android:layout_width">40dp</item>
+ <item name="android:layout_height">40dp</item>
<item name="android:padding">4dp</item>
- <item name="android:layout_marginTop">5dp</item>
- <item name="android:layout_marginBottom">5dp</item>
</style>
<style name="CaptionMenuButtonStyle" parent="@style/Widget.AppCompat.Button.Borderless">
@@ -80,6 +78,12 @@
<item name="android:textColor">@color/tv_pip_edu_text</item>
</style>
+ <style name="LetterboxDialog" parent="@android:style/Theme.Holo">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:background">@color/letterbox_dialog_background</item>
+ </style>
+
<style name="RestartDialogTitleText">
<item name="android:textSize">24sp</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 71e15c12b9c0..c08085ee8cd0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -61,6 +61,7 @@ import android.os.Binder;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.notification.NotificationListenerService;
@@ -125,6 +126,15 @@ public class BubbleController implements ConfigurationChangeListener {
private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
private static final String SYSTEM_DIALOG_REASON_GESTURE_NAV = "gestureNav";
+ // TODO(b/256873975) Should use proper flag when available to shell/launcher
+ /**
+ * Whether bubbles are showing in the bubble bar from launcher. This is only available
+ * on large screens and {@link BubbleController#isShowingAsBubbleBar()} should be used
+ * to check all conditions that indicate if the bubble bar is in use.
+ */
+ private static final boolean BUBBLE_BAR_ENABLED =
+ SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false);
+
private final Context mContext;
private final BubblesImpl mImpl = new BubblesImpl();
private Bubbles.BubbleExpandListener mExpandListener;
@@ -150,9 +160,6 @@ public class BubbleController implements ConfigurationChangeListener {
private final ShellExecutor mBackgroundExecutor;
- // Whether or not we should show bubbles pinned at the bottom of the screen.
- private boolean mIsBubbleBarEnabled;
-
private BubbleLogger mLogger;
private BubbleData mBubbleData;
@Nullable private BubbleStackView mStackView;
@@ -533,10 +540,10 @@ public class BubbleController implements ConfigurationChangeListener {
mDataRepository.removeBubblesForUser(removedUserId, parentUserId);
}
- // TODO(b/256873975): Should pass this into the constructor once flags are available to shell.
- /** Sets whether the bubble bar is enabled (i.e. bubbles pinned to bottom on large screens). */
- public void setBubbleBarEnabled(boolean enabled) {
- mIsBubbleBarEnabled = enabled;
+ /** Whether bubbles are showing in the bubble bar. */
+ public boolean isShowingAsBubbleBar() {
+ // TODO(b/269670598): should also check that we're in gesture nav
+ return BUBBLE_BAR_ENABLED && mBubblePositioner.isLargeScreen();
}
/** Whether this userId belongs to the current user. */
@@ -605,12 +612,6 @@ public class BubbleController implements ConfigurationChangeListener {
mStackView.setUnbubbleConversationCallback(mSysuiProxy::onUnbubbleConversation);
}
- if (mIsBubbleBarEnabled && mBubblePositioner.isLargeScreen()) {
- mBubblePositioner.setUsePinnedLocation(true);
- } else {
- mBubblePositioner.setUsePinnedLocation(false);
- }
-
addToWindowManagerMaybe();
}
@@ -1852,13 +1853,6 @@ public class BubbleController implements ConfigurationChangeListener {
}
@Override
- public void setBubbleBarEnabled(boolean enabled) {
- mMainExecutor.execute(() -> {
- BubbleController.this.setBubbleBarEnabled(enabled);
- });
- }
-
- @Override
public void onNotificationPanelExpandedChanged(boolean expanded) {
mMainExecutor.execute(
() -> BubbleController.this.onNotificationPanelExpandedChanged(expanded));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 6230d22ebe12..3fd09675a245 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -283,7 +283,7 @@ public class BubbleData {
}
boolean isShowingOverflow() {
- return mShowingOverflow && (isExpanded() || mPositioner.showingInTaskbar());
+ return mShowingOverflow && isExpanded();
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 07c58527a815..5ea2450114f0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -18,9 +18,6 @@ package com.android.wm.shell.bubbles;
import static android.view.View.LAYOUT_DIRECTION_RTL;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.IntDef;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -39,8 +36,6 @@ import androidx.annotation.VisibleForTesting;
import com.android.launcher3.icons.IconNormalizer;
import com.android.wm.shell.R;
-import java.lang.annotation.Retention;
-
/**
* Keeps track of display size, configuration, and specific bubble sizes. One place for all
* placement and positioning calculations to refer to.
@@ -50,15 +45,6 @@ public class BubblePositioner {
? "BubblePositioner"
: BubbleDebugConfig.TAG_BUBBLES;
- @Retention(SOURCE)
- @IntDef({TASKBAR_POSITION_NONE, TASKBAR_POSITION_RIGHT, TASKBAR_POSITION_LEFT,
- TASKBAR_POSITION_BOTTOM})
- @interface TaskbarPosition {}
- public static final int TASKBAR_POSITION_NONE = -1;
- public static final int TASKBAR_POSITION_RIGHT = 0;
- public static final int TASKBAR_POSITION_LEFT = 1;
- public static final int TASKBAR_POSITION_BOTTOM = 2;
-
/** When the bubbles are collapsed in a stack only some of them are shown, this is how many. **/
public static final int NUM_VISIBLE_WHEN_RESTING = 2;
/** Indicates a bubble's height should be the maximum available space. **/
@@ -108,15 +94,9 @@ public class BubblePositioner {
private int mOverflowHeight;
private int mMinimumFlyoutWidthLargeScreen;
- private PointF mPinLocation;
private PointF mRestingStackPosition;
private int[] mPaddings = new int[4];
- private boolean mShowingInTaskbar;
- private @TaskbarPosition int mTaskbarPosition = TASKBAR_POSITION_NONE;
- private int mTaskbarIconSize;
- private int mTaskbarSize;
-
public BubblePositioner(Context context, WindowManager windowManager) {
mContext = context;
mWindowManager = windowManager;
@@ -153,27 +133,11 @@ public class BubblePositioner {
+ " insets: " + insets
+ " isLargeScreen: " + mIsLargeScreen
+ " isSmallTablet: " + mIsSmallTablet
- + " bounds: " + bounds
- + " showingInTaskbar: " + mShowingInTaskbar);
+ + " bounds: " + bounds);
}
updateInternal(mRotation, insets, bounds);
}
- /**
- * Updates position information to account for taskbar state.
- *
- * @param taskbarPosition which position the taskbar is displayed in.
- * @param showingInTaskbar whether the taskbar is being shown.
- */
- public void updateForTaskbar(int iconSize,
- @TaskbarPosition int taskbarPosition, boolean showingInTaskbar, int taskbarSize) {
- mShowingInTaskbar = showingInTaskbar;
- mTaskbarIconSize = iconSize;
- mTaskbarPosition = taskbarPosition;
- mTaskbarSize = taskbarSize;
- update();
- }
-
@VisibleForTesting
public void updateInternal(int rotation, Insets insets, Rect bounds) {
mRotation = rotation;
@@ -232,10 +196,6 @@ public class BubblePositioner {
R.dimen.bubbles_flyout_min_width_large_screen);
mMaxBubbles = calculateMaxBubbles();
-
- if (mShowingInTaskbar) {
- adjustForTaskbar();
- }
}
/**
@@ -260,30 +220,6 @@ public class BubblePositioner {
return mDefaultMaxBubbles;
}
- /**
- * Taskbar insets appear as navigationBar insets, however, unlike navigationBar this should
- * not inset bubbles UI as bubbles floats above the taskbar. This adjust the available space
- * and insets to account for the taskbar.
- */
- // TODO(b/171559950): When the insets are reported correctly we can remove this logic
- private void adjustForTaskbar() {
- // When bar is showing on edges... subtract that inset because we appear on top
- if (mShowingInTaskbar && mTaskbarPosition != TASKBAR_POSITION_BOTTOM) {
- WindowInsets metricInsets = mWindowManager.getCurrentWindowMetrics().getWindowInsets();
- Insets navBarInsets = metricInsets.getInsetsIgnoringVisibility(
- WindowInsets.Type.navigationBars());
- int newInsetLeft = mInsets.left;
- int newInsetRight = mInsets.right;
- if (mTaskbarPosition == TASKBAR_POSITION_LEFT) {
- mPositionRect.left -= navBarInsets.left;
- newInsetLeft -= navBarInsets.left;
- } else if (mTaskbarPosition == TASKBAR_POSITION_RIGHT) {
- mPositionRect.right += navBarInsets.right;
- newInsetRight -= navBarInsets.right;
- }
- mInsets = Insets.of(newInsetLeft, mInsets.top, newInsetRight, mInsets.bottom);
- }
- }
/**
* @return a rect of available screen space accounting for orientation, system bars and cutouts.
@@ -327,14 +263,12 @@ public class BubblePositioner {
* to the left or right side.
*/
public boolean showBubblesVertically() {
- return isLandscape() || mShowingInTaskbar || mIsLargeScreen;
+ return isLandscape() || mIsLargeScreen;
}
/** Size of the bubble. */
public int getBubbleSize() {
- return (mShowingInTaskbar && mTaskbarIconSize > 0)
- ? mTaskbarIconSize
- : mBubbleSize;
+ return mBubbleSize;
}
/** The amount of padding at the top of the screen that the bubbles avoid when being placed. */
@@ -699,9 +633,6 @@ public class BubblePositioner {
/** The position the bubble stack should rest at when collapsed. */
public PointF getRestingPosition() {
- if (mPinLocation != null) {
- return mPinLocation;
- }
if (mRestingStackPosition == null) {
return getDefaultStartPosition();
}
@@ -713,9 +644,6 @@ public class BubblePositioner {
* is being shown.
*/
public PointF getDefaultStartPosition() {
- if (mPinLocation != null) {
- return mPinLocation;
- }
// Start on the left if we're in LTR, right otherwise.
final boolean startOnLeft =
mContext.getResources().getConfiguration().getLayoutDirection()
@@ -730,7 +658,6 @@ public class BubblePositioner {
1 /* default starts with 1 bubble */));
}
-
/**
* Returns the region that the stack position must stay within. This goes slightly off the left
* and right sides of the screen, below the status bar/cutout and above the navigation bar.
@@ -751,39 +678,6 @@ public class BubblePositioner {
}
/**
- * @return whether the bubble stack is pinned to the taskbar.
- */
- public boolean showingInTaskbar() {
- return mShowingInTaskbar;
- }
-
- /**
- * @return the taskbar position if set.
- */
- public int getTaskbarPosition() {
- return mTaskbarPosition;
- }
-
- public int getTaskbarSize() {
- return mTaskbarSize;
- }
-
- /**
- * In some situations bubbles will be pinned to a specific onscreen location. This sets whether
- * bubbles should be pinned or not.
- */
- public void setUsePinnedLocation(boolean usePinnedLocation) {
- if (usePinnedLocation) {
- mShowingInTaskbar = true;
- mPinLocation = new PointF(mPositionRect.right - mBubbleSize,
- mPositionRect.bottom - mBubbleSize);
- } else {
- mPinLocation = null;
- mShowingInTaskbar = false;
- }
- }
-
- /**
* Navigation bar has an area where system gestures can be started from.
*
* @return {@link Rect} for system navigation bar gesture zone
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 f2afefe243bc..15f8eaca0833 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
@@ -680,8 +680,6 @@ public class BubbleStackView extends FrameLayout
// Re-show the expanded view if we hid it.
showExpandedViewIfNeeded();
- } else if (mPositioner.showingInTaskbar()) {
- mStackAnimationController.snapStackBack();
} else {
// Fling the stack to the edge, and save whether or not it's going to end up on
// the left side of the screen.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index df4325763a17..a5deac5a51da 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -257,11 +257,6 @@ public interface Bubbles {
*/
void onUserRemoved(int removedUserId);
- /**
- * Sets whether bubble bar should be enabled or not.
- */
- void setBubbleBarEnabled(boolean enabled);
-
/** Listener to find out about stack expansion / collapse events. */
interface BubbleExpandListener {
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
index 0ee0ea60a1bc..5533842f2d89 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
@@ -417,23 +417,9 @@ public class StackAnimationController extends
}
/**
- * Snaps the stack back to the previous resting position.
- */
- public void snapStackBack() {
- if (mLayout == null) {
- return;
- }
- PointF p = getStackPositionAlongNearestHorizontalEdge();
- springStackAfterFling(p.x, p.y);
- }
-
- /**
* Where the stack would be if it were snapped to the nearest horizontal edge (left or right).
*/
public PointF getStackPositionAlongNearestHorizontalEdge() {
- if (mPositioner.showingInTaskbar()) {
- return mPositioner.getRestingPosition();
- }
final PointF stackPos = getStackPosition();
final boolean onLeft = mLayout.isFirstChildXLeftOfCenter(stackPos.x);
final RectF bounds = mPositioner.getAllowableStackPositionRegion(getBubbleCount());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index f616e6f64750..ffc56b6f6106 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -120,6 +120,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
private int mOrientation;
private int mRotation;
private int mDensity;
+ private int mUiMode;
private final boolean mDimNonImeSide;
private ValueAnimator mDividerFlingAnimator;
@@ -295,10 +296,12 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
final Rect rootBounds = configuration.windowConfiguration.getBounds();
final int orientation = configuration.orientation;
final int density = configuration.densityDpi;
+ final int uiMode = configuration.uiMode;
if (mOrientation == orientation
&& mRotation == rotation
&& mDensity == density
+ && mUiMode == uiMode
&& mRootBounds.equals(rootBounds)) {
return false;
}
@@ -310,6 +313,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
mRootBounds.set(rootBounds);
mRotation = rotation;
mDensity = density;
+ mUiMode = uiMode;
mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null);
updateDividerConfig(mContext);
initDividerPosition(mTempRect);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index 3b2db5127316..76d9152fdfbc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -126,14 +126,12 @@ public class CompatUIController implements OnDisplaysChangedListener,
private final Lazy<Transitions> mTransitionsLazy;
private final DockStateReader mDockStateReader;
private final CompatUIConfiguration mCompatUIConfiguration;
-
- private CompatUICallback mCallback;
-
// Only show each hint once automatically in the process life.
private final CompatUIHintsState mCompatUIHintsState;
-
private final CompatUIShellCommandHandler mCompatUIShellCommandHandler;
+ private CompatUICallback mCallback;
+
// Indicates if the keyguard is currently showing, in which case compat UIs shouldn't
// be shown.
private boolean mKeyguardShowing;
@@ -372,19 +370,20 @@ public class CompatUIController implements OnDisplaysChangedListener,
RestartDialogWindowManager layout =
mTaskIdToRestartDialogWindowManagerMap.get(taskInfo.taskId);
if (layout != null) {
- // TODO(b/266262111) Handle theme change when taskListener changes
- if (layout.getTaskListener() != taskListener) {
- mSetOfTaskIdsShowingRestartDialog.remove(taskInfo.taskId);
- }
- layout.setRequestRestartDialog(
- mSetOfTaskIdsShowingRestartDialog.contains(taskInfo.taskId));
- // UI already exists, update the UI layout.
- if (!layout.updateCompatInfo(taskInfo, taskListener,
- showOnDisplay(layout.getDisplayId()))) {
- // The layout is no longer eligible to be shown, remove from active layouts.
+ if (layout.needsToBeRecreated(taskInfo, taskListener)) {
mTaskIdToRestartDialogWindowManagerMap.remove(taskInfo.taskId);
+ layout.release();
+ } else {
+ layout.setRequestRestartDialog(
+ mSetOfTaskIdsShowingRestartDialog.contains(taskInfo.taskId));
+ // UI already exists, update the UI layout.
+ if (!layout.updateCompatInfo(taskInfo, taskListener,
+ showOnDisplay(layout.getDisplayId()))) {
+ // The layout is no longer eligible to be shown, remove from active layouts.
+ mTaskIdToRestartDialogWindowManagerMap.remove(taskInfo.taskId);
+ }
+ return;
}
- return;
}
// Create a new UI layout.
final Context context = getOrCreateDisplayContext(taskInfo.displayId);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
index db87f657c1b2..cfb2accbcecd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
@@ -151,7 +151,6 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana
@Override
public void setConfiguration(Configuration configuration) {
super.setConfiguration(configuration);
- // TODO(b/266262111): Investigate loss of theme configuration when switching TaskListener
mContext = mContext.createConfigurationContext(configuration);
}
@@ -211,7 +210,8 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana
}
View layout = getLayout();
- if (layout == null || prevTaskListener != taskListener) {
+ if (layout == null || prevTaskListener != taskListener
+ || mTaskConfig.uiMode != prevTaskConfig.uiMode) {
// Layout wasn't created yet or TaskListener changed, recreate the layout for new
// surface parent.
release();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java
index 10f25d0eef11..2440838844c4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java
@@ -155,6 +155,11 @@ class RestartDialogWindowManager extends CompatUIWindowManagerAbstract {
return super.updateCompatInfo(taskInfo, taskListener, canShow);
}
+ boolean needsToBeRecreated(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener) {
+ return taskInfo.configuration.uiMode != mTaskInfo.configuration.uiMode
+ || !getTaskListener().equals(taskListener);
+ }
+
private void updateDialogMargins() {
if (mLayout == null) {
return;
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 1239cdc5b606..45785238fe00 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
@@ -194,7 +194,8 @@ public abstract class WMShellModule {
DisplayController displayController,
SyncTransactionQueue syncQueue,
Optional<DesktopModeController> desktopModeController,
- Optional<DesktopTasksController> desktopTasksController) {
+ Optional<DesktopTasksController> desktopTasksController,
+ Optional<SplitScreenController> splitScreenController) {
if (DesktopModeStatus.isAnyEnabled()) {
return new DesktopModeWindowDecorViewModel(
context,
@@ -204,7 +205,8 @@ public abstract class WMShellModule {
displayController,
syncQueue,
desktopModeController,
- desktopTasksController);
+ desktopTasksController,
+ splitScreenController);
}
return new CaptionWindowDecorViewModel(
context,
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 fce013837f01..73a740381090 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
@@ -85,7 +85,7 @@ class DesktopTasksController(
fun showDesktopApps() {
ProtoLog.v(WM_SHELL_DESKTOP_MODE, "showDesktopApps")
val wct = WindowContainerTransaction()
- bringDesktopAppsToFront(wct, force = true)
+ bringDesktopAppsToFront(wct)
// Execute transaction if there are pending operations
if (!wct.isEmpty) {
@@ -156,19 +156,9 @@ class DesktopTasksController(
?: WINDOWING_MODE_UNDEFINED
}
- private fun bringDesktopAppsToFront(wct: WindowContainerTransaction, force: Boolean = false) {
- val activeTasks = desktopModeTaskRepository.getActiveTasks()
-
- // Skip if all tasks are already visible
- if (!force && activeTasks.all(desktopModeTaskRepository::isVisibleTask)) {
- ProtoLog.d(
- WM_SHELL_DESKTOP_MODE,
- "bringDesktopAppsToFront: active tasks are already in front, skipping."
- )
- return
- }
-
+ private fun bringDesktopAppsToFront(wct: WindowContainerTransaction) {
ProtoLog.v(WM_SHELL_DESKTOP_MODE, "bringDesktopAppsToFront")
+ val activeTasks = desktopModeTaskRepository.getActiveTasks()
// First move home to front and then other tasks on top of it
moveHomeTaskToFront(wct)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index b59fe1818780..4cfaae6e51c7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -36,6 +36,7 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_U
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import android.content.ClipDescription;
+import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
@@ -58,9 +59,9 @@ import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.annotations.ExternalMainThread;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
-import com.android.wm.shell.sysui.ConfigurationChangeListener;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
@@ -70,7 +71,7 @@ import java.util.ArrayList;
* Handles the global drag and drop handling for the Shell.
*/
public class DragAndDropController implements DisplayController.OnDisplaysChangedListener,
- View.OnDragListener, ConfigurationChangeListener {
+ View.OnDragListener, ComponentCallbacks2 {
private static final String TAG = DragAndDropController.class.getSimpleName();
@@ -119,7 +120,6 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
mMainExecutor.executeDelayed(() -> {
mDisplayController.addDisplayWindowListener(this);
}, 0);
- mShellController.addConfigurationChangeListener(this);
}
/**
@@ -180,6 +180,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
try {
wm.addView(rootView, layoutParams);
addDisplayDropTarget(displayId, context, wm, rootView, dragLayout);
+ context.registerComponentCallbacks(this);
} catch (WindowManager.InvalidDisplayException e) {
Slog.w(TAG, "Unable to add view for display id: " + displayId);
}
@@ -209,6 +210,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
if (pd == null) {
return;
}
+ pd.context.unregisterComponentCallbacks(this);
pd.wm.removeViewImmediate(pd.rootView);
mDisplayDropTargets.remove(displayId);
}
@@ -328,18 +330,29 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
return mimeTypes;
}
+ // Note: Component callbacks are always called on the main thread of the process
+ @ExternalMainThread
@Override
- public void onThemeChanged() {
- for (int i = 0; i < mDisplayDropTargets.size(); i++) {
- mDisplayDropTargets.get(i).dragLayout.onThemeChange();
- }
+ public void onConfigurationChanged(Configuration newConfig) {
+ mMainExecutor.execute(() -> {
+ for (int i = 0; i < mDisplayDropTargets.size(); i++) {
+ mDisplayDropTargets.get(i).dragLayout.onConfigChanged(newConfig);
+ }
+ });
}
+ // Note: Component callbacks are always called on the main thread of the process
+ @ExternalMainThread
@Override
- public void onConfigurationChanged(Configuration newConfig) {
- for (int i = 0; i < mDisplayDropTargets.size(); i++) {
- mDisplayDropTargets.get(i).dragLayout.onConfigChanged(newConfig);
- }
+ public void onTrimMemory(int level) {
+ // Do nothing
+ }
+
+ // Note: Component callbacks are always called on the main thread of the process
+ @ExternalMainThread
+ @Override
+ public void onLowMemory() {
+ // Do nothing
}
private static class PerDisplay {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index 44fd8eec4d06..fe42822ab6a1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -18,6 +18,8 @@ package com.android.wm.shell.draganddrop;
import static android.app.StatusBarManager.DISABLE_NONE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.content.pm.ActivityInfo.CONFIG_ASSETS_PATHS;
+import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
@@ -72,6 +74,7 @@ public class DragLayout extends LinearLayout {
private final SplitScreenController mSplitScreenController;
private final IconProvider mIconProvider;
private final StatusBarManager mStatusBarManager;
+ private final Configuration mLastConfiguration = new Configuration();
private DragAndDropPolicy.Target mCurrentTarget = null;
private DropZoneView mDropZoneView1;
@@ -92,6 +95,7 @@ public class DragLayout extends LinearLayout {
mIconProvider = iconProvider;
mPolicy = new DragAndDropPolicy(context, splitScreenController);
mStatusBarManager = context.getSystemService(StatusBarManager.class);
+ mLastConfiguration.setTo(context.getResources().getConfiguration());
mDisplayMargin = context.getResources().getDimensionPixelSize(
R.dimen.drop_layout_display_margin);
@@ -132,11 +136,6 @@ public class DragLayout extends LinearLayout {
return super.onApplyWindowInsets(insets);
}
- public void onThemeChange() {
- mDropZoneView1.onThemeChange();
- mDropZoneView2.onThemeChange();
- }
-
public void onConfigChanged(Configuration newConfig) {
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE
&& getOrientation() != HORIZONTAL) {
@@ -147,6 +146,15 @@ public class DragLayout extends LinearLayout {
setOrientation(LinearLayout.VERTICAL);
updateContainerMargins(newConfig.orientation);
}
+
+ final int diff = newConfig.diff(mLastConfiguration);
+ final boolean themeChanged = (diff & CONFIG_ASSETS_PATHS) != 0
+ || (diff & CONFIG_UI_MODE) != 0;
+ if (themeChanged) {
+ mDropZoneView1.onThemeChange();
+ mDropZoneView2.onThemeChange();
+ }
+ mLastConfiguration.setTo(newConfig);
}
private void updateContainerMarginsForSingleTask() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
index 26f47fcdaa44..d094c229e0f8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
@@ -108,6 +108,10 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
}
if (!createdWindowDecor) {
mSyncQueue.runInSync(t -> {
+ if (!leash.isValid()) {
+ // Task vanished before sync completion
+ return;
+ }
// Reset several properties back to fullscreen (PiP, for example, leaves all these
// properties in a bad state).
t.setWindowCrop(leash, null);
@@ -136,6 +140,10 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
final Point positionInParent = state.mTaskInfo.positionInParent;
if (!oldPositionInParent.equals(state.mTaskInfo.positionInParent)) {
mSyncQueue.runInSync(t -> {
+ if (!state.mLeash.isValid()) {
+ // Task vanished before sync completion
+ return;
+ }
t.setPosition(state.mLeash, positionInParent.x, positionInParent.y);
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
index 480bf93b2ddb..53bf42a3c911 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
@@ -39,6 +39,9 @@ import android.window.TaskSnapshot;
* Represents the content overlay used during the entering PiP animation.
*/
public abstract class PipContentOverlay {
+ // Fixed string used in WMShellFlickerTests
+ protected static final String LAYER_NAME = "PipContentOverlay";
+
protected SurfaceControl mLeash;
/** Attaches the internal {@link #mLeash} to the given parent leash. */
@@ -86,7 +89,7 @@ public abstract class PipContentOverlay {
mContext = context;
mLeash = new SurfaceControl.Builder(new SurfaceSession())
.setCallsite(TAG)
- .setName(TAG)
+ .setName(LAYER_NAME)
.setColorLayer()
.build();
}
@@ -139,7 +142,7 @@ public abstract class PipContentOverlay {
mSourceRectHint = new Rect(sourceRectHint);
mLeash = new SurfaceControl.Builder(new SurfaceSession())
.setCallsite(TAG)
- .setName(TAG)
+ .setName(LAYER_NAME)
.build();
}
@@ -194,7 +197,7 @@ public abstract class PipContentOverlay {
prepareAppIconOverlay(activityInfo);
mLeash = new SurfaceControl.Builder(new SurfaceSession())
.setCallsite(TAG)
- .setName(TAG)
+ .setName(LAYER_NAME)
.build();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index f11836ea5bee..e9d257139779 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -1594,7 +1594,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
// source rect hint to enter PiP use bounds animation.
if (sourceHintRect == null) {
if (SystemProperties.getBoolean(
- "persist.wm.debug.enable_pip_app_icon_overlay", false)) {
+ "persist.wm.debug.enable_pip_app_icon_overlay", true)) {
animator.setAppIconContentOverlay(
mContext, currentBounds, mTaskInfo.topActivityInfo);
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index e5c0570841f4..7234b15bf6d2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -804,7 +804,7 @@ public class PipTransition extends PipTransitionController {
// We use content overlay when there is no source rect hint to enter PiP use bounds
// animation.
if (SystemProperties.getBoolean(
- "persist.wm.debug.enable_pip_app_icon_overlay", false)) {
+ "persist.wm.debug.enable_pip_app_icon_overlay", true)) {
animator.setAppIconContentOverlay(
mContext, currentBounds, taskInfo.topActivityInfo);
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index c7ad4fdcacf0..94b9e907fa76 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -422,6 +422,11 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mStageCoordinator.goToFullscreenFromSplit();
}
+ /** Move the specified task to fullscreen, regardless of focus state. */
+ public void moveTaskToFullscreen(int taskId) {
+ mStageCoordinator.moveTaskToFullscreen(taskId);
+ }
+
public boolean isLaunchToSplit(TaskInfo taskInfo) {
return mStageCoordinator.isLaunchToSplit(taskInfo);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 746bfad56ea8..c0e48105ffbe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -204,7 +204,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// and exit, since exit itself can trigger a number of changes that update the stages.
private boolean mShouldUpdateRecents;
private boolean mExitSplitScreenOnHide;
- private boolean mIsSplitEntering;
+ private boolean mIsDividerRemoteAnimating;
private boolean mIsDropEntering;
private boolean mIsExiting;
@@ -764,17 +764,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (options1 == null) options1 = new Bundle();
if (pendingIntent2 == null) {
- // Launching a solo task.
- ActivityOptions activityOptions = ActivityOptions.fromBundle(options1);
- activityOptions.update(ActivityOptions.makeRemoteAnimation(adapter));
- options1 = activityOptions.toBundle();
- addActivityOptions(options1, null /* launchTarget */);
- if (shortcutInfo1 != null) {
- wct.startShortcut(mContext.getPackageName(), shortcutInfo1, options1);
- } else {
- wct.sendPendingIntent(pendingIntent1, fillInIntent1, options1);
- }
- mSyncQueue.queue(wct);
+ // Launching a solo intent or shortcut as fullscreen.
+ launchAsFullscreenWithRemoteAnimation(pendingIntent1, fillInIntent1, shortcutInfo1,
+ options1, adapter, wct);
return;
}
@@ -797,13 +789,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (options1 == null) options1 = new Bundle();
if (taskId == INVALID_TASK_ID) {
- // Launching a solo task.
- ActivityOptions activityOptions = ActivityOptions.fromBundle(options1);
- activityOptions.update(ActivityOptions.makeRemoteAnimation(adapter));
- options1 = activityOptions.toBundle();
- addActivityOptions(options1, null /* launchTarget */);
- wct.sendPendingIntent(pendingIntent, fillInIntent, options1);
- mSyncQueue.queue(wct);
+ // Launching a solo intent as fullscreen.
+ launchAsFullscreenWithRemoteAnimation(pendingIntent, fillInIntent, null, options1,
+ adapter, wct);
return;
}
@@ -822,13 +810,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (options1 == null) options1 = new Bundle();
if (taskId == INVALID_TASK_ID) {
- // Launching a solo task.
- ActivityOptions activityOptions = ActivityOptions.fromBundle(options1);
- activityOptions.update(ActivityOptions.makeRemoteAnimation(adapter));
- options1 = activityOptions.toBundle();
- addActivityOptions(options1, null /* launchTarget */);
- wct.startShortcut(mContext.getPackageName(), shortcutInfo, options1);
- mSyncQueue.queue(wct);
+ // Launching a solo shortcut as fullscreen.
+ launchAsFullscreenWithRemoteAnimation(null, null, shortcutInfo, options1, adapter, wct);
return;
}
@@ -838,6 +821,49 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
instanceId);
}
+ private void launchAsFullscreenWithRemoteAnimation(@Nullable PendingIntent pendingIntent,
+ @Nullable Intent fillInIntent, @Nullable ShortcutInfo shortcutInfo,
+ @Nullable Bundle options, RemoteAnimationAdapter adapter,
+ WindowContainerTransaction wct) {
+ LegacyTransitions.ILegacyTransition transition =
+ (transit, apps, wallpapers, nonApps, finishedCallback, t) -> {
+ if (apps == null || apps.length == 0) {
+ onRemoteAnimationFinished(apps);
+ t.apply();
+ try {
+ adapter.getRunner().onAnimationCancelled(mKeyguardShowing);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error starting remote animation", e);
+ }
+ return;
+ }
+
+ for (int i = 0; i < apps.length; ++i) {
+ if (apps[i].mode == MODE_OPENING) {
+ t.show(apps[i].leash);
+ }
+ }
+ t.apply();
+
+ try {
+ adapter.getRunner().onAnimationStart(
+ transit, apps, wallpapers, nonApps, finishedCallback);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error starting remote animation", e);
+ }
+ };
+
+ addActivityOptions(options, null /* launchTarget */);
+ if (shortcutInfo != null) {
+ wct.startShortcut(mContext.getPackageName(), shortcutInfo, options);
+ } else if (pendingIntent != null) {
+ wct.sendPendingIntent(pendingIntent, fillInIntent, options);
+ } else {
+ Slog.e(TAG, "Pending intent and shortcut are null is invalid case.");
+ }
+ mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
+ }
+
private void startWithLegacyTransition(WindowContainerTransaction wct,
@Nullable PendingIntent mainPendingIntent, @Nullable Intent mainFillInIntent,
@Nullable ShortcutInfo mainShortcutInfo, @Nullable Bundle mainOptions,
@@ -881,7 +907,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Set false to avoid record new bounds with old task still on top;
mShouldUpdateRecents = false;
- mIsSplitEntering = true;
+ mIsDividerRemoteAnimating = true;
if (mSplitRequest == null) {
mSplitRequest = new SplitRequest(mainTaskId,
mainPendingIntent != null ? mainPendingIntent.getIntent() : null,
@@ -894,23 +920,25 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (options == null) options = new Bundle();
addActivityOptions(options, mMainStage);
- options = wrapAsSplitRemoteAnimation(adapter, options);
updateWindowBounds(mSplitLayout, wct);
+ wct.reorder(mRootTaskInfo.token, true);
+ wct.setForceTranslucent(mRootTaskInfo.token, false);
// TODO(b/268008375): Merge APIs to start a split pair into one.
if (mainTaskId != INVALID_TASK_ID) {
+ options = wrapAsSplitRemoteAnimation(adapter, options);
wct.startTask(mainTaskId, options);
- } else if (mainShortcutInfo != null) {
- wct.startShortcut(mContext.getPackageName(), mainShortcutInfo, options);
+ mSyncQueue.queue(wct);
} else {
- wct.sendPendingIntent(mainPendingIntent, mainFillInIntent, options);
+ if (mainShortcutInfo != null) {
+ wct.startShortcut(mContext.getPackageName(), mainShortcutInfo, options);
+ } else {
+ wct.sendPendingIntent(mainPendingIntent, mainFillInIntent, options);
+ }
+ mSyncQueue.queue(wrapAsSplitRemoteAnimation(adapter), WindowManager.TRANSIT_OPEN, wct);
}
- wct.reorder(mRootTaskInfo.token, true);
- wct.setForceTranslucent(mRootTaskInfo.token, false);
-
- mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
setDividerVisibility(true, t);
});
@@ -936,7 +964,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
new IRemoteAnimationFinishedCallback.Stub() {
@Override
public void onAnimationFinished() throws RemoteException {
- onRemoteAnimationFinishedOrCancelled(false /* cancel */, evictWct);
+ onRemoteAnimationFinishedOrCancelled(evictWct);
finishedCallback.onAnimationFinished();
}
};
@@ -952,7 +980,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Override
public void onAnimationCancelled(boolean isKeyguardOccluded) {
- onRemoteAnimationFinishedOrCancelled(true /* cancel */, evictWct);
+ onRemoteAnimationFinishedOrCancelled(evictWct);
try {
adapter.getRunner().onAnimationCancelled(isKeyguardOccluded);
} catch (RemoteException e) {
@@ -967,21 +995,68 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return activityOptions.toBundle();
}
+ private LegacyTransitions.ILegacyTransition wrapAsSplitRemoteAnimation(
+ RemoteAnimationAdapter adapter) {
+ LegacyTransitions.ILegacyTransition transition =
+ (transit, apps, wallpapers, nonApps, finishedCallback, t) -> {
+ if (apps == null || apps.length == 0) {
+ onRemoteAnimationFinished(apps);
+ t.apply();
+ try {
+ adapter.getRunner().onAnimationCancelled(mKeyguardShowing);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error starting remote animation", e);
+ }
+ return;
+ }
+
+ // Wrap the divider bar into non-apps target to animate together.
+ nonApps = ArrayUtils.appendElement(RemoteAnimationTarget.class, nonApps,
+ getDividerBarLegacyTarget());
+
+ for (int i = 0; i < apps.length; ++i) {
+ if (apps[i].mode == MODE_OPENING) {
+ t.show(apps[i].leash);
+ // Reset the surface position of the opening app to prevent offset.
+ t.setPosition(apps[i].leash, 0, 0);
+ }
+ }
+ t.apply();
+
+ IRemoteAnimationFinishedCallback wrapCallback =
+ new IRemoteAnimationFinishedCallback.Stub() {
+ @Override
+ public void onAnimationFinished() throws RemoteException {
+ onRemoteAnimationFinished(apps);
+ finishedCallback.onAnimationFinished();
+ }
+ };
+ Transitions.setRunningRemoteTransitionDelegate(adapter.getCallingApplication());
+ try {
+ adapter.getRunner().onAnimationStart(
+ transit, apps, wallpapers, nonApps, wrapCallback);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error starting remote animation", e);
+ }
+ };
+
+ return transition;
+ }
+
private void setEnterInstanceId(InstanceId instanceId) {
if (instanceId != null) {
mLogger.enterRequested(instanceId, ENTER_REASON_LAUNCHER);
}
}
- private void onRemoteAnimationFinishedOrCancelled(boolean cancel,
- WindowContainerTransaction evictWct) {
- mIsSplitEntering = false;
+ private void onRemoteAnimationFinishedOrCancelled(WindowContainerTransaction evictWct) {
+ mIsDividerRemoteAnimating = false;
mShouldUpdateRecents = true;
mSplitRequest = null;
// If any stage has no child after animation finished, it means that split will display
// nothing, such status will happen if task and intent is same app but not support
// multi-instance, we should exit split and expand that app as full screen.
- if (!cancel && (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0)) {
+ if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
mMainExecutor.execute(() ->
exitSplitScreen(mMainStage.getChildCount() == 0
? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
@@ -994,6 +1069,27 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
+ private void onRemoteAnimationFinished(RemoteAnimationTarget[] apps) {
+ mIsDividerRemoteAnimating = false;
+ mShouldUpdateRecents = true;
+ mSplitRequest = null;
+ // If any stage has no child after finished animation, that side of the split will display
+ // nothing. This might happen if starting the same app on the both sides while not
+ // supporting multi-instance. Exit the split screen and expand that app to full screen.
+ if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
+ mMainExecutor.execute(() -> exitSplitScreen(mMainStage.getChildCount() == 0
+ ? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
+ mSplitUnsupportedToast.show();
+ return;
+ }
+
+ final WindowContainerTransaction evictWct = new WindowContainerTransaction();
+ prepareEvictNonOpeningChildTasks(SPLIT_POSITION_TOP_OR_LEFT, apps, evictWct);
+ prepareEvictNonOpeningChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, apps, evictWct);
+ mSyncQueue.queue(evictWct);
+ }
+
+
/**
* Collects all the current child tasks of a specific split and prepares transaction to evict
* them to display.
@@ -1236,12 +1332,12 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Notify recents if we are exiting in a way that breaks the pair, and disable further
// updates to splits in the recents until we enter split again
if (shouldBreakPairedTaskInRecents(exitReason) && mShouldUpdateRecents) {
- recentTasks.removeSplitPair(mMainStage.getLastVisibleTaskId());
- recentTasks.removeSplitPair(mSideStage.getLastVisibleTaskId());
+ recentTasks.removeSplitPair(mMainStage.getTopVisibleChildTaskId());
+ recentTasks.removeSplitPair(mSideStage.getTopVisibleChildTaskId());
}
});
mShouldUpdateRecents = false;
- mIsSplitEntering = false;
+ mIsDividerRemoteAnimating = false;
mSplitLayout.getInvisibleBounds(mTempRect1);
if (childrenToTop == null || childrenToTop.getTopVisibleChildTaskId() == INVALID_TASK_ID) {
@@ -1574,7 +1670,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
&& !ENABLE_SHELL_TRANSITIONS) {
// Clear the divider remote animating flag as the divider will be re-rendered to apply
// the new rotation config.
- mIsSplitEntering = false;
+ mIsDividerRemoteAnimating = false;
mSplitLayout.update(null /* t */);
onLayoutSizeChanged(mSplitLayout);
}
@@ -1624,9 +1720,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
void onChildTaskAppeared(StageListenerImpl stageListener, int taskId) {
+ // Handle entering split screen while there is a split pair running in the background.
if (stageListener == mSideStageListener && !isSplitScreenVisible() && isSplitActive()
- && !mIsSplitEntering) {
- // Handle entring split case here if split already running background.
+ && mSplitRequest == null) {
if (mIsDropEntering) {
mSplitLayout.resetDividerPosition();
} else {
@@ -1718,7 +1814,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mDividerVisible = visible;
sendSplitVisibilityChanged();
- if (mIsSplitEntering) {
+ if (mIsDividerRemoteAnimating) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
" Skip animating divider bar due to it's remote animating.");
return;
@@ -1738,7 +1834,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
" Skip animating divider bar due to divider leash not ready.");
return;
}
- if (mIsSplitEntering) {
+ if (mIsDividerRemoteAnimating) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
" Skip animating divider bar due to it's remote animating.");
return;
@@ -1806,7 +1902,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitLayout.flingDividerToDismiss(
mSideStagePosition != SPLIT_POSITION_BOTTOM_OR_RIGHT,
EXIT_REASON_APP_FINISHED);
- } else if (!isSplitScreenVisible() && !mIsSplitEntering) {
+ } else if (!isSplitScreenVisible() && mSplitRequest == null) {
+ // Dismiss split screen in the background once any sides of the split become empty.
exitSplitScreen(null /* childrenToTop */, EXIT_REASON_APP_FINISHED);
}
} else if (isSideStage && hasChildren && !mMainStage.isActive()) {
@@ -2391,6 +2488,20 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitLayout.flingDividerToDismiss(!leftOrTop, EXIT_REASON_FULLSCREEN_SHORTCUT);
}
+ /** Move the specified task to fullscreen, regardless of focus state. */
+ public void moveTaskToFullscreen(int taskId) {
+ boolean leftOrTop;
+ if (mMainStage.containsTask(taskId)) {
+ leftOrTop = (mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
+ } else if (mSideStage.containsTask(taskId)) {
+ leftOrTop = (mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT);
+ } else {
+ return;
+ }
+ mSplitLayout.flingDividerToDismiss(!leftOrTop, EXIT_REASON_FULLSCREEN_SHORTCUT);
+
+ }
+
boolean isLaunchToSplit(TaskInfo taskInfo) {
return getActivateSplitPosition(taskInfo) != SPLIT_POSITION_UNDEFINED;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 0359761388dc..a841b7f96d3c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -92,7 +92,6 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
protected SurfaceControl mDimLayer;
protected SparseArray<ActivityManager.RunningTaskInfo> mChildrenTaskInfo = new SparseArray<>();
private final SparseArray<SurfaceControl> mChildrenLeashes = new SparseArray<>();
- private int mLastVisibleTaskId = INVALID_TASK_ID;
// TODO(b/204308910): Extracts SplitDecorManager related code to common package.
private SplitDecorManager mSplitDecorManager;
@@ -124,13 +123,6 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
}
/**
- * Returns the last visible task's id.
- */
- int getLastVisibleTaskId() {
- return mLastVisibleTaskId;
- }
-
- /**
* Returns the top visible child task's id.
*/
int getTopVisibleChildTaskId() {
@@ -229,9 +221,6 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
return;
}
mChildrenTaskInfo.put(taskInfo.taskId, taskInfo);
- if (taskInfo.isVisible && taskInfo.taskId != mLastVisibleTaskId) {
- mLastVisibleTaskId = taskInfo.taskId;
- }
mCallbacks.onChildTaskStatusChanged(taskInfo.taskId, true /* present */,
taskInfo.isVisible);
if (!ENABLE_SHELL_TRANSITIONS) {
@@ -264,9 +253,6 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
} else if (mChildrenTaskInfo.contains(taskId)) {
mChildrenTaskInfo.remove(taskId);
mChildrenLeashes.remove(taskId);
- if (taskId == mLastVisibleTaskId) {
- mLastVisibleTaskId = INVALID_TASK_ID;
- }
mCallbacks.onChildTaskStatusChanged(taskId, false /* present */, taskInfo.isVisible);
if (ENABLE_SHELL_TRANSITIONS) {
// Status is managed/synchronized by the transition lifecycle.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 2981f5e160f6..9224b3cbd798 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -174,7 +174,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
final TaskPositioner taskPositioner =
- new TaskPositioner(mTaskOrganizer, windowDecoration);
+ new TaskPositioner(mTaskOrganizer, windowDecoration, mDisplayController);
final CaptionTouchEventListener touchEventListener =
new CaptionTouchEventListener(taskInfo, taskPositioner);
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index de5f2f467e99..c517f7be330b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -20,10 +20,14 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.content.Context;
+import android.graphics.Rect;
import android.hardware.input.InputManager;
import android.os.Handler;
import android.os.Looper;
@@ -37,7 +41,6 @@ import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.View;
import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
import androidx.annotation.Nullable;
@@ -50,6 +53,7 @@ import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.desktopmode.DesktopModeStatus;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import java.util.Optional;
@@ -80,6 +84,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
private final InputMonitorFactory mInputMonitorFactory;
private TaskOperations mTaskOperations;
+ private Optional<SplitScreenController> mSplitScreenController;
+
public DesktopModeWindowDecorViewModel(
Context context,
Handler mainHandler,
@@ -88,7 +94,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
DisplayController displayController,
SyncTransactionQueue syncQueue,
Optional<DesktopModeController> desktopModeController,
- Optional<DesktopTasksController> desktopTasksController) {
+ Optional<DesktopTasksController> desktopTasksController,
+ Optional<SplitScreenController> splitScreenController) {
this(
context,
mainHandler,
@@ -98,6 +105,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
syncQueue,
desktopModeController,
desktopTasksController,
+ splitScreenController,
new DesktopModeWindowDecoration.Factory(),
new InputMonitorFactory());
}
@@ -112,6 +120,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
SyncTransactionQueue syncQueue,
Optional<DesktopModeController> desktopModeController,
Optional<DesktopTasksController> desktopTasksController,
+ Optional<SplitScreenController> splitScreenController,
DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory,
InputMonitorFactory inputMonitorFactory) {
mContext = context;
@@ -120,6 +129,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mActivityTaskManager = mContext.getSystemService(ActivityTaskManager.class);
mTaskOrganizer = taskOrganizer;
mDisplayController = displayController;
+ mSplitScreenController = splitScreenController;
mSyncQueue = syncQueue;
mDesktopModeController = desktopModeController;
mDesktopTasksController = desktopTasksController;
@@ -230,6 +240,15 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
final int id = v.getId();
if (id == R.id.close_window || id == R.id.close_button) {
mTaskOperations.closeTask(mTaskToken);
+ if (mSplitScreenController.isPresent()
+ && mSplitScreenController.get().isSplitScreenVisible()) {
+ int remainingTaskPosition = mTaskId == mSplitScreenController.get()
+ .getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT).taskId
+ ? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT;
+ ActivityManager.RunningTaskInfo remainingTask = mSplitScreenController.get()
+ .getTaskInfo(remainingTaskPosition);
+ mSplitScreenController.get().moveTaskToFullscreen(remainingTask.taskId);
+ }
} else if (id == R.id.back_button) {
mTaskOperations.injectBackKey();
} else if (id == R.id.caption_handle) {
@@ -261,9 +280,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
if (taskInfo.isFocused) {
return mDragDetector.isDragEvent();
}
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.reorder(mTaskToken, true /* onTop */);
- mSyncQueue.queue(wct);
return false;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
@@ -401,14 +417,14 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
* @param ev the {@link MotionEvent} received by {@link EventReceiver}
*/
private void handleReceivedMotionEvent(MotionEvent ev, InputMonitor inputMonitor) {
+ final DesktopModeWindowDecoration relevantDecor = getRelevantWindowDecor(ev);
if (DesktopModeStatus.isProto2Enabled()) {
- final DesktopModeWindowDecoration focusedDecor = getFocusedDecor();
- if (focusedDecor == null
- || focusedDecor.mTaskInfo.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
- handleCaptionThroughStatusBar(ev);
+ if (relevantDecor == null
+ || relevantDecor.mTaskInfo.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
+ handleCaptionThroughStatusBar(ev, relevantDecor);
}
}
- handleEventOutsideFocusedCaption(ev);
+ handleEventOutsideFocusedCaption(ev, relevantDecor);
// Prevent status bar from reacting to a caption drag.
if (DesktopModeStatus.isProto2Enabled()) {
if (mTransitionDragActive) {
@@ -422,16 +438,16 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
}
// If an UP/CANCEL action is received outside of caption bounds, turn off handle menu
- private void handleEventOutsideFocusedCaption(MotionEvent ev) {
+ private void handleEventOutsideFocusedCaption(MotionEvent ev,
+ DesktopModeWindowDecoration relevantDecor) {
final int action = ev.getActionMasked();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
- final DesktopModeWindowDecoration focusedDecor = getFocusedDecor();
- if (focusedDecor == null) {
+ if (relevantDecor == null) {
return;
}
if (!mTransitionDragActive) {
- focusedDecor.closeHandleMenuIfNeeded(ev);
+ relevantDecor.closeHandleMenuIfNeeded(ev);
}
}
}
@@ -441,39 +457,38 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
* Perform caption actions if not able to through normal means.
* Turn on desktop mode if handle is dragged below status bar.
*/
- private void handleCaptionThroughStatusBar(MotionEvent ev) {
+ private void handleCaptionThroughStatusBar(MotionEvent ev,
+ DesktopModeWindowDecoration relevantDecor) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
// Begin drag through status bar if applicable.
- final DesktopModeWindowDecoration focusedDecor = getFocusedDecor();
- if (focusedDecor != null) {
+ if (relevantDecor != null) {
boolean dragFromStatusBarAllowed = false;
if (DesktopModeStatus.isProto2Enabled()) {
// In proto2 any full screen task can be dragged to freeform
- dragFromStatusBarAllowed = focusedDecor.mTaskInfo.getWindowingMode()
+ dragFromStatusBarAllowed = relevantDecor.mTaskInfo.getWindowingMode()
== WINDOWING_MODE_FULLSCREEN;
}
- if (dragFromStatusBarAllowed && focusedDecor.checkTouchEventInHandle(ev)) {
+ if (dragFromStatusBarAllowed && relevantDecor.checkTouchEventInHandle(ev)) {
mTransitionDragActive = true;
}
}
break;
}
case MotionEvent.ACTION_UP: {
- final DesktopModeWindowDecoration focusedDecor = getFocusedDecor();
- if (focusedDecor == null) {
+ if (relevantDecor == null) {
mTransitionDragActive = false;
return;
}
if (mTransitionDragActive) {
mTransitionDragActive = false;
final int statusBarHeight = mDisplayController
- .getDisplayLayout(focusedDecor.mTaskInfo.displayId).stableInsets().top;
+ .getDisplayLayout(relevantDecor.mTaskInfo.displayId).stableInsets().top;
if (ev.getY() > statusBarHeight) {
if (DesktopModeStatus.isProto2Enabled()) {
mDesktopTasksController.ifPresent(
- c -> c.moveToDesktop(focusedDecor.mTaskInfo));
+ c -> c.moveToDesktop(relevantDecor.mTaskInfo));
} else if (DesktopModeStatus.isProto1Enabled()) {
mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true));
}
@@ -481,7 +496,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
return;
}
}
- focusedDecor.checkClickEvent(ev);
+ relevantDecor.checkClickEvent(ev);
break;
}
case MotionEvent.ACTION_CANCEL: {
@@ -491,6 +506,38 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
}
@Nullable
+ private DesktopModeWindowDecoration getRelevantWindowDecor(MotionEvent ev) {
+ if (mSplitScreenController.isPresent()
+ && mSplitScreenController.get().isSplitScreenVisible()) {
+ // We can't look at focused task here as only one task will have focus.
+ return getSplitScreenDecor(ev);
+ } else {
+ return getFocusedDecor();
+ }
+ }
+
+ @Nullable
+ private DesktopModeWindowDecoration getSplitScreenDecor(MotionEvent ev) {
+ ActivityManager.RunningTaskInfo topOrLeftTask =
+ mSplitScreenController.get().getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT);
+ ActivityManager.RunningTaskInfo bottomOrRightTask =
+ mSplitScreenController.get().getTaskInfo(SPLIT_POSITION_BOTTOM_OR_RIGHT);
+ if (topOrLeftTask != null && topOrLeftTask.getConfiguration()
+ .windowConfiguration.getBounds().contains((int) ev.getX(), (int) ev.getY())) {
+ return mWindowDecorByTaskId.get(topOrLeftTask.taskId);
+ } else if (bottomOrRightTask != null && bottomOrRightTask.getConfiguration()
+ .windowConfiguration.getBounds().contains((int) ev.getX(), (int) ev.getY())) {
+ Rect bottomOrRightBounds = bottomOrRightTask.getConfiguration().windowConfiguration
+ .getBounds();
+ ev.offsetLocation(-bottomOrRightBounds.left, -bottomOrRightBounds.top);
+ return mWindowDecorByTaskId.get(bottomOrRightTask.taskId);
+ } else {
+ return null;
+ }
+
+ }
+
+ @Nullable
private DesktopModeWindowDecoration getFocusedDecor() {
final int size = mWindowDecorByTaskId.size();
DesktopModeWindowDecoration focusedDecor = null;
@@ -558,7 +605,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
final TaskPositioner taskPositioner =
- new TaskPositioner(mTaskOrganizer, windowDecoration, mDragStartListener);
+ new TaskPositioner(mTaskOrganizer, windowDecoration, mDisplayController,
+ mDragStartListener);
final DesktopModeTouchEventListener touchEventListener =
new DesktopModeTouchEventListener(taskInfo, taskPositioner);
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 0779f1d72551..72da1089c91c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -74,6 +74,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
private boolean mDesktopActive;
private AdditionalWindow mHandleMenu;
private final int mHandleMenuWidthId = R.dimen.freeform_decor_caption_menu_width;
+ private final int mHandleMenuShadowRadiusId = R.dimen.caption_menu_shadow_radius;
+ private final int mHandleMenuCornerRadiusId = R.dimen.caption_menu_corner_radius;
private PointF mHandleMenuPosition = new PointF();
DesktopModeWindowDecoration(
@@ -353,19 +355,16 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
.windowConfiguration.getBounds().width();
final int menuWidth = loadDimensionPixelSize(resources, mHandleMenuWidthId);
final int menuHeight = loadDimensionPixelSize(resources, mCaptionMenuHeightId);
-
- // Elevation gives the appearance of a changed x/y coordinate; this is to fix that
- int elevationOffset = 2 * loadDimensionPixelSize(resources,
- R.dimen.caption_menu_elevation);
+ final int shadowRadius = loadDimensionPixelSize(resources, mHandleMenuShadowRadiusId);
+ final int cornerRadius = loadDimensionPixelSize(resources, mHandleMenuCornerRadiusId);
final int x = mRelayoutParams.mCaptionX + (captionWidth / 2) - (menuWidth / 2)
- - mResult.mDecorContainerOffsetX - elevationOffset;
- final int y =
- mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY - elevationOffset;
+ - mResult.mDecorContainerOffsetX;
+ final int y = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY;
mHandleMenuPosition.set(x, y);
String namePrefix = "Caption Menu";
mHandleMenu = addWindow(R.layout.desktop_mode_decor_handle_menu, namePrefix, t, x, y,
- menuWidth, menuHeight, 2 * elevationOffset);
+ menuWidth, menuHeight, shadowRadius, cornerRadius);
mSyncQueue.runInSync(transaction -> {
transaction.merge(t);
t.close();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
index d3f92277bf03..a3d364a0068e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
@@ -19,9 +19,11 @@ package com.android.wm.shell.windowdecor;
import android.annotation.IntDef;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.util.DisplayMetrics;
import android.window.WindowContainerTransaction;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayController;
class TaskPositioner implements DragPositioningCallback {
@@ -35,6 +37,7 @@ class TaskPositioner implements DragPositioningCallback {
static final int CTRL_TYPE_BOTTOM = 8;
private final ShellTaskOrganizer mTaskOrganizer;
+ private final DisplayController mDisplayController;
private final WindowDecoration mWindowDecoration;
private final Rect mTaskBoundsAtDragStart = new Rect();
@@ -45,14 +48,16 @@ class TaskPositioner implements DragPositioningCallback {
private int mCtrlType;
private DragStartListener mDragStartListener;
- TaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration) {
- this(taskOrganizer, windowDecoration, dragStartListener -> {});
+ TaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
+ DisplayController displayController) {
+ this(taskOrganizer, windowDecoration, displayController, dragStartListener -> {});
}
TaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
- DragStartListener dragStartListener) {
+ DisplayController displayController, DragStartListener dragStartListener) {
mTaskOrganizer = taskOrganizer;
mWindowDecoration = windowDecoration;
+ mDisplayController = displayController;
mDragStartListener = dragStartListener;
}
@@ -128,15 +133,44 @@ class TaskPositioner implements DragPositioningCallback {
mRepositionTaskBounds.offset((int) deltaX, (int) deltaY);
}
+ // If width or height are negative or less than the minimum width or height, revert the
+ // respective bounds to use previous bound dimensions.
+ if (mRepositionTaskBounds.width() < getMinWidth()) {
+ mRepositionTaskBounds.right = oldRight;
+ mRepositionTaskBounds.left = oldLeft;
+ }
+ if (mRepositionTaskBounds.height() < getMinHeight()) {
+ mRepositionTaskBounds.top = oldTop;
+ mRepositionTaskBounds.bottom = oldBottom;
+ }
+ // If there are no changes to the bounds after checking new bounds against minimum width
+ // and height, do not set bounds and return false
if (oldLeft == mRepositionTaskBounds.left && oldTop == mRepositionTaskBounds.top
&& oldRight == mRepositionTaskBounds.right
&& oldBottom == mRepositionTaskBounds.bottom) {
return false;
}
+
wct.setBounds(mWindowDecoration.mTaskInfo.token, mRepositionTaskBounds);
return true;
}
+ private float getMinWidth() {
+ return mWindowDecoration.mTaskInfo.minWidth < 0 ? getDefaultMinSize()
+ : mWindowDecoration.mTaskInfo.minWidth;
+ }
+
+ private float getMinHeight() {
+ return mWindowDecoration.mTaskInfo.minHeight < 0 ? getDefaultMinSize()
+ : mWindowDecoration.mTaskInfo.minHeight;
+ }
+
+ private float getDefaultMinSize() {
+ float density = mDisplayController.getDisplayLayout(mWindowDecoration.mTaskInfo.displayId)
+ .densityDpi() * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ return mWindowDecoration.mTaskInfo.defaultMinSize * density;
+ }
+
interface DragStartListener {
/**
* Inform the implementing class that a drag resize has started
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index ae685ad4b8d9..133826f3e69b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -391,11 +391,12 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
* @param yPos y position of new window
* @param width width of new window
* @param height height of new window
- * @param cropPadding padding to add to window crop to ensure shadows display properly
- * @return
+ * @param shadowRadius radius of the shadow of the new window
+ * @param cornerRadius radius of the corners of the new window
+ * @return the {@link AdditionalWindow} that was added.
*/
AdditionalWindow addWindow(int layoutId, String namePrefix, SurfaceControl.Transaction t,
- int xPos, int yPos, int width, int height, int cropPadding) {
+ int xPos, int yPos, int width, int height, int shadowRadius, int cornerRadius) {
final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
SurfaceControl windowSurfaceControl = builder
.setName(namePrefix + " of Task=" + mTaskInfo.taskId)
@@ -404,9 +405,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
.build();
View v = LayoutInflater.from(mDecorWindowContext).inflate(layoutId, null);
- t.setPosition(
- windowSurfaceControl, xPos, yPos)
- .setWindowCrop(windowSurfaceControl, width + cropPadding, height + cropPadding)
+ t.setPosition(windowSurfaceControl, xPos, yPos)
+ .setWindowCrop(windowSurfaceControl, width, height)
+ .setShadowRadius(windowSurfaceControl, shadowRadius)
+ .setCornerRadius(windowSurfaceControl, cornerRadius)
.show(windowSurfaceControl);
final WindowManager.LayoutParams lp =
new WindowManager.LayoutParams(width, height,
diff --git a/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
index fac04614d945..47a116be1b66 100644
--- a/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
@@ -20,6 +20,7 @@
package="com.android.wm.shell.tests">
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+ <uses-permission android:name="android.permission.VIBRATE"/>
<application android:debuggable="true" android:largeHeap="true">
<uses-library android:name="android.test.mock" />
diff --git a/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml b/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml
index 27d40b2b25b2..aa1b24189274 100644
--- a/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml
@@ -24,4 +24,6 @@
<dimen name="test_window_decor_bottom_outset">40dp</dimen>
<dimen name="test_window_decor_shadow_radius">5dp</dimen>
<dimen name="test_window_decor_resize_handle">10dp</dimen>
+ <dimen name="test_caption_menu_shadow_radius">4dp</dimen>
+ <dimen name="test_caption_menu_corner_radius">20dp</dimen>
</resources> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index 875e6105b7bc..98de58404e80 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -474,6 +474,36 @@ public class CompatUIControllerTest extends ShellTestCase {
verify(mMockRestartDialogLayout).updateVisibility(true);
}
+ @Test
+ public void testRestartLayoutRecreatedIfNeeded() {
+ final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID,
+ /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN);
+ doReturn(true).when(mMockRestartDialogLayout)
+ .needsToBeRecreated(any(TaskInfo.class),
+ any(ShellTaskOrganizer.TaskListener.class));
+
+ mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
+ mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
+
+ verify(mMockRestartDialogLayout, times(2))
+ .createLayout(anyBoolean());
+ }
+
+ @Test
+ public void testRestartLayoutNotRecreatedIfNotNeeded() {
+ final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID,
+ /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN);
+ doReturn(false).when(mMockRestartDialogLayout)
+ .needsToBeRecreated(any(TaskInfo.class),
+ any(ShellTaskOrganizer.TaskListener.class));
+
+ mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
+ mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
+
+ verify(mMockRestartDialogLayout, times(1))
+ .createLayout(anyBoolean());
+ }
+
private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat,
@CameraCompatControlState int cameraCompatControlState) {
RunningTaskInfo taskInfo = new RunningTaskInfo();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
index b6dbcf204364..523cb6629d9a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
@@ -48,7 +48,6 @@ import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
@@ -82,7 +81,7 @@ public class DragAndDropControllerTest extends ShellTestCase {
@Mock
private ShellExecutor mMainExecutor;
@Mock
- private SplitScreenController mSplitScreenController;
+ private WindowManager mWindowManager;
private DragAndDropController mController;
@@ -100,11 +99,6 @@ public class DragAndDropControllerTest extends ShellTestCase {
}
@Test
- public void instantiateController_registerConfigChangeListener() {
- verify(mShellController, times(1)).addConfigurationChangeListener(any());
- }
-
- @Test
public void testIgnoreNonDefaultDisplays() {
final int nonDefaultDisplayId = 12345;
final View dragLayout = mock(View.class);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
index 355072116cb1..1d1aa795173c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
@@ -49,6 +49,7 @@ import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.desktopmode.DesktopTasksController;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import org.junit.Before;
import org.junit.Test;
@@ -73,6 +74,7 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {
@Mock private Choreographer mMainChoreographer;
@Mock private ShellTaskOrganizer mTaskOrganizer;
@Mock private DisplayController mDisplayController;
+ @Mock private SplitScreenController mSplitScreenController;
@Mock private SyncTransactionQueue mSyncQueue;
@Mock private DesktopModeController mDesktopModeController;
@Mock private DesktopTasksController mDesktopTasksController;
@@ -98,6 +100,7 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {
mSyncQueue,
Optional.of(mDesktopModeController),
Optional.of(mDesktopTasksController),
+ Optional.of(mSplitScreenController),
mDesktopModeWindowDecorFactory,
mMockInputMonitorFactory
);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt
index f185a8a80719..8f66f4e7e47b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt
@@ -8,6 +8,8 @@ import android.testing.AndroidTestingRunner
import android.window.WindowContainerToken
import android.window.WindowContainerTransaction.Change.CHANGE_DRAG_RESIZING
import androidx.test.filters.SmallTest
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.windowdecor.TaskPositioner.CTRL_TYPE_RIGHT
@@ -45,6 +47,11 @@ class TaskPositionerTest : ShellTestCase() {
@Mock
private lateinit var taskBinder: IBinder
+ @Mock
+ private lateinit var mockDisplayController: DisplayController
+ @Mock
+ private lateinit var mockDisplayLayout: DisplayLayout
+
private lateinit var taskPositioner: TaskPositioner
@Before
@@ -54,12 +61,21 @@ class TaskPositionerTest : ShellTestCase() {
taskPositioner = TaskPositioner(
mockShellTaskOrganizer,
mockWindowDecoration,
+ mockDisplayController,
mockDragStartListener
)
+
`when`(taskToken.asBinder()).thenReturn(taskBinder)
+ `when`(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
+ `when`(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
+
mockWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
taskId = TASK_ID
token = taskToken
+ minWidth = MIN_WIDTH
+ minHeight = MIN_HEIGHT
+ defaultMinSize = DEFAULT_MIN
+ displayId = DISPLAY_ID
configuration.windowConfiguration.bounds = STARTING_BOUNDS
}
}
@@ -209,8 +225,239 @@ class TaskPositionerTest : ShellTestCase() {
})
}
+ @Test
+ fun testDragResize_resize_setBoundsDoesNotChangeHeightWhenLessThanMin() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Resize to width of 95px and height of 5px with min width of 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 5
+ val newY = STARTING_BOUNDS.top.toFloat() + 95
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
+ != 0) && change.configuration.windowConfiguration.bounds.top ==
+ STARTING_BOUNDS.top &&
+ change.configuration.windowConfiguration.bounds.bottom ==
+ STARTING_BOUNDS.bottom
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_setBoundsDoesNotChangeWidthWhenLessThanMin() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Resize to height of 95px and width of 5px with min width of 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 95
+ val newY = STARTING_BOUNDS.top.toFloat() + 5
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
+ != 0) && change.configuration.windowConfiguration.bounds.right ==
+ STARTING_BOUNDS.right &&
+ change.configuration.windowConfiguration.bounds.left ==
+ STARTING_BOUNDS.left
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_setBoundsDoesNotChangeHeightWhenNegative() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Resize to height of -5px and width of 95px
+ val newX = STARTING_BOUNDS.right.toFloat() - 5
+ val newY = STARTING_BOUNDS.top.toFloat() + 105
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
+ != 0) && change.configuration.windowConfiguration.bounds.top ==
+ STARTING_BOUNDS.top &&
+ change.configuration.windowConfiguration.bounds.bottom ==
+ STARTING_BOUNDS.bottom
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_setBoundsDoesNotChangeWidthWhenNegative() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Resize to width of -5px and height of 95px
+ val newX = STARTING_BOUNDS.right.toFloat() - 105
+ val newY = STARTING_BOUNDS.top.toFloat() + 5
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
+ != 0) && change.configuration.windowConfiguration.bounds.right ==
+ STARTING_BOUNDS.right &&
+ change.configuration.windowConfiguration.bounds.left ==
+ STARTING_BOUNDS.left
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_setBoundsRunsWhenResizeBoundsValid() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Shrink to height 20px and width 20px with both min height/width equal to 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 80
+ val newY = STARTING_BOUNDS.top.toFloat() + 80
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_setBoundsDoesNotRunWithNegativeHeightAndWidth() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Shrink to height 5px and width 5px with both min height/width equal to 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 95
+ val newY = STARTING_BOUNDS.top.toFloat() + 95
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_useDefaultMinWhenMinWidthInvalid() {
+ mockWindowDecoration.mTaskInfo.minWidth = -1
+
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Shrink to width and height of 3px with invalid minWidth = -1 and defaultMinSize = 5px
+ val newX = STARTING_BOUNDS.right.toFloat() - 97
+ val newY = STARTING_BOUNDS.top.toFloat() + 97
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_useMinWidthWhenValid() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Shrink to width and height of 7px with valid minWidth = 10px and defaultMinSize = 5px
+ val newX = STARTING_BOUNDS.right.toFloat() - 93
+ val newY = STARTING_BOUNDS.top.toFloat() + 93
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
+ }
+ })
+ }
+
companion object {
private const val TASK_ID = 5
+ private const val MIN_WIDTH = 10
+ private const val MIN_HEIGHT = 10
+ private const val DENSITY_DPI = 20
+ private const val DEFAULT_MIN = 40
+ private const val DISPLAY_ID = 1
private val STARTING_BOUNDS = Rect(0, 0, 100, 100)
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index b80edcece512..7e39b5b8f2ce 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -108,6 +108,8 @@ public class WindowDecorationTests extends ShellTestCase {
private SurfaceControl.Transaction mMockSurfaceControlAddWindowT;
private WindowDecoration.RelayoutParams mRelayoutParams = new WindowDecoration.RelayoutParams();
private int mCaptionMenuWidthId;
+ private int mCaptionMenuShadowRadiusId;
+ private int mCaptionMenuCornerRadiusId;
@Before
public void setUp() {
@@ -118,6 +120,8 @@ public class WindowDecorationTests extends ShellTestCase {
mRelayoutParams.mLayoutResId = 0;
mRelayoutParams.mCaptionHeightId = R.dimen.test_freeform_decor_caption_height;
mCaptionMenuWidthId = R.dimen.test_freeform_decor_caption_menu_width;
+ mCaptionMenuShadowRadiusId = R.dimen.test_caption_menu_shadow_radius;
+ mCaptionMenuCornerRadiusId = R.dimen.test_caption_menu_corner_radius;
mRelayoutParams.mShadowRadiusId = R.dimen.test_window_decor_shadow_radius;
doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory)
@@ -431,7 +435,19 @@ public class WindowDecorationTests extends ShellTestCase {
verify(additionalWindowSurfaceBuilder).setParent(decorContainerSurface);
verify(additionalWindowSurfaceBuilder).build();
verify(mMockSurfaceControlAddWindowT).setPosition(additionalWindowSurface, 20, 40);
- verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, 442, 74);
+ final int width = WindowDecoration.loadDimensionPixelSize(
+ mContext.getResources(), mCaptionMenuWidthId);
+ final int height = WindowDecoration.loadDimensionPixelSize(
+ mContext.getResources(), mRelayoutParams.mCaptionHeightId);
+ verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, width, height);
+ final int shadowRadius = WindowDecoration.loadDimensionPixelSize(mContext.getResources(),
+ mCaptionMenuShadowRadiusId);
+ verify(mMockSurfaceControlAddWindowT)
+ .setShadowRadius(additionalWindowSurface, shadowRadius);
+ final int cornerRadius = WindowDecoration.loadDimensionPixelSize(mContext.getResources(),
+ mCaptionMenuCornerRadiusId);
+ verify(mMockSurfaceControlAddWindowT)
+ .setCornerRadius(additionalWindowSurface, cornerRadius);
verify(mMockSurfaceControlAddWindowT).show(additionalWindowSurface);
verify(mMockSurfaceControlViewHostFactory, Mockito.times(2))
.create(any(), eq(defaultDisplay), any());
@@ -559,13 +575,15 @@ public class WindowDecorationTests extends ShellTestCase {
int y = mRelayoutParams.mCaptionY;
int width = loadDimensionPixelSize(resources, mCaptionMenuWidthId);
int height = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionHeightId);
+ int shadowRadius = loadDimensionPixelSize(resources, mCaptionMenuShadowRadiusId);
+ int cornerRadius = loadDimensionPixelSize(resources, mCaptionMenuCornerRadiusId);
String name = "Test Window";
WindowDecoration.AdditionalWindow additionalWindow =
addWindow(R.layout.desktop_mode_decor_handle_menu, name,
mMockSurfaceControlAddWindowT,
x - mRelayoutResult.mDecorContainerOffsetX,
y - mRelayoutResult.mDecorContainerOffsetY,
- width, height, 10);
+ width, height, shadowRadius, cornerRadius);
return additionalWindow;
}
}
diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java
index 5ecec4ddd1ad..3125f088c72b 100644
--- a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java
+++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java
@@ -72,6 +72,7 @@ public final class LowLightDreamManager {
public static final int AMBIENT_LIGHT_MODE_LOW_LIGHT = 2;
private final DreamManager mDreamManager;
+ private final LowLightTransitionCoordinator mLowLightTransitionCoordinator;
@Nullable
private final ComponentName mLowLightDreamComponent;
@@ -81,8 +82,10 @@ public final class LowLightDreamManager {
@Inject
public LowLightDreamManager(
DreamManager dreamManager,
+ LowLightTransitionCoordinator lowLightTransitionCoordinator,
@Named(LOW_LIGHT_DREAM_COMPONENT) @Nullable ComponentName lowLightDreamComponent) {
mDreamManager = dreamManager;
+ mLowLightTransitionCoordinator = lowLightTransitionCoordinator;
mLowLightDreamComponent = lowLightDreamComponent;
}
@@ -111,7 +114,9 @@ public final class LowLightDreamManager {
mAmbientLightMode = ambientLightMode;
- mDreamManager.setSystemDreamComponent(mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT
- ? mLowLightDreamComponent : null);
+ boolean shouldEnterLowLight = mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT;
+ mLowLightTransitionCoordinator.notifyBeforeLowLightTransition(shouldEnterLowLight,
+ () -> mDreamManager.setSystemDreamComponent(
+ shouldEnterLowLight ? mLowLightDreamComponent : null));
}
}
diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.java b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.java
new file mode 100644
index 000000000000..874a2d5af75e
--- /dev/null
+++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.java
@@ -0,0 +1,111 @@
+/*
+ * 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.dream.lowlight;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.annotation.Nullable;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Helper class that allows listening and running animations before entering or exiting low light.
+ */
+@Singleton
+public class LowLightTransitionCoordinator {
+ /**
+ * Listener that is notified before low light entry.
+ */
+ public interface LowLightEnterListener {
+ /**
+ * Callback that is notified before the device enters low light.
+ *
+ * @return an optional animator that will be waited upon before entering low light.
+ */
+ Animator onBeforeEnterLowLight();
+ }
+
+ /**
+ * Listener that is notified before low light exit.
+ */
+ public interface LowLightExitListener {
+ /**
+ * Callback that is notified before the device exits low light.
+ *
+ * @return an optional animator that will be waited upon before exiting low light.
+ */
+ Animator onBeforeExitLowLight();
+ }
+
+ private LowLightEnterListener mLowLightEnterListener;
+ private LowLightExitListener mLowLightExitListener;
+
+ @Inject
+ public LowLightTransitionCoordinator() {
+ }
+
+ /**
+ * Sets the listener for the low light enter event.
+ *
+ * Only one listener can be set at a time. This method will overwrite any previously set
+ * listener. Null can be used to unset the listener.
+ */
+ public void setLowLightEnterListener(@Nullable LowLightEnterListener lowLightEnterListener) {
+ mLowLightEnterListener = lowLightEnterListener;
+ }
+
+ /**
+ * Sets the listener for the low light exit event.
+ *
+ * Only one listener can be set at a time. This method will overwrite any previously set
+ * listener. Null can be used to unset the listener.
+ */
+ public void setLowLightExitListener(@Nullable LowLightExitListener lowLightExitListener) {
+ mLowLightExitListener = lowLightExitListener;
+ }
+
+ /**
+ * Notifies listeners that the device is about to enter or exit low light.
+ *
+ * @param entering true if listeners should be notified before entering low light, false if this
+ * is notifying before exiting.
+ * @param callback callback that will be run after listeners complete.
+ */
+ void notifyBeforeLowLightTransition(boolean entering, Runnable callback) {
+ Animator animator = null;
+
+ if (entering && mLowLightEnterListener != null) {
+ animator = mLowLightEnterListener.onBeforeEnterLowLight();
+ } else if (!entering && mLowLightExitListener != null) {
+ animator = mLowLightExitListener.onBeforeExitLowLight();
+ }
+
+ // If the listener returned an animator to indicate it was running an animation, run the
+ // callback after the animation completes, otherwise call the callback directly.
+ if (animator != null) {
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ callback.run();
+ }
+ });
+ } else {
+ callback.run();
+ }
+ }
+}
diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java
index 91a170f7ae14..4b95d8c84bac 100644
--- a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java
+++ b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java
@@ -21,7 +21,10 @@ import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE
import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_UNKNOWN;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+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.verify;
@@ -44,44 +47,52 @@ public class LowLightDreamManagerTest {
private DreamManager mDreamManager;
@Mock
+ private LowLightTransitionCoordinator mTransitionCoordinator;
+
+ @Mock
private ComponentName mDreamComponent;
+ LowLightDreamManager mLowLightDreamManager;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+
+ // Automatically run any provided Runnable to mTransitionCoordinator to simplify testing.
+ doAnswer(invocation -> {
+ ((Runnable) invocation.getArgument(1)).run();
+ return null;
+ }).when(mTransitionCoordinator).notifyBeforeLowLightTransition(anyBoolean(),
+ any(Runnable.class));
+
+ mLowLightDreamManager = new LowLightDreamManager(mDreamManager, mTransitionCoordinator,
+ mDreamComponent);
}
@Test
public void setAmbientLightMode_lowLight_setSystemDream() {
- final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
- mDreamComponent);
-
- lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
+ mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
+ verify(mTransitionCoordinator).notifyBeforeLowLightTransition(eq(true), any());
verify(mDreamManager).setSystemDreamComponent(mDreamComponent);
}
@Test
public void setAmbientLightMode_regularLight_clearSystemDream() {
- final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
- mDreamComponent);
-
- lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_REGULAR);
+ mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_REGULAR);
+ verify(mTransitionCoordinator).notifyBeforeLowLightTransition(eq(false), any());
verify(mDreamManager).setSystemDreamComponent(null);
}
@Test
public void setAmbientLightMode_defaultUnknownMode_clearSystemDream() {
- final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
- mDreamComponent);
-
// Set to low light first.
- lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
+ mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
clearInvocations(mDreamManager);
// Return to default unknown mode.
- lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_UNKNOWN);
+ mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_UNKNOWN);
verify(mDreamManager).setSystemDreamComponent(null);
}
@@ -89,7 +100,7 @@ public class LowLightDreamManagerTest {
@Test
public void setAmbientLightMode_dreamComponentNotSet_doNothing() {
final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
- null /*dream component*/);
+ mTransitionCoordinator, null /*dream component*/);
lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.java b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.java
new file mode 100644
index 000000000000..81e1e33d6220
--- /dev/null
+++ b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.java
@@ -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.
+ */
+
+package com.android.dream.lowlight;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.animation.Animator;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class LowLightTransitionCoordinatorTest {
+ @Mock
+ private LowLightTransitionCoordinator.LowLightEnterListener mEnterListener;
+
+ @Mock
+ private LowLightTransitionCoordinator.LowLightExitListener mExitListener;
+
+ @Mock
+ private Animator mAnimator;
+
+ @Captor
+ private ArgumentCaptor<Animator.AnimatorListener> mAnimatorListenerCaptor;
+
+ @Mock
+ private Runnable mRunnable;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void onEnterCalledOnListeners() {
+ LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator();
+
+ coordinator.setLowLightEnterListener(mEnterListener);
+
+ coordinator.notifyBeforeLowLightTransition(true, mRunnable);
+
+ verify(mEnterListener).onBeforeEnterLowLight();
+ verify(mRunnable).run();
+ }
+
+ @Test
+ public void onExitCalledOnListeners() {
+ LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator();
+
+ coordinator.setLowLightExitListener(mExitListener);
+
+ coordinator.notifyBeforeLowLightTransition(false, mRunnable);
+
+ verify(mExitListener).onBeforeExitLowLight();
+ verify(mRunnable).run();
+ }
+
+ @Test
+ public void listenerNotCalledAfterRemoval() {
+ LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator();
+
+ coordinator.setLowLightEnterListener(mEnterListener);
+ coordinator.setLowLightEnterListener(null);
+
+ coordinator.notifyBeforeLowLightTransition(true, mRunnable);
+
+ verifyZeroInteractions(mEnterListener);
+ verify(mRunnable).run();
+ }
+
+ @Test
+ public void runnableCalledAfterAnimationEnds() {
+ when(mEnterListener.onBeforeEnterLowLight()).thenReturn(mAnimator);
+
+ LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator();
+ coordinator.setLowLightEnterListener(mEnterListener);
+
+ coordinator.notifyBeforeLowLightTransition(true, mRunnable);
+
+ // Animator listener is added and the runnable is not run yet.
+ verify(mAnimator).addListener(mAnimatorListenerCaptor.capture());
+ verifyZeroInteractions(mRunnable);
+
+ // Runnable is run once the animation ends.
+ mAnimatorListenerCaptor.getValue().onAnimationEnd(null);
+ verify(mRunnable).run();
+ }
+}
diff --git a/media/java/android/media/projection/OWNERS b/media/java/android/media/projection/OWNERS
index 9ca391013aa3..2273f816ac60 100644
--- a/media/java/android/media/projection/OWNERS
+++ b/media/java/android/media/projection/OWNERS
@@ -1,2 +1,4 @@
michaelwr@google.com
santoscordon@google.com
+chaviw@google.com
+nmusgrave@google.com
diff --git a/packages/AppPredictionLib/Android.bp b/packages/AppPredictionLib/Android.bp
index 5a68fdc9ae75..31c193631602 100644
--- a/packages/AppPredictionLib/Android.bp
+++ b/packages/AppPredictionLib/Android.bp
@@ -25,7 +25,7 @@ android_library {
name: "app_prediction",
sdk_version: "system_current",
- min_sdk_version: "system_current",
+ min_sdk_version: "current",
srcs: [
"src/**/*.java",
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 87e61b527477..d253dda61e5b 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -65,7 +65,7 @@ android_library {
"src/**/*.kt",
],
- min_sdk_version: "29",
+ min_sdk_version: "30",
}
diff --git a/packages/SettingsLib/DeviceStateRotationLock/OWNERS b/packages/SettingsLib/DeviceStateRotationLock/OWNERS
new file mode 100644
index 000000000000..091df2610866
--- /dev/null
+++ b/packages/SettingsLib/DeviceStateRotationLock/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/packages/SettingsLib/src/com/android/settingslib/devicestate/OWNERS \ No newline at end of file
diff --git a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java
index 4ed7e19f341d..10b004e1b243 100644
--- a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java
+++ b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java
@@ -29,6 +29,7 @@ import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.SparseIntArray;
@@ -36,6 +37,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
@@ -57,6 +59,7 @@ public final class DeviceStateRotationLockSettingsManager {
private final SecureSettings mSecureSettings;
private String[] mDeviceStateRotationLockDefaults;
private SparseIntArray mDeviceStateRotationLockSettings;
+ private SparseIntArray mDeviceStateDefaultRotationLockSettings;
private SparseIntArray mDeviceStateRotationLockFallbackSettings;
private String mLastSettingValue;
private List<SettableDeviceState> mSettableDeviceStates;
@@ -93,9 +96,7 @@ public final class DeviceStateRotationLockSettingsManager {
/** Returns true if device-state based rotation lock settings are enabled. */
public static boolean isDeviceStateRotationLockEnabled(Context context) {
return context.getResources()
- .getStringArray(R.array.config_perDeviceStateRotationLockDefaults)
- .length
- > 0;
+ .getStringArray(R.array.config_perDeviceStateRotationLockDefaults).length > 0;
}
private void listenForSettingsChange() {
@@ -228,6 +229,15 @@ public final class DeviceStateRotationLockSettingsManager {
try {
key = Integer.parseInt(values[i++]);
value = Integer.parseInt(values[i++]);
+ boolean isPersistedValueIgnored = value == DEVICE_STATE_ROTATION_LOCK_IGNORED;
+ boolean isDefaultValueIgnored = mDeviceStateDefaultRotationLockSettings.get(key)
+ == DEVICE_STATE_ROTATION_LOCK_IGNORED;
+ if (isPersistedValueIgnored != isDefaultValueIgnored) {
+ Log.w(TAG, "Conflict for ignored device state " + key
+ + ". Falling back on defaults");
+ fallbackOnDefaults();
+ return;
+ }
mDeviceStateRotationLockSettings.put(key, value);
} catch (NumberFormatException e) {
Log.wtf(TAG, "Error deserializing one of the saved settings", e);
@@ -276,6 +286,9 @@ public final class DeviceStateRotationLockSettingsManager {
}
private void persistSettingIfChanged(String newSettingValue) {
+ Log.v(TAG, "persistSettingIfChanged: "
+ + "last=" + mLastSettingValue + ", "
+ + "new=" + newSettingValue);
if (TextUtils.equals(mLastSettingValue, newSettingValue)) {
return;
}
@@ -288,6 +301,8 @@ public final class DeviceStateRotationLockSettingsManager {
private void loadDefaults() {
mSettableDeviceStates = new ArrayList<>(mDeviceStateRotationLockDefaults.length);
+ mDeviceStateDefaultRotationLockSettings = new SparseIntArray(
+ mDeviceStateRotationLockDefaults.length);
mDeviceStateRotationLockSettings = new SparseIntArray(
mDeviceStateRotationLockDefaults.length);
mDeviceStateRotationLockFallbackSettings = new SparseIntArray(1);
@@ -311,6 +326,7 @@ public final class DeviceStateRotationLockSettingsManager {
boolean isSettable = rotationLockSetting != DEVICE_STATE_ROTATION_LOCK_IGNORED;
mSettableDeviceStates.add(new SettableDeviceState(deviceState, isSettable));
mDeviceStateRotationLockSettings.put(deviceState, rotationLockSetting);
+ mDeviceStateDefaultRotationLockSettings.put(deviceState, rotationLockSetting);
} catch (NumberFormatException e) {
Log.wtf(TAG, "Error parsing settings entry. Entry was: " + entry, e);
return;
@@ -318,6 +334,22 @@ public final class DeviceStateRotationLockSettingsManager {
}
}
+ /** Dumps internal state. */
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("DeviceStateRotationLockSettingsManager");
+ pw.increaseIndent();
+ pw.println("mDeviceStateRotationLockDefaults: " + Arrays.toString(
+ mDeviceStateRotationLockDefaults));
+ pw.println("mDeviceStateDefaultRotationLockSettings: "
+ + mDeviceStateDefaultRotationLockSettings);
+ pw.println("mDeviceStateRotationLockSettings: " + mDeviceStateRotationLockSettings);
+ pw.println("mDeviceStateRotationLockFallbackSettings: "
+ + mDeviceStateRotationLockFallbackSettings);
+ pw.println("mSettableDeviceStates: " + mSettableDeviceStates);
+ pw.println("mLastSettingValue: " + mLastSettingValue);
+ pw.decreaseIndent();
+ }
+
/**
* Called when the persisted settings have changed, requiring a reinitialization of the
* in-memory map.
@@ -372,5 +404,13 @@ public final class DeviceStateRotationLockSettingsManager {
public int hashCode() {
return Objects.hash(mDeviceState, mIsSettable);
}
+
+ @Override
+ public String toString() {
+ return "SettableDeviceState{"
+ + "mDeviceState=" + mDeviceState
+ + ", mIsSettable=" + mIsSettable
+ + '}';
+ }
}
}
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 6d8bf5fe9012..6aa00dfe507f 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -532,7 +532,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Wekkers en onthounotas"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Laat toe dat wekkers en onthounotas gestel word"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Wekkers en onthounotas"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Laat hierdie program toe om wekkers te stel en tydsensitiewe handelinge te skeduleer. Dit laat die program op die agtergrond werk, wat meer batterykrag kan gebruik.\n\nAs hierdie toestemming af is, sal bestaande wekkers en tydgegronde geleenthede wat deur hierdie program geskeduleer is, nie werk nie."</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Laat hierdie app toe om wekkers te stel en tydsensitiewe handelinge te skeduleer. Dit laat die app op die agtergrond werk, wat meer batterykrag kan gebruik.\n\nAs hierdie toestemming af is, sal bestaande wekkers en tydgegronde geleenthede wat deur hierdie app geskeduleer is, nie werk nie."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"skedule, wekker, onthounota, horlosie"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Skakel aan"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Skakel Moenie steur nie aan"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index f39f7fc1779d..9ee3bcf75a3f 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -532,7 +532,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmi i podsjetnici"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Dozvoli postavljanje alarma i podsjetnika"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmi i podsjetnici"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Dozvolite ovoj aplikaciji da postavlja alarme i zakazuje vremenski osjetljive radnje. Ovim će se omogućiti aplikaciji da radi u pozadini, čime se može povećati potrošnja baterije.\n\nAko je ovo odobrenje isključeno, postojeći alarmi i događaji zasnovani na vremenu koje je ova aplikacija zakazala neće funkcionirati."</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Dozvolite ovoj aplikaciji da postavlja alarme i zakazuje vremenski osjetljive radnje. Ovim će se omogućiti aplikaciji da radi u pozadini, čime se može povećati potrošnja baterije.\n\nAko je ovo odobrenje isključeno, postojeći alarmi i događaji zasnovani na vremenu, a koje je ova aplikacija zakazala, neće funkcionirati."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"raspored, alarm, podsjetnik, sat"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Uključi"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Uključi način rada Ne ometaj"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 516a86457967..5caab29acce2 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -532,7 +532,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes i recordatoris"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permet la configuració d\'alarmes i recordatoris"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes i recordatoris"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permet que aquesta aplicació configuri alarmes i programi accions. Això permet a l\'aplicació executar-se en segon pla i, per tant, és possible que consumeixi més bateria.\n\nSi aquest permís està desactivat, les alarmes i els esdeveniments que ja hagi programat l\'aplicació no funcionaran."</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permet que aquesta aplicació configuri alarmes i programi accions a una hora determinada. Això permet a l\'aplicació executar-se en segon pla i, per tant, és possible que consumeixi més bateria.\n\nSi aquest permís està desactivat, les alarmes i els esdeveniments que ja hagi programat l\'aplicació no funcionaran."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programació, alarma, recordatori, rellotge"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Activa"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Activa el mode No molestis"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 34e59f31fb3f..a37b500ac5de 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -532,7 +532,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmak eta abisuak"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Eman alarmak eta abisuak ezartzeko baimena"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmak eta abisuak"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Eman alarmak ezartzeko eta denbora-muga duten ekintzak programatzeko baimena aplikazioari. Hala, aplikazioak atzeko planoan funtzionatuko du, eta litekeena da bateria gehiago kontsumitzea.\n\nEz baduzu ematen baimen hori, ez dute funtzionatuko aplikazio honen bidez programatutako alarmek eta denbora-muga duten ekintzek."</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Eman alarmak ezartzeko eta denbora-muga duten ekintzak programatzeko baimena aplikazioari. Hala, aplikazioak atzeko planoan funtzionatuko du, eta litekeena da bateria gehiago kontsumitzea.\n\nBaimen hori ematen ez baduzu, ez dute funtzionatuko aplikazio honen bidez programatutako alarmek eta denbora-muga duten ekintzek."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programazioa, alarma, abisua, erlojua"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktibatu"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Aktibatu ez molestatzeko modua"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 779515894503..22b4fbf631da 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -530,7 +530,7 @@
<string name="okay" msgid="949938843324579502">"ठिक छ"</string>
<string name="done" msgid="381184316122520313">"सम्पन्न भयो"</string>
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"अलार्म र रिमाइन्डरहरू"</string>
- <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"अलार्म तथा रिमाइन्डर सेट गर्न दिइयोस्"</string>
+ <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"अलार्म तथा रिमाइन्डर सेट गर्ने अनुमति दिनुहोस्"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"अलार्म तथा रिमाइन्डर"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"यो एपलाई अलार्म सेट गर्ने र समयमै पूरा गर्नु पर्ने कारबाहीहरूको रुटिन बनाउने अनुमति दिनुहोस्। यो अनुमति दिइएको छ भने यो एप ब्याकग्राउन्डमा चल्छ र धेरै ब्याट्री खपत हुन्छ।\n\nयो अनुमति दिइएको छैन भने सेट गरिएका अलार्म बज्दैनन् र यो एपले तय गरेका गतिविधि चल्दैनन्।"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"समयतालिका, अलार्म, रिमाइन्डर, घडी"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index b18d81973536..96f845e58818 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -532,7 +532,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmy i przypomnienia"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Zezwalaj na ustawianie alarmów i przypomnień"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmy i przypomnienia"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Zezwól na ustawianie alarmów i planowanie innych działań, w przypadku których czas jest istotny. Dzięki temu aplikacja będzie mogła działać w tle, co może zwiększyć wykorzystanie baterii.\n\nJeśli nie włączysz tych uprawnień, istniejące alarmy i zaplanowane wydarzenia z tej aplikacji nie będą działać."</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Zezwalaj tej aplikacji na ustawianie alarmów i planowanie działań, w przypadku których czas jest istotny. Aplikacja będzie mogła działać w tle, co może zwiększyć wykorzystanie baterii.\n\nJeśli nie włączysz tego uprawnienia, istniejące alarmy i zaplanowane wydarzenia z tej aplikacji nie będą działać."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"harmonogram, alarm, przypomnienie, zegar"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Włącz"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Włącz tryb Nie przeszkadzać"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 816108e52bcf..da7dcc5fa268 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -532,7 +532,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes e lembretes"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Autorizar a definição de alarmes e lembretes"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permitir que o app defina alarmes e programe ações mais imediatas. Essa opção autoriza o app a ser executado em segundo plano, o que pode consumir mais bateria.\n\nSe a permissão for desativada, os alarmes e eventos programados pelo app não funcionarão."</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permitir que o app defina alarmes e programe ações com hora marcada. Essa opção autoriza o app a ser executado em segundo plano, o que pode consumir mais bateria.\n\nSe a permissão for desativada, os alarmes e eventos programados pelo app não funcionarão."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programar, alarme, lembrete, relógio"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Ativar"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Ativar o Não perturbe"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index d9116fe49ada..f70fae0223f0 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -530,7 +530,7 @@
<string name="okay" msgid="949938843324579502">"OK"</string>
<string name="done" msgid="381184316122520313">"Concluir"</string>
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes e lembretes"</string>
- <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permitir a definição de alarmes e lembretes"</string>
+ <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permitir alarmes e lembretes"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permita que esta app defina alarmes e agende outras ações com base no tempo. Esta ação permite que a app seja executada em segundo plano, o que pode utilizar mais bateria.\n\nSe esta autorização estiver desativada, os alarmes existentes e os eventos com base no tempo agendados por esta app não funcionam."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"agendar, alarme, lembrete, relógio"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 816108e52bcf..da7dcc5fa268 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -532,7 +532,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes e lembretes"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Autorizar a definição de alarmes e lembretes"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permitir que o app defina alarmes e programe ações mais imediatas. Essa opção autoriza o app a ser executado em segundo plano, o que pode consumir mais bateria.\n\nSe a permissão for desativada, os alarmes e eventos programados pelo app não funcionarão."</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permitir que o app defina alarmes e programe ações com hora marcada. Essa opção autoriza o app a ser executado em segundo plano, o que pode consumir mais bateria.\n\nSe a permissão for desativada, os alarmes e eventos programados pelo app não funcionarão."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programar, alarme, lembrete, relógio"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Ativar"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Ativar o Não perturbe"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index ea5faa8dee93..fabfcdec3ae9 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -532,7 +532,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarme și mementouri"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permite setarea pentru alarme și mementouri"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarme și mementouri"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permite acestei aplicații să stabilească alarme și să planifice acțiuni dependente de timp. Astfel, aplicația poate să ruleze în fundal, fapt care ar putea consuma mai multă baterie.\n\nDacă permisiunea este dezactivată, alarmele și evenimentele dependente de timp planificate de aplicație nu vor funcționa."</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permite acestei aplicații să seteze alarme și să planifice acțiuni care trebuie realizate în timp scurt. Astfel, aplicația poate să ruleze în fundal, ceea ce ar putea crește consumul de baterie.\n\nDacă permisiunea este dezactivată, alarmele și evenimentele dependente de timp planificate de aplicație nu vor funcționa."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programare, alarmă, memento, ceas"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Activează"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Activează Nu deranja"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 9e4f23cc5a56..fe49f87d1f15 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -532,7 +532,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Будильники и напоминания"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Разрешить установку будильников и напоминаний"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Будильники и напоминания"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Если вы разрешите этому приложению устанавливать будильники и планировать на определенное время действия, оно будет работать в фоновом режиме. В таком случае заряд батареи может расходоваться быстрее.\n\nЕсли отключить эту настройку, текущие будильники и созданные приложением мероприятия перестанут запускаться."</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Вы можете разрешить этому приложению устанавливать будильники и планировать запуск действий в определенное время. В этом случае оно будет работать в фоновом режиме и быстрее расходовать заряд батареи.\n\nЕсли отключить это разрешение, текущие будильники и созданные приложением события перестанут запускаться."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"установить, будильник, напоминание, часы"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Включить"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Включите режим \"Не беспокоить\""</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 1d187039f369..3f6a44019b71 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -532,7 +532,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Budíky a pripomenutia"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Povoliť nastavovanie budíkov a pripomenutí"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Budíky a pripomenutia"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Povoľte tejto aplikácii nastavovať budíky a plánovať akcie s časovým obmedzením. Aplikácii to umožní pracovať na pozadí, čo môže zvýšiť spotrebu batérie.\n\nAk je toto povolenie vypnuté, súčasné budíky a udalosti s časovým obmedzením naplánované touto aplikáciu nebudú fungovať."</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Povoľte tejto aplikácii nastavovať budíky a plánovať akcie s časovým obmedzením. Aplikácii to umožní pracovať na pozadí, čo môže zvýšiť spotrebu batérie.\n\nAk je toto povolenie vypnuté, existujúce budíky a udalosti s časovým obmedzením naplánované touto aplikáciu nebudú fungovať."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"plán, budík, pripomenutie, hodiny"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Zapnúť"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Zapnite režim bez vyrušení"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 738e97e6d659..61229297036e 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -530,7 +530,7 @@
<string name="okay" msgid="949938843324579502">"Tamam"</string>
<string name="done" msgid="381184316122520313">"Bitti"</string>
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmlar ve hatırlatıcılar"</string>
- <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Alarm ve hatırlatıcı ayarlanmasına izin ver"</string>
+ <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Alarm ve hatırlatıcı ayarlamasına izin ver"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmlar ve hatırlatıcılar"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Bu uygulamanın alarm kurmasına ve zamana bağlı işlemler programlamasına izin verin. Bu izin, uygulamanın arka planda çalışmasına olanak sağlayarak daha fazla pil harcanmasına neden olabilir.\n\nBu izin verilmezse bu uygulama tarafından programlanmış mevcut alarmlar ve zamana bağlı etkinlikler çalışmaz."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"program, alarm, hatırlatıcı, saat"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 50d292192727..4931c90915e4 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -240,7 +240,7 @@
<string name="adb_wireless_error" msgid="721958772149779856">"錯誤"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"無線偵錯"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"如要查看並使用可用的裝置,請開啟無線偵錯功能"</string>
- <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"使用 QR 圖碼配對裝置"</string>
+ <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"使用 QR code 配對裝置"</string>
<string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"使用 QR code 掃描器配對新裝置"</string>
<string name="adb_pair_method_code_title" msgid="1122590300445142904">"使用配對碼配對裝置"</string>
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"使用六位數的配對碼配對新裝置"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index 2614644feb20..688fc720d058 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -55,6 +55,7 @@ public class DreamBackend {
public ComponentName settingsComponentName;
public CharSequence description;
public Drawable previewImage;
+ public boolean supportsComplications = false;
@Override
public String toString() {
@@ -175,6 +176,7 @@ public class DreamBackend {
if (dreamMetadata != null) {
dreamInfo.settingsComponentName = dreamMetadata.settingsActivity;
dreamInfo.previewImage = dreamMetadata.previewImage;
+ dreamInfo.supportsComplications = dreamMetadata.showComplications;
}
dreamInfos.add(dreamInfo);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
index 6a1cee3146a2..562d20d05429 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
@@ -224,6 +224,9 @@ public class EnableZenModeDialog {
mMetricsLogger.logOnConditionSelected();
updateAlarmWarningText(tag.condition);
}
+ tag.line1.setStateDescription(
+ isChecked ? buttonView.getContext().getString(
+ com.android.internal.R.string.selected) : null);
}
});
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java b/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java
index 87e97b17b914..abbdaa73c18e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java
@@ -196,6 +196,9 @@ public class ZenDurationDialog {
if (isChecked) {
tag.rb.setChecked(true);
}
+ tag.line1.setStateDescription(
+ isChecked ? buttonView.getContext().getString(
+ com.android.internal.R.string.selected) : null);
}
});
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
index 81006dd6b011..0fa15eb6bc0c 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
@@ -33,7 +33,10 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager.SettableDeviceState;
+import com.google.common.truth.Expect;
+
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -45,6 +48,8 @@ import java.util.List;
@RunWith(AndroidJUnit4.class)
public class DeviceStateRotationLockSettingsManagerTest {
+ @Rule public Expect mExpect = Expect.create();
+
@Mock private Context mMockContext;
@Mock private Resources mMockResources;
@@ -117,4 +122,40 @@ public class DeviceStateRotationLockSettingsManagerTest {
new SettableDeviceState(/* deviceState= */ 0, /* isSettable= */ false)
).inOrder();
}
+
+ @Test
+ public void persistedInvalidIgnoredState_returnsDefaults() {
+ when(mMockResources.getStringArray(
+ R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(
+ new String[]{"0:1", "1:0:2", "2:2"});
+ // Here 2 has IGNORED, and in the defaults 1 has IGNORED.
+ persistSettings("0:2:2:0:1:2");
+ DeviceStateRotationLockSettingsManager manager =
+ new DeviceStateRotationLockSettingsManager(mMockContext, mFakeSecureSettings);
+
+ mExpect.that(manager.getRotationLockSetting(0)).isEqualTo(1);
+ mExpect.that(manager.getRotationLockSetting(1)).isEqualTo(2);
+ mExpect.that(manager.getRotationLockSetting(2)).isEqualTo(2);
+ }
+
+ @Test
+ public void persistedValidValues_returnsPersistedValues() {
+ when(mMockResources.getStringArray(
+ R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(
+ new String[]{"0:1", "1:0:2", "2:2"});
+ persistSettings("0:2:1:0:2:1");
+ DeviceStateRotationLockSettingsManager manager =
+ new DeviceStateRotationLockSettingsManager(mMockContext, mFakeSecureSettings);
+
+ mExpect.that(manager.getRotationLockSetting(0)).isEqualTo(2);
+ mExpect.that(manager.getRotationLockSetting(1)).isEqualTo(1);
+ mExpect.that(manager.getRotationLockSetting(2)).isEqualTo(1);
+ }
+
+ private void persistSettings(String value) {
+ mFakeSecureSettings.putStringForUser(
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ value,
+ UserHandle.USER_CURRENT);
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java
index 59d56747ec5d..6b81c1a6f794 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java
@@ -16,6 +16,8 @@
package com.android.settingslib.notification;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -78,6 +80,8 @@ public class EnableZenModeDialogTest {
mController.mForeverId = Condition.newId(mContext).appendPath("forever").build();
when(mContext.getString(com.android.internal.R.string.zen_mode_forever))
.thenReturn("testSummary");
+ when(mContext.getString(com.android.internal.R.string.selected))
+ .thenReturn("selected");
NotificationManager.Policy alarmsEnabledPolicy = new NotificationManager.Policy(
NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS, 0, 0, 0);
doReturn(alarmsEnabledPolicy).when(mNotificationManager).getNotificationPolicy();
@@ -190,4 +194,25 @@ public class EnableZenModeDialogTest {
// alarm warning should NOT be null
assertNotNull(mController.computeAlarmWarningText(null));
}
+
+ @Test
+ public void testAccessibility() {
+ mController.bindConditions(null);
+ EnableZenModeDialog.ConditionTag forever = mController.getConditionTagAt(
+ ZenDurationDialog.FOREVER_CONDITION_INDEX);
+ EnableZenModeDialog.ConditionTag countdown = mController.getConditionTagAt(
+ ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+ EnableZenModeDialog.ConditionTag alwaysAsk = mController.getConditionTagAt(
+ ZenDurationDialog.ALWAYS_ASK_CONDITION_INDEX);
+
+ forever.rb.setChecked(true);
+ assertThat(forever.line1.getStateDescription().toString()).isEqualTo("selected");
+ assertThat(countdown.line1.getStateDescription()).isNull();
+ assertThat(alwaysAsk.line1.getStateDescription()).isNull();
+
+ alwaysAsk.rb.setChecked(true);
+ assertThat(forever.line1.getStateDescription()).isNull();
+ assertThat(countdown.line1.getStateDescription()).isNull();
+ assertThat(alwaysAsk.line1.getStateDescription().toString()).isEqualTo("selected");
+ }
} \ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java
index 437c0d4f4469..fc45e89a6dd5 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java
@@ -16,6 +16,8 @@
package com.android.settingslib.notification;
+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.assertTrue;
@@ -205,4 +207,27 @@ public class ZenDurationDialogTest {
ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
assertEquals(120, tag.countdownZenDuration);
}
+
+ @Test
+ public void testAccessibility() {
+ Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_DURATION,
+ Settings.Secure.ZEN_DURATION_FOREVER);
+ mController.setupDialog(mBuilder);
+ ZenDurationDialog.ConditionTag forever = mController.getConditionTagAt(
+ ZenDurationDialog.FOREVER_CONDITION_INDEX);
+ ZenDurationDialog.ConditionTag countdown = mController.getConditionTagAt(
+ ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+ ZenDurationDialog.ConditionTag alwaysAsk = mController.getConditionTagAt(
+ ZenDurationDialog.ALWAYS_ASK_CONDITION_INDEX);
+
+ forever.rb.setChecked(true);
+ assertThat(forever.line1.getStateDescription().toString()).isEqualTo("selected");
+ assertThat(countdown.line1.getStateDescription()).isNull();
+ assertThat(alwaysAsk.line1.getStateDescription()).isNull();
+
+ alwaysAsk.rb.setChecked(true);
+ assertThat(forever.line1.getStateDescription()).isNull();
+ assertThat(countdown.line1.getStateDescription()).isNull();
+ assertThat(alwaysAsk.line1.getStateDescription().toString()).isEqualTo("selected");
+ }
} \ No newline at end of file
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 17a94b8639d0..296c2ae5cf99 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -419,7 +419,7 @@ class ActivityLaunchAnimator(
internal val delegate: AnimationDelegate
init {
- delegate = AnimationDelegate(controller, callback, launchAnimator, listener)
+ delegate = AnimationDelegate(controller, callback, listener, launchAnimator)
}
@BinderThread
@@ -446,10 +446,10 @@ class ActivityLaunchAnimator(
constructor(
private val controller: Controller,
private val callback: Callback,
- /** The animator to use to animate the window launch. */
- private val launchAnimator: LaunchAnimator = DEFAULT_LAUNCH_ANIMATOR,
/** Listener for animation lifecycle events. */
- private val listener: Listener? = null
+ private val listener: Listener? = null,
+ /** The animator to use to animate the window launch. */
+ private val launchAnimator: LaunchAnimator = DEFAULT_LAUNCH_ANIMATOR
) : RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> {
private val launchContainer = controller.launchContainer
private val context = launchContainer.context
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt
index 40a5e9794d37..c49a487c6766 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt
@@ -26,7 +26,7 @@ interface Expandable {
* currently not attached or visible).
*
* @param cujType the CUJ type from the [com.android.internal.jank.InteractionJankMonitor]
- * associated to the launch that will use this controller.
+ * associated to the launch that will use this controller.
*/
fun activityLaunchController(cujType: Int? = null): ActivityLaunchAnimator.Controller?
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
index 9668066be125..3417ffd6b83a 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
@@ -75,7 +75,7 @@ class LaunchAnimator(private val timings: Timings, private val interpolators: In
* - Get the associated [Context].
* - Compute whether we are expanding fully above the launch container.
* - Get to overlay to which we initially put the window background layer, until the opening
- * window is made visible (see [openingWindowSyncView]).
+ * window is made visible (see [openingWindowSyncView]).
*
* This container can be changed to force this [Controller] to animate the expanding view
* inside a different location, for instance to ensure correct layering during the
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt
index b98b92219c33..ed8e70568b48 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt
@@ -24,7 +24,7 @@ interface LaunchableView {
* Set whether this view should block/postpone all calls to [View.setVisibility]. This ensures
* that this view:
* - remains invisible during the launch animation given that it is ghosted and already drawn
- * somewhere else.
+ * somewhere else.
* - remains invisible as long as a dialog expanded from it is shown.
* - restores its expected visibility once the dialog expanded from it is dismissed.
*
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt
index 0e2d23b04a4f..6946e6bf88a8 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt
@@ -182,9 +182,9 @@ class RemoteTransitionAdapter {
* Represents a TransitionInfo object as an array of old-style targets
*
* @param wallpapers If true, this will return wallpaper targets; otherwise it returns
- * non-wallpaper targets.
+ * non-wallpaper targets.
* @param leashMap Temporary map of change leash -> launcher leash. Is an output, so should
- * be populated by this function. If null, it is ignored.
+ * be populated by this function. If null, it is ignored.
*/
fun wrapTargets(
info: TransitionInfo,
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ShadeInterpolation.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ShadeInterpolation.kt
index a96f893a8db4..b89a8b0e0272 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ShadeInterpolation.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ShadeInterpolation.kt
@@ -6,6 +6,7 @@ object ShadeInterpolation {
/**
* Interpolate alpha for notification background scrim during shade expansion.
+ *
* @param fraction Shade expansion fraction
*/
@JvmStatic
@@ -16,6 +17,7 @@ object ShadeInterpolation {
/**
* Interpolate alpha for shade content during shade expansion.
+ *
* @param fraction Shade expansion fraction
*/
@JvmStatic
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
index 341784e26257..468a8b10bc01 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
@@ -161,7 +161,6 @@ class TextInterpolator(layout: Layout) {
* This API is useful to continue animation from the middle of the state. For example, if you
* animate weight from 200 to 400, then if you want to move back to 200 at the half of the
* animation, it will look like
- *
* <pre> <code>
* ```
* val interp = TextInterpolator(layout)
@@ -497,7 +496,9 @@ class TextInterpolator(layout: Layout) {
count,
layout.textDirectionHeuristic,
paint
- ) { _, _, glyphs, _ -> runs.add(glyphs) }
+ ) { _, _, glyphs, _ ->
+ runs.add(glyphs)
+ }
out.add(runs)
if (lineNo > 0) {
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt
index 0b842ad5331c..5ed723bdd254 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt
@@ -25,7 +25,6 @@ import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary
/**
* Shader class that renders an expanding ripple effect. The ripple contains three elements:
- *
* 1. an expanding filled [RippleShape] that appears in the beginning and quickly fades away
* 2. an expanding ring that appears throughout the effect
* 3. an expanding ring-shaped area that reveals noise over #2.
@@ -311,6 +310,7 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) :
* Parameters used for fade in and outs of the ripple.
*
* <p>Note that all the fade in/ outs are "linear" progression.
+ *
* ```
* (opacity)
* 1
@@ -325,6 +325,7 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) :
* fadeIn fadeOut
* Start & End Start & End
* ```
+ *
* <p>If no fade in/ out is needed, set [fadeInStart] and [fadeInEnd] to 0; [fadeOutStart] and
* [fadeOutEnd] to 1.
*/
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt
index 79bc2f432ded..89871fa7d875 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt
@@ -30,12 +30,14 @@ data class TurbulenceNoiseAnimationConfig(
* Noise move speed variables.
*
* Its sign determines the direction; magnitude determines the speed. <ul>
+ *
* ```
* <li> [noiseMoveSpeedX] positive: right to left; negative: left to right.
* <li> [noiseMoveSpeedY] positive: bottom to top; negative: top to bottom.
* <li> [noiseMoveSpeedZ] its sign doesn't matter much, as it moves in Z direction. Use it
* to add turbulence in place.
* ```
+ *
* </ul>
*/
val noiseMoveSpeedX: Float = 0f,
diff --git a/packages/SystemUI/animation/src/com/android/systemui/util/AnimatorExtensions.kt b/packages/SystemUI/animation/src/com/android/systemui/util/AnimatorExtensions.kt
new file mode 100644
index 000000000000..35dbb89ad801
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/util/AnimatorExtensions.kt
@@ -0,0 +1,80 @@
+/*
+ * 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
+
+import androidx.core.animation.Animator
+
+/**
+ * Add an action which will be invoked when the animation has ended.
+ *
+ * @return the [Animator.AnimatorListener] added to the Animator
+ * @see Animator.end
+ */
+inline fun Animator.doOnEnd(
+ crossinline action: (animator: Animator) -> Unit
+): Animator.AnimatorListener = addListener(onEnd = action)
+
+/**
+ * Add an action which will be invoked when the animation has started.
+ *
+ * @return the [Animator.AnimatorListener] added to the Animator
+ * @see Animator.start
+ */
+inline fun Animator.doOnStart(
+ crossinline action: (animator: Animator) -> Unit
+): Animator.AnimatorListener = addListener(onStart = action)
+
+/**
+ * Add an action which will be invoked when the animation has been cancelled.
+ *
+ * @return the [Animator.AnimatorListener] added to the Animator
+ * @see Animator.cancel
+ */
+inline fun Animator.doOnCancel(
+ crossinline action: (animator: Animator) -> Unit
+): Animator.AnimatorListener = addListener(onCancel = action)
+
+/**
+ * Add an action which will be invoked when the animation has repeated.
+ *
+ * @return the [Animator.AnimatorListener] added to the Animator
+ */
+inline fun Animator.doOnRepeat(
+ crossinline action: (animator: Animator) -> Unit
+): Animator.AnimatorListener = addListener(onRepeat = action)
+
+/**
+ * Add a listener to this Animator using the provided actions.
+ *
+ * @return the [Animator.AnimatorListener] added to the Animator
+ */
+inline fun Animator.addListener(
+ crossinline onEnd: (animator: Animator) -> Unit = {},
+ crossinline onStart: (animator: Animator) -> Unit = {},
+ crossinline onCancel: (animator: Animator) -> Unit = {},
+ crossinline onRepeat: (animator: Animator) -> Unit = {}
+): Animator.AnimatorListener {
+ val listener =
+ object : Animator.AnimatorListener {
+ override fun onAnimationRepeat(animator: Animator) = onRepeat(animator)
+ override fun onAnimationEnd(animator: Animator) = onEnd(animator)
+ override fun onAnimationCancel(animator: Animator) = onCancel(animator)
+ override fun onAnimationStart(animator: Animator) = onStart(animator)
+ }
+ addListener(listener)
+ return listener
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt
new file mode 100644
index 000000000000..f64ea4561906
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.systemui.lint
+
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import org.jetbrains.uast.UAnnotation
+import org.jetbrains.uast.UElement
+
+class DemotingTestWithoutBugDetector : Detector(), SourceCodeScanner {
+ override fun getApplicableUastTypes(): List<Class<out UElement>> {
+ return listOf(UAnnotation::class.java)
+ }
+
+ override fun createUastHandler(context: JavaContext): UElementHandler {
+ return object : UElementHandler() {
+ override fun visitAnnotation(node: UAnnotation) {
+ if (node.qualifiedName !in DEMOTING_ANNOTATION) {
+ return
+ }
+ val bugId = node.findAttributeValue("bugId")!!.evaluate() as Int
+ if (bugId <= 0) {
+ val location = context.getLocation(node)
+ val message = "Please attach a bug id to track demoted test"
+ context.report(ISSUE, node, location, message)
+ }
+ }
+ }
+ }
+
+ companion object {
+ val DEMOTING_ANNOTATION =
+ listOf("androidx.test.filters.FlakyTest", "android.platform.test.annotations.FlakyTest")
+
+ @JvmField
+ val ISSUE: Issue =
+ Issue.create(
+ id = "DemotingTestWithoutBug",
+ briefDescription = "Demoting a test without attaching a bug.",
+ explanation =
+ """
+ Annotations (`@FlakyTest`) demote tests to an unmonitored \
+ test suite. Please set the `bugId` field in such annotations to track \
+ the test status.
+ """,
+ category = Category.TESTING,
+ priority = 8,
+ severity = Severity.WARNING,
+ implementation =
+ Implementation(
+ DemotingTestWithoutBugDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ )
+ )
+ }
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DumpableNotRegisteredDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DumpableNotRegisteredDetector.kt
new file mode 100644
index 000000000000..30e2a2527a93
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DumpableNotRegisteredDetector.kt
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.systemui.lint
+
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Context
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Location
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.intellij.psi.PsiMethod
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UClass
+
+/**
+ * Checks if any class has implemented the `Dumpable` interface but has not registered itself with
+ * the `DumpManager`.
+ */
+@Suppress("UnstableApiUsage")
+class DumpableNotRegisteredDetector : Detector(), SourceCodeScanner {
+
+ private var isDumpable: Boolean = false
+ private var isCoreStartable: Boolean = false
+ private var hasRegisterCall: Boolean = false
+ private var classLocation: Location? = null
+
+ override fun beforeCheckFile(context: Context) {
+ isDumpable = false
+ isCoreStartable = false
+ hasRegisterCall = false
+ classLocation = null
+ }
+
+ override fun applicableSuperClasses(): List<String> {
+ return listOf(DUMPABLE_CLASS_NAME)
+ }
+
+ override fun getApplicableMethodNames(): List<String> {
+ return listOf("registerDumpable", "registerNormalDumpable", "registerCriticalDumpable")
+ }
+
+ override fun visitClass(context: JavaContext, declaration: UClass) {
+ if (declaration.isInterface || context.evaluator.isAbstract(declaration)) {
+ // Don't require interfaces or abstract classes to call `register` (assume the full
+ // implementations will call it). This also means that we correctly don't warn for the
+ // `Dumpable` interface itself.
+ return
+ }
+
+ classLocation = context.getNameLocation(declaration)
+
+ val superTypeClassNames = declaration.superTypes.mapNotNull { it.resolve()?.qualifiedName }
+ isDumpable = superTypeClassNames.contains(DUMPABLE_CLASS_NAME)
+ isCoreStartable = superTypeClassNames.contains(CORE_STARTABLE_CLASS_NAME)
+ }
+
+ override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+ if (context.evaluator.isMemberInSubClassOf(method, DUMP_MANAGER_CLASS_NAME)) {
+ hasRegisterCall = true
+ }
+ }
+
+ override fun afterCheckFile(context: Context) {
+ if (!isDumpable) {
+ return
+ }
+ if (isDumpable && isCoreStartable) {
+ // CoreStartables will be automatically registered, so classes that implement
+ // CoreStartable do not need a `register` call.
+ return
+ }
+
+ if (!hasRegisterCall) {
+ context.report(
+ issue = ISSUE,
+ location = classLocation!!,
+ message =
+ "Any class implementing `Dumpable` must call " +
+ "`DumpManager.registerNormalDumpable` or " +
+ "`DumpManager.registerCriticalDumpable`",
+ )
+ }
+ }
+
+ companion object {
+ @JvmField
+ val ISSUE: Issue =
+ Issue.create(
+ id = "DumpableNotRegistered",
+ briefDescription = "Dumpable not registered with DumpManager.",
+ explanation =
+ """
+ This class has implemented the `Dumpable` interface, but it has not registered \
+ itself with the `DumpManager`. This means that the class will never actually \
+ be dumped. Please call `DumpManager.registerNormalDumpable` or \
+ `DumpManager.registerCriticalDumpable` in the class's constructor or \
+ initialization method.""",
+ category = Category.CORRECTNESS,
+ priority = 8,
+ severity = Severity.WARNING,
+ implementation =
+ Implementation(DumpableNotRegisteredDetector::class.java, Scope.JAVA_FILE_SCOPE)
+ )
+
+ private const val DUMPABLE_CLASS_NAME = "com.android.systemui.Dumpable"
+ private const val CORE_STARTABLE_CLASS_NAME = "com.android.systemui.CoreStartable"
+ private const val DUMP_MANAGER_CLASS_NAME = "com.android.systemui.dump.DumpManager"
+ }
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
index 254a6fb4714f..387b67d231cd 100644
--- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
@@ -32,13 +32,15 @@ class SystemUIIssueRegistry : IssueRegistry() {
BindServiceOnMainThreadDetector.ISSUE,
BroadcastSentViaContextDetector.ISSUE,
CleanArchitectureDependencyViolationDetector.ISSUE,
+ DumpableNotRegisteredDetector.ISSUE,
SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY,
NonInjectedMainThreadDetector.ISSUE,
RegisterReceiverViaContextDetector.ISSUE,
SoftwareBitmapDetector.ISSUE,
NonInjectedServiceDetector.ISSUE,
- StaticSettingsProviderDetector.ISSUE
+ StaticSettingsProviderDetector.ISSUE,
+ DemotingTestWithoutBugDetector.ISSUE
)
override val api: Int
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetectorTest.kt
index a4b59fd8e086..a5f832a17de4 100644
--- a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetectorTest.kt
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetectorTest.kt
@@ -64,7 +64,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes
class BadClass(
private val viewModel: ViewModel,
)
- """.trimIndent()
+ """
+ .trimIndent()
)
)
.issues(
@@ -98,7 +99,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes
class BadClass(
private val repository: Repository,
)
- """.trimIndent()
+ """
+ .trimIndent()
)
)
.issues(
@@ -136,7 +138,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes
private val interactor: Interactor,
private val viewmodel: ViewModel,
)
- """.trimIndent()
+ """
+ .trimIndent()
)
)
.issues(
@@ -176,7 +179,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes
class BadClass(
private val interactor: Interactor,
)
- """.trimIndent()
+ """
+ .trimIndent()
)
)
.issues(
@@ -207,7 +211,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes
data class Model(
private val name: String,
)
- """.trimIndent()
+ """
+ .trimIndent()
)
private val REPOSITORY_FILE =
TestFiles.kotlin(
@@ -228,7 +233,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes
return models
}
}
- """.trimIndent()
+ """
+ .trimIndent()
)
private val INTERACTOR_FILE =
TestFiles.kotlin(
@@ -245,7 +251,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes
return repository.getModels()
}
}
- """.trimIndent()
+ """
+ .trimIndent()
)
private val VIEW_MODEL_FILE =
TestFiles.kotlin(
@@ -262,7 +269,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes
return interactor.getModels().map { model -> model.name }
}
}
- """.trimIndent()
+ """
+ .trimIndent()
)
private val NON_CLEAN_ARCHITECTURE_FILE =
TestFiles.kotlin(
@@ -282,7 +290,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes
)
}
}
- """.trimIndent()
+ """
+ .trimIndent()
)
private val LEGITIMATE_FILES =
arrayOf(
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt
new file mode 100644
index 000000000000..557c300635eb
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestFiles
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+
+class DemotingTestWithoutBugDetectorTest : SystemUILintDetectorTest() {
+
+ override fun getDetector(): Detector = DemotingTestWithoutBugDetector()
+ override fun getIssues(): List<Issue> = listOf(DemotingTestWithoutBugDetector.ISSUE)
+
+ @Test
+ fun testMarkFlaky_withBugId() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+ import androidx.test.filters.FlakyTest;
+
+ @FlakyTest(bugId = 123)
+ public class TestClass {
+ public void testCase() {}
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(DemotingTestWithoutBugDetector.ISSUE)
+ .run()
+ .expectClean()
+
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+ import android.platform.test.annotations.FlakyTest;
+
+ @FlakyTest(bugId = 123)
+ public class TestClass {
+ public void testCase() {}
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(DemotingTestWithoutBugDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun testMarkFlaky_withoutBugId() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+ import androidx.test.filters.FlakyTest;
+
+ @FlakyTest
+ public class TestClass {
+ public void testCase() {}
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(DemotingTestWithoutBugDetector.ISSUE)
+ .run()
+ .expect(
+ """
+ src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test [DemotingTestWithoutBug]
+ @FlakyTest
+ ~~~~~~~~~~
+ 0 errors, 1 warnings
+ """
+ )
+
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+ import android.platform.test.annotations.FlakyTest;
+
+ @FlakyTest
+ public class TestClass {
+ public void testCase() {}
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(DemotingTestWithoutBugDetector.ISSUE)
+ .run()
+ .expect(
+ """
+ src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test [DemotingTestWithoutBug]
+ @FlakyTest
+ ~~~~~~~~~~
+ 0 errors, 1 warnings
+ """
+ )
+ }
+
+ private val filtersFlakyTestStub: TestFile =
+ java(
+ """
+ package androidx.test.filters;
+
+ public @interface FlakyTest {
+ int bugId() default -1;
+ }
+ """
+ )
+ private val annotationsFlakyTestStub: TestFile =
+ java(
+ """
+ package android.platform.test.annotations;
+
+ public @interface FlakyTest {
+ int bugId() default -1;
+ }
+ """
+ )
+ private val stubs = arrayOf(filtersFlakyTestStub, annotationsFlakyTestStub)
+}
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DumpableNotRegisteredDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DumpableNotRegisteredDetectorTest.kt
new file mode 100644
index 000000000000..95b700543f1e
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DumpableNotRegisteredDetectorTest.kt
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.TestFiles
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+
+@Suppress("UnstableApiUsage")
+class DumpableNotRegisteredDetectorTest : SystemUILintDetectorTest() {
+ override fun getDetector(): Detector = DumpableNotRegisteredDetector()
+
+ override fun getIssues(): List<Issue> = listOf(DumpableNotRegisteredDetector.ISSUE)
+
+ @Test
+ fun classIsNotDumpable_noViolation() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+
+ class SomeClass() {
+ }
+ """
+ .trimIndent()
+ ),
+ *stubs,
+ )
+ .issues(DumpableNotRegisteredDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun classIsDumpable_andRegisterIsCalled_noViolation() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+
+ import com.android.systemui.Dumpable;
+ import com.android.systemui.dump.DumpManager;
+
+ public class SomeClass implements Dumpable {
+ SomeClass(DumpManager dumpManager) {
+ dumpManager.registerDumpable(this);
+ }
+
+ @Override
+ void dump(PrintWriter pw, String[] args) {
+ pw.println("testDump");
+ }
+ }
+ """
+ .trimIndent()
+ ),
+ *stubs,
+ )
+ .issues(DumpableNotRegisteredDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun classIsDumpable_andRegisterNormalIsCalled_noViolation() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+
+ import com.android.systemui.Dumpable;
+ import com.android.systemui.dump.DumpManager;
+
+ public class SomeClass implements Dumpable {
+ SomeClass(DumpManager dumpManager) {
+ dumpManager.registerNormalDumpable(this);
+ }
+
+ @Override
+ void dump(PrintWriter pw, String[] args) {
+ pw.println("testDump");
+ }
+ }
+ """
+ .trimIndent()
+ ),
+ *stubs,
+ )
+ .issues(DumpableNotRegisteredDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun classIsDumpable_andRegisterCriticalIsCalled_noViolation() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+
+ import com.android.systemui.Dumpable;
+ import com.android.systemui.dump.DumpManager;
+
+ public class SomeClass implements Dumpable {
+ SomeClass(DumpManager dumpManager) {
+ dumpManager.registerCriticalDumpable(this);
+ }
+
+ @Override
+ void dump(PrintWriter pw, String[] args) {
+ pw.println("testDump");
+ }
+ }
+ """
+ .trimIndent()
+ ),
+ *stubs,
+ )
+ .issues(DumpableNotRegisteredDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun classIsDumpable_noRegister_violation() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+
+ import com.android.systemui.Dumpable;
+
+ public class SomeClass implements Dumpable {
+ @Override
+ public void dump() {
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs,
+ )
+ .issues(DumpableNotRegisteredDetector.ISSUE)
+ .run()
+ .expect(
+ ("""
+ src/test/pkg/SomeClass.java:5: Warning: Any class implementing Dumpable must call DumpManager.registerNormalDumpable or DumpManager.registerCriticalDumpable [DumpableNotRegistered]
+ public class SomeClass implements Dumpable {
+ ~~~~~~~~~
+ 0 errors, 1 warnings
+ """)
+ .trimIndent()
+ )
+ }
+
+ @Test
+ fun classIsDumpable_usesNotDumpManagerMethod_violation() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+
+ import com.android.systemui.Dumpable;
+ import com.android.systemui.OtherRegistrationObject;
+
+ public class SomeClass implements Dumpable {
+ public SomeClass(OtherRegistrationObject otherRegistrationObject) {
+ otherRegistrationObject.registerDumpable(this);
+ }
+ @Override
+ public void dump() {
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs,
+ )
+ .issues(DumpableNotRegisteredDetector.ISSUE)
+ .run()
+ .expect(
+ ("""
+ src/test/pkg/SomeClass.java:6: Warning: Any class implementing Dumpable must call DumpManager.registerNormalDumpable or DumpManager.registerCriticalDumpable [DumpableNotRegistered]
+ public class SomeClass implements Dumpable {
+ ~~~~~~~~~
+ 0 errors, 1 warnings
+ """)
+ .trimIndent()
+ )
+ }
+
+ @Test
+ fun classIsDumpableAndCoreStartable_noRegister_noViolation() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+
+ import com.android.systemui.Dumpable;
+ import com.android.systemui.CoreStartable;
+
+ public class SomeClass implements Dumpable, CoreStartable {
+ @Override
+ public void start() {
+ }
+
+ @Override
+ public void dump() {
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs,
+ )
+ .issues(DumpableNotRegisteredDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun classIsAbstract_noRegister_noViolation() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+
+ import com.android.systemui.Dumpable;
+
+ public abstract class SomeClass implements Dumpable {
+ void abstractMethodHere();
+
+ @Override
+ public void dump() {
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs,
+ )
+ .issues(DumpableNotRegisteredDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ companion object {
+ private val DUMPABLE_STUB =
+ TestFiles.java(
+ """
+ package com.android.systemui;
+
+ import com.android.systemui.dump.DumpManager;
+ import java.io.PrintWriter;
+
+ public interface Dumpable {
+ void dump();
+ }
+ """
+ )
+ .indented()
+
+ private val DUMP_MANAGER_STUB =
+ TestFiles.java(
+ """
+ package com.android.systemui.dump;
+
+ public interface DumpManager {
+ void registerDumpable(Dumpable module);
+ void registerNormalDumpable(Dumpable module);
+ void registerCriticalDumpable(Dumpable module);
+ }
+ """
+ )
+ .indented()
+
+ private val OTHER_REGISTRATION_OBJECT_STUB =
+ TestFiles.java(
+ """
+ package com.android.systemui;
+
+ public interface OtherRegistrationObject {
+ void registerDumpable(Dumpable module);
+ }
+ """
+ )
+ .indented()
+
+ private val CORE_STARTABLE_STUB =
+ TestFiles.java(
+ """
+ package com.android.systemui;
+
+ public interface CoreStartable {
+ void start();
+ }
+ """
+ )
+ .indented()
+
+ private val stubs =
+ arrayOf(
+ DUMPABLE_STUB,
+ DUMP_MANAGER_STUB,
+ OTHER_REGISTRATION_OBJECT_STUB,
+ CORE_STARTABLE_STUB,
+ )
+ }
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/SystemUiController.kt b/packages/SystemUI/compose/core/src/com/android/compose/SystemUiController.kt
index a02954ab4800..08ab1462b161 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/SystemUiController.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/SystemUiController.kt
@@ -78,11 +78,10 @@ interface SystemUiController {
* Set the status bar color.
*
* @param color The **desired** [Color] to set. This may require modification if running on an
- * API level that only supports white status bar icons.
+ * API level that only supports white status bar icons.
* @param darkIcons Whether dark status bar icons would be preferable.
* @param transformColorForLightContent A lambda which will be invoked to transform [color] if
- * dark icons were requested but are not available. Defaults to applying a black scrim.
- *
+ * dark icons were requested but are not available. Defaults to applying a black scrim.
* @see statusBarDarkContentEnabled
*/
fun setStatusBarColor(
@@ -95,16 +94,15 @@ interface SystemUiController {
* Set the navigation bar color.
*
* @param color The **desired** [Color] to set. This may require modification if running on an
- * API level that only supports white navigation bar icons. Additionally this will be ignored
- * and [Color.Transparent] will be used on API 29+ where gesture navigation is preferred or the
- * system UI automatically applies background protection in other navigation modes.
+ * API level that only supports white navigation bar icons. Additionally this will be ignored
+ * and [Color.Transparent] will be used on API 29+ where gesture navigation is preferred or
+ * the system UI automatically applies background protection in other navigation modes.
* @param darkIcons Whether dark navigation bar icons would be preferable.
* @param navigationBarContrastEnforced Whether the system should ensure that the navigation bar
- * has enough contrast when a fully transparent background is requested. Only supported on API
- * 29+.
+ * has enough contrast when a fully transparent background is requested. Only supported on API
+ * 29+.
* @param transformColorForLightContent A lambda which will be invoked to transform [color] if
- * dark icons were requested but are not available. Defaults to applying a black scrim.
- *
+ * dark icons were requested but are not available. Defaults to applying a black scrim.
* @see navigationBarDarkContentEnabled
* @see navigationBarContrastEnforced
*/
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
index cfc38df08b0a..d4a81f9c765d 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
@@ -255,7 +255,9 @@ fun Expandable(
.onGloballyPositioned {
controller.boundsInComposeViewRoot.value = it.boundsInRoot()
}
- ) { wrappedContent(controller.expandable) }
+ ) {
+ wrappedContent(controller.expandable)
+ }
}
else -> {
val clickModifier =
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt
index edb10c7d392f..767756e17747 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt
@@ -156,9 +156,9 @@ internal class ExpandableControllerImpl(
* Create a [LaunchAnimator.Controller] that is going to be used to drive an activity or dialog
* animation. This controller will:
* 1. Compute the start/end animation state using [boundsInComposeViewRoot] and the location of
- * composeViewRoot on the screen.
+ * composeViewRoot on the screen.
* 2. Update [animatorState] with the current animation state if we are animating, or null
- * otherwise.
+ * otherwise.
*/
private fun launchController(): LaunchAnimator.Controller {
return object : LaunchAnimator.Controller {
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/pager/Pager.kt b/packages/SystemUI/compose/core/src/com/android/compose/pager/Pager.kt
index eb9d62506faa..a80a1f934dab 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/pager/Pager.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/pager/Pager.kt
@@ -86,21 +86,20 @@ object PagerDefaults {
/**
* A horizontally scrolling layout that allows users to flip between items to the left and right.
*
- * @sample com.google.accompanist.sample.pager.HorizontalPagerSample
- *
* @param count the number of pages.
* @param modifier the modifier to apply to this layout.
* @param state the state object to be used to control or observe the pager's state.
* @param reverseLayout reverse the direction of scrolling and layout, when `true` items will be
- * composed from the end to the start and [PagerState.currentPage] == 0 will mean the first item is
- * located at the end.
+ * composed from the end to the start and [PagerState.currentPage] == 0 will mean the first item
+ * is located at the end.
* @param itemSpacing horizontal spacing to add between items.
* @param flingBehavior logic describing fling behavior.
* @param key the scroll position will be maintained based on the key, which means if you add/remove
- * items before the current visible item the item with the given key will be kept as the first
- * visible one.
+ * items before the current visible item the item with the given key will be kept as the first
+ * visible one.
* @param content a block which describes the content. Inside this block you can reference
- * [PagerScope.currentPage] and other properties in [PagerScope].
+ * [PagerScope.currentPage] and other properties in [PagerScope].
+ * @sample com.google.accompanist.sample.pager.HorizontalPagerSample
*/
@ExperimentalPagerApi
@Composable
@@ -134,21 +133,20 @@ fun HorizontalPager(
/**
* A vertically scrolling layout that allows users to flip between items to the top and bottom.
*
- * @sample com.google.accompanist.sample.pager.VerticalPagerSample
- *
* @param count the number of pages.
* @param modifier the modifier to apply to this layout.
* @param state the state object to be used to control or observe the pager's state.
* @param reverseLayout reverse the direction of scrolling and layout, when `true` items will be
- * composed from the bottom to the top and [PagerState.currentPage] == 0 will mean the first item is
- * located at the bottom.
+ * composed from the bottom to the top and [PagerState.currentPage] == 0 will mean the first item
+ * is located at the bottom.
* @param itemSpacing vertical spacing to add between items.
* @param flingBehavior logic describing fling behavior.
* @param key the scroll position will be maintained based on the key, which means if you add/remove
- * items before the current visible item the item with the given key will be kept as the first
- * visible one.
+ * items before the current visible item the item with the given key will be kept as the first
+ * visible one.
* @param content a block which describes the content. Inside this block you can reference
- * [PagerScope.currentPage] and other properties in [PagerScope].
+ * [PagerScope.currentPage] and other properties in [PagerScope].
+ * @sample com.google.accompanist.sample.pager.VerticalPagerSample
*/
@ExperimentalPagerApi
@Composable
@@ -246,7 +244,9 @@ internal fun Pager(
// Constraint the content to be <= than the size of the pager.
.fillParentMaxHeight()
.wrapContentSize()
- ) { pagerScope.content(page) }
+ ) {
+ pagerScope.content(page)
+ }
}
}
} else {
@@ -272,7 +272,9 @@ internal fun Pager(
// Constraint the content to be <= than the size of the pager.
.fillParentMaxWidth()
.wrapContentSize()
- ) { pagerScope.content(page) }
+ ) {
+ pagerScope.content(page)
+ }
}
}
}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/pager/PagerState.kt b/packages/SystemUI/compose/core/src/com/android/compose/pager/PagerState.kt
index 2e6ae78b43c7..1822a68f1e77 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/pager/PagerState.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/pager/PagerState.kt
@@ -198,7 +198,7 @@ class PagerState(
*
* @param page the page to animate to. Must be between 0 and [pageCount] (inclusive).
* @param pageOffset the percentage of the page width to offset, from the start of [page]. Must
- * be in the range 0f..1f.
+ * be in the range 0f..1f.
*/
suspend fun animateScrollToPage(
@IntRange(from = 0) page: Int,
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/pager/SnappingFlingBehavior.kt b/packages/SystemUI/compose/core/src/com/android/compose/pager/SnappingFlingBehavior.kt
index 23122de56758..98140295306a 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/pager/SnappingFlingBehavior.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/pager/SnappingFlingBehavior.kt
@@ -44,11 +44,11 @@ internal object SnappingFlingBehaviorDefaults {
/**
* Create and remember a snapping [FlingBehavior] to be used with [LazyListState].
*
- * TODO: move this to a new module and make it public
- *
* @param lazyListState The [LazyListState] to update.
* @param decayAnimationSpec The decay animation spec to use for decayed flings.
* @param snapAnimationSpec The animation spec to use when snapping.
+ *
+ * TODO: move this to a new module and make it public
*/
@Composable
internal fun rememberSnappingFlingBehavior(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
index 3eeadae5385f..a74e56b6e2f2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
@@ -60,7 +60,7 @@ import com.android.systemui.people.ui.viewmodel.PeopleViewModel
*
* @param viewModel the [PeopleViewModel] that should be composed.
* @param onResult the callback called with the result of this screen. Callers should usually finish
- * the Activity/Fragment/View hosting this Composable once a result is available.
+ * the Activity/Fragment/View hosting this Composable once a result is available.
*/
@Composable
fun PeopleScreen(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt
index 3f590df697cb..0484ff475cdf 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt
@@ -79,7 +79,9 @@ internal fun PeopleScreenEmpty(
containerColor = androidColors.colorAccentPrimary,
contentColor = androidColors.textColorOnAccent,
)
- ) { Text(stringResource(R.string.got_it)) }
+ ) {
+ Text(stringResource(R.string.got_it))
+ }
}
}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index ab36d5899739..00c0a0b3e7b3 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -38,6 +38,7 @@ import kotlinx.coroutines.launch
private val TAG = ClockRegistry::class.simpleName!!
private const val DEBUG = true
+private val KEY_TIMESTAMP = "appliedTimestamp"
/** ClockRegistry aggregates providers and plugins */
open class ClockRegistry(
@@ -134,9 +135,9 @@ open class ClockRegistry(
assertNotMainThread()
try {
- value?._applied_timestamp = System.currentTimeMillis()
- val json = ClockSettings.serialize(value)
+ value?.metadata?.put(KEY_TIMESTAMP, System.currentTimeMillis())
+ val json = ClockSettings.serialize(value)
if (handleAllUsers) {
Settings.Secure.putStringForUser(
context.contentResolver,
@@ -172,7 +173,7 @@ open class ClockRegistry(
clockChangeListeners.forEach(func)
}
- private fun mutateSetting(mutator: (ClockSettings) -> ClockSettings) {
+ public fun mutateSetting(mutator: (ClockSettings) -> ClockSettings) {
scope.launch(bgDispatcher) { applySettings(mutator(settings ?: ClockSettings())) }
}
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 2a40f5c70420..4df7a44d3e1d 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
@@ -95,7 +95,7 @@ class DefaultClockController(
open inner class DefaultClockFaceController(
override val view: AnimatableClockView,
- val seedColor: Int?,
+ var seedColor: Int?,
) : ClockFaceController {
// MAGENTA is a placeholder, and will be assigned correctly in initialize
@@ -111,9 +111,9 @@ class DefaultClockController(
init {
if (seedColor != null) {
- currentColor = seedColor
+ currentColor = seedColor!!
}
- view.setColors(currentColor, currentColor)
+ view.setColors(DOZE_COLOR, currentColor)
}
override val events =
@@ -141,7 +141,7 @@ class DefaultClockController(
fun updateColor() {
val color =
if (seedColor != null) {
- seedColor
+ seedColor!!
} else if (isRegionDark) {
resources.getColor(android.R.color.system_accent1_100)
} else {
@@ -194,6 +194,14 @@ class DefaultClockController(
smallClock.updateColor()
}
+ override fun onSeedColorChanged(seedColor: Int?) {
+ largeClock.seedColor = seedColor
+ smallClock.seedColor = seedColor
+
+ largeClock.updateColor()
+ smallClock.updateColor()
+ }
+
override fun onLocaleChanged(locale: Locale) {
val nf = NumberFormat.getInstance(locale)
if (nf.format(FORMAT_NUMBER.toLong()) == burmeseNumerals) {
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
index c120876a7a63..0d880759bd09 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
@@ -51,7 +51,7 @@ object CustomizationProviderContract {
*
* Supported operations:
* - Query - to know which slots are available, query the [SlotTable.URI] [Uri]. The result
- * set will contain rows with the [SlotTable.Columns] columns.
+ * set will contain rows with the [SlotTable.Columns] columns.
*/
object SlotTable {
const val TABLE_NAME = "slots"
@@ -74,8 +74,8 @@ object CustomizationProviderContract {
*
* Supported operations:
* - Query - to know about all the affordances that are available on the device, regardless
- * of which ones are currently selected, query the [AffordanceTable.URI] [Uri]. The result
- * set will contain rows, each with the columns specified in [AffordanceTable.Columns].
+ * of which ones are currently selected, query the [AffordanceTable.URI] [Uri]. The result
+ * set will contain rows, each with the columns specified in [AffordanceTable.Columns].
*/
object AffordanceTable {
const val TABLE_NAME = "affordances"
@@ -128,14 +128,14 @@ object CustomizationProviderContract {
*
* Supported operations:
* - Insert - to insert an affordance and place it in a slot, insert values for the columns
- * into the [SelectionTable.URI] [Uri]. The maximum capacity rule is enforced by the system.
- * Selecting a new affordance for a slot that is already full will automatically remove the
- * oldest affordance from the slot.
+ * into the [SelectionTable.URI] [Uri]. The maximum capacity rule is enforced by the
+ * system. Selecting a new affordance for a slot that is already full will automatically
+ * remove the oldest affordance from the slot.
* - Query - to know which affordances are set on which slots, query the
- * [SelectionTable.URI] [Uri]. The result set will contain rows, each of which with the
- * columns from [SelectionTable.Columns].
+ * [SelectionTable.URI] [Uri]. The result set will contain rows, each of which with the
+ * columns from [SelectionTable.Columns].
* - Delete - to unselect an affordance, removing it from a slot, delete from the
- * [SelectionTable.URI] [Uri], passing in values for each column.
+ * [SelectionTable.URI] [Uri], passing in values for each column.
*/
object SelectionTable {
const val TABLE_NAME = "selections"
@@ -160,7 +160,7 @@ object CustomizationProviderContract {
*
* Supported operations:
* - Query - to know the values of flags, query the [FlagsTable.URI] [Uri]. The result set will
- * contain rows, each of which with the columns from [FlagsTable.Columns].
+ * contain rows, each of which with the columns from [FlagsTable.Columns].
*/
object FlagsTable {
const val TABLE_NAME = "flags"
diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt
index 943d7996dd89..8a6fc5dc53f1 100644
--- a/packages/SystemUI/ktfmt_includes.txt
+++ b/packages/SystemUI/ktfmt_includes.txt
@@ -1,28 +1,20 @@
+packages/SystemUI
-packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
-packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
--packages/SystemUI/checks/src/com/android/internal/systemui/lint/BindServiceViaContextDetector.kt
-packages/SystemUI/checks/src/com/android/internal/systemui/lint/BroadcastSentViaContextDetector.kt
--packages/SystemUI/checks/src/com/android/internal/systemui/lint/GetMainLooperViaContextDetector.kt
-packages/SystemUI/checks/src/com/android/internal/systemui/lint/RegisterReceiverViaContextDetector.kt
-packages/SystemUI/checks/src/com/android/internal/systemui/lint/SoftwareBitmapDetector.kt
--packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
--packages/SystemUI/checks/tests/com/android/systemui/lint/BindServiceViaContextDetectorTest.kt
--packages/SystemUI/checks/tests/com/android/systemui/lint/BroadcastSentViaContextDetectorTest.kt
--packages/SystemUI/checks/tests/com/android/systemui/lint/GetMainLooperViaContextDetectorTest.kt
--packages/SystemUI/checks/tests/com/android/systemui/lint/RegisterReceiverViaContextDetectorTest.kt
--packages/SystemUI/checks/tests/com/android/systemui/lint/SoftwareBitmapDetectorTest.kt
+-packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+-packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
-packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
--packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainerController.kt
+-packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/View.kt
-packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
-packages/SystemUI/shared/src/com/android/systemui/flags/FlagListenable.kt
-packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
-packages/SystemUI/shared/src/com/android/systemui/flags/FlagSerializer.kt
-packages/SystemUI/shared/src/com/android/systemui/flags/FlagSettingsHelper.kt
-packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
+-packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionDarkness.kt
-packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonPositionCalculator.kt
-packages/SystemUI/shared/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerManager.kt
-packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt
@@ -35,8 +27,6 @@
-packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt
-packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
-packages/SystemUI/src/com/android/keyguard/KeyguardBiometricLockoutLogger.kt
--packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
--packages/SystemUI/src/com/android/keyguard/KeyguardListenQueue.kt
-packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
-packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherAnchor.kt
-packages/SystemUI/src/com/android/keyguard/clock/ClockPalette.kt
@@ -65,12 +55,10 @@
-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricIconController.kt
-packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
-packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
-packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt
-packages/SystemUI/src/com/android/systemui/biometrics/DwellRippleShader.kt
--packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt
-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.kt
-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt
@@ -80,7 +68,6 @@
-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.kt
-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.kt
-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsHapticsSimulator.kt
--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt
-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
-packages/SystemUI/src/com/android/systemui/biometrics/Utils.kt
@@ -93,8 +80,6 @@
-packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
-packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt
-packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
--packages/SystemUI/src/com/android/systemui/camera/CameraIntents.kt
--packages/SystemUI/src/com/android/systemui/camera/CameraIntentsWrapper.kt
-packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt
-packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt
-packages/SystemUI/src/com/android/systemui/controls/ControlsMetricsLogger.kt
@@ -102,7 +87,6 @@
-packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt
-packages/SystemUI/src/com/android/systemui/controls/CustomIconCache.kt
-packages/SystemUI/src/com/android/systemui/controls/TooltipManager.kt
--packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt
-packages/SystemUI/src/com/android/systemui/controls/controller/ControlInfo.kt
-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
@@ -132,6 +116,7 @@
-packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt
-packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt
-packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
+-packages/SystemUI/src/com/android/systemui/controls/start/ControlsStartable.kt
-packages/SystemUI/src/com/android/systemui/controls/ui/Behavior.kt
-packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
-packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
@@ -162,7 +147,6 @@
-packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderImpl.kt
-packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
-packages/SystemUI/src/com/android/systemui/demomode/DemoModeAvailabilityTracker.kt
--packages/SystemUI/src/com/android/systemui/demomode/DemoModeController.kt
-packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
-packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
-packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt
@@ -172,20 +156,16 @@
-packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt
-packages/SystemUI/src/com/android/systemui/dump/LogBufferFreezer.kt
-packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt
+-packages/SystemUI/src/com/android/systemui/flags/Flags.kt
-packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt
-packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
-packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
--packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
+-packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt
+-packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt
+-packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartable.kt
+-packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
-packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
--packages/SystemUI/src/com/android/systemui/log/LogLevel.kt
--packages/SystemUI/src/com/android/systemui/log/LogMessage.kt
--packages/SystemUI/src/com/android/systemui/log/LogMessageImpl.kt
--packages/SystemUI/src/com/android/systemui/log/LogcatEchoTracker.kt
--packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt
--packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerProd.kt
--packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
-packages/SystemUI/src/com/android/systemui/media/MediaProjectionCaptureTarget.kt
--packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt
-packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogFactory.kt
-packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
-packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
@@ -202,6 +182,11 @@
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLogger.kt
+-packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt
+-packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
+-packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionTaskView.kt
+-packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTasksAdapter.kt
+-packages/SystemUI/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolver.kt
-packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt
-packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
-packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt
@@ -220,8 +205,6 @@
-packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
-packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt
-packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
--packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
--packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
-packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt
-packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt
-packages/SystemUI/src/com/android/systemui/qs/QSExpansionPathInterpolator.kt
@@ -237,7 +220,6 @@
-packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialog.kt
-packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialogEventLogger.kt
-packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt
--packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
-packages/SystemUI/src/com/android/systemui/qs/tileimpl/HeightOverrideable.kt
-packages/SystemUI/src/com/android/systemui/qs/tileimpl/IgnorableChildLinearLayout.kt
-packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -245,10 +227,6 @@
-packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
-packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
-packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
--packages/SystemUI/src/com/android/systemui/ripple/RippleShader.kt
--packages/SystemUI/src/com/android/systemui/ripple/RippleShaderUtilLibrary.kt
--packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt
--packages/SystemUI/src/com/android/systemui/ripple/SdfShaderLibrary.kt
-packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
-packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
-packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt
@@ -259,23 +237,21 @@
-packages/SystemUI/src/com/android/systemui/settings/UserContentResolverProvider.kt
-packages/SystemUI/src/com/android/systemui/settings/UserContextProvider.kt
-packages/SystemUI/src/com/android/systemui/settings/UserFileManager.kt
--packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt
-packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
-packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
-packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessMirrorHandler.kt
-packages/SystemUI/src/com/android/systemui/settings/brightness/MirroredBrightnessController.kt
-packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManager.kt
-packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt
--packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
-packages/SystemUI/src/com/android/systemui/shade/NPVCDownEventState.kt
--packages/SystemUI/src/com/android/systemui/shade/NotifPanelEvents.kt
-packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
-packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
-packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
+-packages/SystemUI/src/com/android/systemui/shade/ShadeHeightLogger.kt
-packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
+-packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
-packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
-packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt
--packages/SystemUI/src/com/android/systemui/shade/transition/SplitShadeOverScroller.kt
-packages/SystemUI/src/com/android/systemui/smartspace/SmartspacePrecondition.kt
-packages/SystemUI/src/com/android/systemui/smartspace/SmartspaceTargetFilter.kt
-packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
@@ -284,10 +260,8 @@
-packages/SystemUI/src/com/android/systemui/smartspace/preconditions/LockscreenPrecondition.kt
-packages/SystemUI/src/com/android/systemui/statusbar/AbstractLockscreenShadeTransitionController.kt
-packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBarWifiView.kt
-packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
-packages/SystemUI/src/com/android/systemui/statusbar/DisableFlagsLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
-packages/SystemUI/src/com/android/systemui/statusbar/LockScreenShadeOverScroller.kt
-packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionController.kt
-packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeScrimTransitionController.kt
@@ -311,10 +285,12 @@
-packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
-packages/SystemUI/src/com/android/systemui/statusbar/dagger/StartCentralSurfacesModule.kt
-packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/events/StatusBarEventsModule.kt
-packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
-packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
-packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
-packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt
-packages/SystemUI/src/com/android/systemui/statusbar/gesture/GenericGestureDetector.kt
-packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureHandler.kt
-packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt
@@ -325,7 +301,6 @@
-packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.kt
@@ -396,6 +371,9 @@
-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/fsi/FsiChromeViewBinder.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/fsi/FsiDebug.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/fsi/FsiTaskViewConfig.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconBuilder.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -403,6 +381,7 @@
-packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryViewWalker.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/people/NotificationPersonExtractor.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/people/ViewPipeline.kt
@@ -444,13 +423,10 @@
-packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
-packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallFlags.kt
-packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/ShadeStateListener.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserInfoTracker.kt
-packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherFeatureController.kt
-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/ConnectivitySlots.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
-packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt
-packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsController.kt
-packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImpl.kt
@@ -470,19 +446,17 @@
-packages/SystemUI/src/com/android/systemui/statusbar/tv/VpnStatusObserver.kt
-packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt
-packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt
--packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
-packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
+-packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
-packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarRootView.kt
-packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt
-packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
-packages/SystemUI/src/com/android/systemui/tv/TVSystemUICoreStartableModule.kt
+-packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
-packages/SystemUI/src/com/android/systemui/unfold/FoldStateLogger.kt
-packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
--packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt
--packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
-packages/SystemUI/src/com/android/systemui/unfold/UnfoldProgressProvider.kt
-packages/SystemUI/src/com/android/systemui/user/UserCreator.kt
--packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
-packages/SystemUI/src/com/android/systemui/user/UserSwitcherPopupMenu.kt
-packages/SystemUI/src/com/android/systemui/user/UserSwitcherRootView.kt
-packages/SystemUI/src/com/android/systemui/util/AsyncActivityLauncher.kt
@@ -509,7 +483,6 @@
-packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
-packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
-packages/SystemUI/src/com/android/systemui/util/animation/UniqueObjectHostView.kt
--packages/SystemUI/src/com/android/systemui/util/collection/RingBuffer.kt
-packages/SystemUI/src/com/android/systemui/util/concurrency/Execution.kt
-packages/SystemUI/src/com/android/systemui/util/concurrency/PendingTasksContainer.kt
-packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt
@@ -517,6 +490,7 @@
-packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
-packages/SystemUI/src/com/android/systemui/util/kotlin/IpcSerializer.kt
-packages/SystemUI/src/com/android/systemui/util/kotlin/nullability.kt
+-packages/SystemUI/src/com/android/systemui/util/recycler/HorizontalSpacerItemDecoration.kt
-packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt
-packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
-packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialogReceiver.kt
@@ -525,7 +499,6 @@
-packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt
-packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
-packages/SystemUI/tests/src/com/android/keyguard/KeyguardBiometricLockoutLoggerTest.kt
--packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
-packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
-packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
-packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
@@ -550,7 +523,6 @@
-packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
-packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
--packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
-packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
-packages/SystemUI/tests/src/com/android/systemui/broadcast/ActionReceiverTest.kt
@@ -569,7 +541,6 @@
-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt
-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt
-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt
-packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt
-packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt
@@ -579,8 +550,8 @@
-packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestDialogTest.kt
-packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt
-packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/management/TestControlsRequestDialog.kt
-packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
-packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
-packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt
-packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt
@@ -596,13 +567,16 @@
-packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt
-packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartableTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
-packages/SystemUI/tests/src/com/android/systemui/lifecycle/InstantTaskExecutorRule.kt
--packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt
-packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt
-packages/SystemUI/tests/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt
-packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyChipBuilderTest.kt
@@ -610,7 +584,6 @@
-packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogTest.kt
-packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/qs/QSContainerImplTest.kt
-packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
@@ -641,36 +614,29 @@
-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt
-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt
-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
-packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/ripple/RippleViewTest.kt
-packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordDialogTest.kt
-packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
-packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
--packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt
-packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
-packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shade/transition/SplitShadeOverScrollerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
-packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
-packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt
-packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt
-packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/DisableFlagsLoggerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -683,10 +649,12 @@
-packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/CommandRegistryTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
@@ -719,7 +687,6 @@
-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
@@ -733,8 +700,7 @@
-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLoggerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/ShadeExpansionStateManagerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherControllerOldImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt
@@ -744,7 +710,6 @@
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImplTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
@@ -753,40 +718,36 @@
-packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt
--packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
-packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
-packages/SystemUI/tests/src/com/android/systemui/unfold/util/FoldableTestUtils.kt
--packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt
-packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
-packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
-packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
-packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
-packages/SystemUI/tests/src/com/android/systemui/util/FakeSharedPreferencesTest.kt
-packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
-packages/SystemUI/tests/src/com/android/systemui/util/ListenerSetTest.kt
-packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt
-packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
--packages/SystemUI/tests/src/com/android/systemui/util/collection/RingBufferTest.kt
-packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
-packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
-packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
-packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt
--packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
-packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
-packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSharedPreferences.kt
-packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
-packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
-packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+-packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt
-packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt
-packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/SizeScreenStatusProvider.kt
-packages/SystemUI/unfold/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
--packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldBackground.kt
-packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldMain.kt
+-packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
-packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
-packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
-packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
--packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
-packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
--packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
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 ab4aca569bd4..babe5700a01c 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -112,6 +112,9 @@ interface ClockEvents {
/** Call whenever the color palette should update */
fun onColorPaletteChanged(resources: Resources) {}
+ /** Call if the seed color has changed and should be updated */
+ fun onSeedColorChanged(seedColor: Int?) {}
+
/** Call whenever the weather data should update */
fun onWeatherDataChanged(data: WeatherData) {}
}
@@ -189,12 +192,13 @@ data class ClockSettings(
val clockId: ClockId? = null,
val seedColor: Int? = null,
) {
- var _applied_timestamp: Long? = null
+ // Exclude metadata from equality checks
+ var metadata: JSONObject = JSONObject()
companion object {
private val KEY_CLOCK_ID = "clockId"
private val KEY_SEED_COLOR = "seedColor"
- private val KEY_TIMESTAMP = "_applied_timestamp"
+ private val KEY_METADATA = "metadata"
fun serialize(setting: ClockSettings?): String {
if (setting == null) {
@@ -204,7 +208,7 @@ data class ClockSettings(
return JSONObject()
.put(KEY_CLOCK_ID, setting.clockId)
.put(KEY_SEED_COLOR, setting.seedColor)
- .put(KEY_TIMESTAMP, setting._applied_timestamp)
+ .put(KEY_METADATA, setting.metadata)
.toString()
}
@@ -216,11 +220,11 @@ data class ClockSettings(
val json = JSONObject(jsonStr)
val result =
ClockSettings(
- json.getString(KEY_CLOCK_ID),
+ if (!json.isNull(KEY_CLOCK_ID)) json.getString(KEY_CLOCK_ID) else null,
if (!json.isNull(KEY_SEED_COLOR)) json.getInt(KEY_SEED_COLOR) else null
)
- if (!json.isNull(KEY_TIMESTAMP)) {
- result._applied_timestamp = json.getLong(KEY_TIMESTAMP)
+ if (!json.isNull(KEY_METADATA)) {
+ result.metadata = json.getJSONObject(KEY_METADATA)
}
return result
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt
index e99b2149bc1d..3e34885a6d9c 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt
@@ -35,7 +35,6 @@ import kotlin.math.max
* as the result of taking a bug report).
*
* You can dump the entire buffer at any time by running:
- *
* ```
* $ adb shell dumpsys activity service com.android.systemui/.SystemUIService <bufferName>
* ```
@@ -46,13 +45,11 @@ import kotlin.math.max
* locally (usually for debugging purposes).
*
* To enable logcat echoing for an entire buffer:
- *
* ```
* $ adb shell settings put global systemui/buffer/<bufferName> <level>
* ```
*
* To enable logcat echoing for a specific tag:
- *
* ```
* $ adb shell settings put global systemui/tag/<tag> <level>
* ```
@@ -64,10 +61,10 @@ import kotlin.math.max
* LogBufferFactory.
*
* @param name The name of this buffer, printed when the buffer is dumped and in some other
- * situations.
+ * situations.
* @param maxSize The maximum number of messages to keep in memory at any one time. Buffers start
- * out empty and grow up to [maxSize] as new messages are logged. Once the buffer's size reaches the
- * maximum, it behaves like a ring buffer.
+ * out empty and grow up to [maxSize] as new messages are logged. Once the buffer's size reaches
+ * the maximum, it behaves like a ring buffer.
*/
class LogBuffer
@JvmOverloads
@@ -116,22 +113,22 @@ constructor(
* initializer stored and converts it to a human-readable log message.
*
* @param tag A string of at most 23 characters, used for grouping logs into categories or
- * subjects. If this message is echoed to logcat, this will be the tag that is used.
+ * subjects. If this message is echoed to logcat, this will be the tag that is used.
* @param level Which level to log the message at, both to the buffer and to logcat if it's
- * echoed. In general, a module should split most of its logs into either INFO or DEBUG level.
- * INFO level should be reserved for information that other parts of the system might care
- * about, leaving the specifics of code's day-to-day operations to DEBUG.
+ * echoed. In general, a module should split most of its logs into either INFO or DEBUG level.
+ * INFO level should be reserved for information that other parts of the system might care
+ * about, leaving the specifics of code's day-to-day operations to DEBUG.
* @param messageInitializer A function that will be called immediately to store relevant data
- * on the log message. The value of `this` will be the LogMessage to be initialized.
+ * on the log message. The value of `this` will be the LogMessage to be initialized.
* @param messagePrinter A function that will be called if and when the message needs to be
- * dumped to logcat or a bug report. It should read the data stored by the initializer and
- * convert it to a human-readable string. The value of `this` will be the LogMessage to be
- * printed. **IMPORTANT:** The printer should ONLY ever reference fields on the LogMessage and
- * NEVER any variables in its enclosing scope. Otherwise, the runtime will need to allocate a
- * new instance of the printer for each call, thwarting our attempts at avoiding any sort of
- * allocation.
+ * dumped to logcat or a bug report. It should read the data stored by the initializer and
+ * convert it to a human-readable string. The value of `this` will be the LogMessage to be
+ * printed. **IMPORTANT:** The printer should ONLY ever reference fields on the LogMessage and
+ * NEVER any variables in its enclosing scope. Otherwise, the runtime will need to allocate a
+ * new instance of the printer for each call, thwarting our attempts at avoiding any sort of
+ * allocation.
* @param exception Provide any exception that need to be logged. This is saved as
- * [LogMessage.exception]
+ * [LogMessage.exception]
*/
@JvmOverloads
inline fun log(
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt
index faf1b78c598d..7a125ac14ea1 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt
@@ -28,7 +28,6 @@ import android.provider.Settings
* Version of [LogcatEchoTracker] for debuggable builds
*
* The log level of individual buffers or tags can be controlled via global settings:
- *
* ```
* # Echo any message to <bufferName> of <level> or higher
* $ adb shell settings put global systemui/buffer/<bufferName> <level>
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/util/RingBuffer.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/util/RingBuffer.kt
index 68d78907f028..4773f54a079e 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/util/RingBuffer.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/util/RingBuffer.kt
@@ -30,7 +30,7 @@ import kotlin.math.max
*
* @param maxSize The maximum size the buffer can grow to before it begins functioning as a ring.
* @param factory A function that creates a fresh instance of T. Used by the buffer while it's
- * growing to [maxSize].
+ * growing to [maxSize].
*/
class RingBuffer<T>(private val maxSize: Int, private val factory: () -> T) : Iterable<T> {
diff --git a/packages/SystemUI/res-keyguard/drawable-mdpi/ic_lockscreen_sim.png b/packages/SystemUI/res-keyguard/drawable-mdpi/ic_lockscreen_sim.png
deleted file mode 100644
index 2e259c3e17c1..000000000000
--- a/packages/SystemUI/res-keyguard/drawable-mdpi/ic_lockscreen_sim.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable-xhdpi/ic_lockscreen_sim.png b/packages/SystemUI/res-keyguard/drawable-xhdpi/ic_lockscreen_sim.png
deleted file mode 100644
index f4de96adae30..000000000000
--- a/packages/SystemUI/res-keyguard/drawable-xhdpi/ic_lockscreen_sim.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable-hdpi/ic_lockscreen_sim.png b/packages/SystemUI/res-keyguard/drawable/ic_lockscreen_sim.png
index 7cf9e3699ceb..7cf9e3699ceb 100644
--- a/packages/SystemUI/res-keyguard/drawable-hdpi/ic_lockscreen_sim.png
+++ b/packages/SystemUI/res-keyguard/drawable/ic_lockscreen_sim.png
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml b/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
index 411fea5dd22d..48769fdebd99 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
@@ -14,10 +14,12 @@
~ limitations under the License
-->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
+<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<TextView
android:id="@+id/digit_text"
style="@style/Widget.TextView.NumPadKey.Digit"
+ android:autoSizeMaxTextSize="32sp"
+ android:autoSizeTextType="uniform"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
index 7db0fe908ec0..728d861ab693 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
**
** Copyright 2012, The Android Open Source Project
**
@@ -17,185 +16,185 @@
*/
-->
<!-- This is the SIM PIN view that allows the user to enter a SIM PIN to unlock the device. -->
-<com.android.keyguard.KeyguardSimPinView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/res-auto"
- android:id="@+id/keyguard_sim_pin_view"
- android:orientation="vertical"
+<com.android.keyguard.KeyguardSimPinView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/res-auto"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/keyguard_sim_pin_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ androidprv:layout_maxWidth="@dimen/keyguard_security_width"
+ android:layout_gravity="center_horizontal|bottom">
+ <include layout="@layout/keyguard_bouncer_message_area"/>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
- androidprv:layout_maxWidth="@dimen/keyguard_security_width"
- android:layout_gravity="center_horizontal|bottom">
- <include layout="@layout/keyguard_bouncer_message_area" />
- <Space
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1" />
- <ImageView
- android:id="@+id/keyguard_sim"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:tint="@color/background_protected"
- android:src="@drawable/ic_lockscreen_sim"/>
- <LinearLayout
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:layoutDirection="ltr">
+ <LinearLayout
+ android:id="@+id/pin_area"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:gravity="center"
- android:layoutDirection="ltr"
- >
- <include layout="@layout/keyguard_esim_area"
- android:id="@+id/keyguard_esim_area"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <RelativeLayout
- android:id="@+id/row0"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingBottom="4dp"
- >
+ android:gravity="center_horizontal"
+ android:paddingTop="@dimen/num_pad_entry_row_margin_bottom"
+ android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
+ androidprv:layout_constraintBottom_toTopOf="@+id/flow1"
+ androidprv:layout_constraintEnd_toEndOf="parent"
+ androidprv:layout_constraintStart_toStartOf="parent"
+ androidprv:layout_constraintTop_toTopOf="parent">
+
+ <ImageView
+ android:id="@+id/keyguard_sim"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:layout_gravity="center_horizontal"
+ android:src="@drawable/ic_lockscreen_sim"
+ app:tint="@color/background_protected" />
+
+ <include
+ android:id="@+id/keyguard_esim_area"
+ layout="@layout/keyguard_esim_area"
+ android:layout_gravity="center_horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
<com.android.keyguard.PasswordTextView
android:id="@+id/simPinEntry"
style="@style/Widget.TextView.Password"
android:layout_width="@dimen/keyguard_security_width"
android:layout_height="@dimen/keyguard_password_height"
- android:layout_centerHorizontal="true"
- android:layout_marginRight="72dp"
android:contentDescription="@string/keyguard_accessibility_sim_pin_area"
- android:gravity="center"
- androidprv:scaledTextSize="@integer/scaled_password_text_size" />
- </RelativeLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
android:layout_gravity="center_horizontal"
- android:layout_marginBottom="@dimen/num_pad_row_margin_bottom"
- >
- <com.android.keyguard.NumPadKey
- android:id="@+id/key1"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/simPinEntry"
- androidprv:digit="1"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key2"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/simPinEntry"
- androidprv:digit="2"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key3"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- androidprv:textView="@+id/simPinEntry"
- androidprv:digit="3"
- />
- </LinearLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="@dimen/num_pad_row_margin_bottom"
- >
- <com.android.keyguard.NumPadKey
- android:id="@+id/key4"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/simPinEntry"
- androidprv:digit="4"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key5"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/simPinEntry"
- androidprv:digit="5"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key6"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- androidprv:textView="@+id/simPinEntry"
- androidprv:digit="6"
- />
- </LinearLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="@dimen/num_pad_row_margin_bottom"
- >
- <com.android.keyguard.NumPadKey
- android:id="@+id/key7"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/simPinEntry"
- androidprv:digit="7"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key8"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/simPinEntry"
- androidprv:digit="8"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key9"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- androidprv:textView="@+id/simPinEntry"
- androidprv:digit="9"
- />
- </LinearLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="center_horizontal"
- >
- <com.android.keyguard.NumPadButton
- android:id="@+id/delete_button"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- android:contentDescription="@string/keyboardview_keycode_delete"
- style="@style/NumPadKey.Delete"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key0"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/simPinEntry"
- androidprv:digit="0"
- />
- <com.android.keyguard.NumPadButton
- android:id="@+id/key_enter"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- style="@style/NumPadKey.Enter"
- android:contentDescription="@string/keyboardview_keycode_enter"
- />
+ androidprv:scaledTextSize="@integer/scaled_password_text_size" />
</LinearLayout>
- </LinearLayout>
- <include layout="@layout/keyguard_eca"
- android:id="@+id/keyguard_selector_fade_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_gravity="bottom|center_horizontal"
- android:layout_marginTop="@dimen/keyguard_eca_top_margin"
- android:layout_marginBottom="2dp"
- android:gravity="center_horizontal"/>
+
+ <androidx.constraintlayout.helper.widget.Flow
+ android:id="@+id/flow1"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:orientation="horizontal"
+ androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
+ androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end"
+ androidprv:flow_horizontalStyle="packed"
+ androidprv:flow_maxElementsWrap="3"
+ androidprv:flow_verticalBias="1.0"
+ androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
+ androidprv:flow_verticalStyle="packed"
+ androidprv:flow_wrapMode="aligned"
+ androidprv:layout_constraintBottom_toBottomOf="parent"
+ androidprv:layout_constraintEnd_toEndOf="parent"
+ androidprv:layout_constraintStart_toStartOf="parent"
+ androidprv:layout_constraintTop_toBottomOf="@id/pin_area" />
+
+ <com.android.keyguard.NumPadButton
+ android:id="@+id/delete_button"
+ style="@style/NumPadKey.Delete"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key0"
+ android:contentDescription="@string/keyboardview_keycode_delete" />
+
+ <com.android.keyguard.NumPadButton
+ android:id="@+id/key_enter"
+ style="@style/NumPadKey.Enter"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:contentDescription="@string/keyboardview_keycode_enter" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key1"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key2"
+ androidprv:digit="1"
+ androidprv:textView="@+id/simPinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key2"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key3"
+ androidprv:digit="2"
+ androidprv:textView="@+id/simPinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key3"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key4"
+ androidprv:digit="3"
+ androidprv:textView="@+id/simPinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key4"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key5"
+ androidprv:digit="4"
+ androidprv:textView="@+id/simPinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key5"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key6"
+ androidprv:digit="5"
+ androidprv:textView="@+id/simPinEntry" />
+
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key6"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key7"
+ androidprv:digit="6"
+ androidprv:textView="@+id/simPinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key7"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key8"
+ androidprv:digit="7"
+ androidprv:textView="@+id/simPinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key8"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key9"
+ androidprv:digit="8"
+ androidprv:textView="@+id/simPinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key9"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/delete_button"
+ androidprv:digit="9"
+ androidprv:textView="@+id/simPinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key0"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key_enter"
+ androidprv:digit="0"
+ androidprv:textView="@+id/simPinEntry" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <include
+ android:id="@+id/keyguard_selector_fade_container"
+ layout="@layout/keyguard_eca"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|center_horizontal"
+ android:layout_marginBottom="2dp"
+ android:layout_marginTop="@dimen/keyguard_eca_top_margin"
+ android:gravity="center_horizontal"
+ android:orientation="vertical" />
</com.android.keyguard.KeyguardSimPinView>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
index 422bd4c12e8e..7e24d1231aee 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
@@ -21,6 +21,7 @@
<com.android.keyguard.KeyguardSimPukView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/res-auto"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/keyguard_sim_puk_view"
android:orientation="vertical"
android:layout_width="match_parent"
@@ -29,173 +30,165 @@
android:layout_gravity="center_horizontal|bottom">
<include layout="@layout/keyguard_bouncer_message_area"/>
- <Space
+ <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="0dp"
- android:layout_weight="1" />
-
- <ImageView
- android:id="@+id/keyguard_sim"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:tint="@color/background_protected"
- android:src="@drawable/ic_lockscreen_sim"/>
-
- <LinearLayout
+ android:layout_weight="1"
+ android:layoutDirection="ltr">
+ <LinearLayout
+ android:id="@+id/pin_area"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:gravity="center"
- android:layoutDirection="ltr"
- >
- <include layout="@layout/keyguard_esim_area"
- android:id="@+id/keyguard_esim_area"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- <RelativeLayout
- android:id="@+id/row0"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingBottom="4dp"
- >
+ android:gravity="center_horizontal"
+ android:paddingTop="@dimen/num_pad_entry_row_margin_bottom"
+ android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
+ androidprv:layout_constraintBottom_toTopOf="@+id/flow1"
+ androidprv:layout_constraintEnd_toEndOf="parent"
+ androidprv:layout_constraintStart_toStartOf="parent"
+ androidprv:layout_constraintTop_toTopOf="parent">
+
+ <ImageView
+ android:id="@+id/keyguard_sim"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:layout_gravity="center_horizontal"
+ android:src="@drawable/ic_lockscreen_sim"
+ app:tint="@color/background_protected" />
+
+ <include
+ android:id="@+id/keyguard_esim_area"
+ layout="@layout/keyguard_esim_area"
+ android:layout_gravity="center_horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
<com.android.keyguard.PasswordTextView
android:id="@+id/pukEntry"
style="@style/Widget.TextView.Password"
android:layout_width="@dimen/keyguard_security_width"
android:layout_height="@dimen/keyguard_password_height"
- android:layout_centerHorizontal="true"
- android:layout_marginRight="72dp"
- android:contentDescription="@string/keyguard_accessibility_sim_puk_area"
- android:gravity="center"
- androidprv:scaledTextSize="@integer/scaled_password_text_size" />
- </RelativeLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="@dimen/num_pad_row_margin_bottom"
- >
- <com.android.keyguard.NumPadKey
- android:id="@+id/key1"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pukEntry"
- androidprv:digit="1"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key2"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pukEntry"
- androidprv:digit="2"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key3"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- androidprv:textView="@+id/pukEntry"
- androidprv:digit="3"
- />
- </LinearLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="@dimen/num_pad_row_margin_bottom"
-
- >
- <com.android.keyguard.NumPadKey
- android:id="@+id/key4"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pukEntry"
- androidprv:digit="4"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key5"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pukEntry"
- androidprv:digit="5"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key6"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- androidprv:textView="@+id/pukEntry"
- androidprv:digit="6"
- />
- </LinearLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="@dimen/num_pad_row_margin_bottom"
- >
- <com.android.keyguard.NumPadKey
- android:id="@+id/key7"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pukEntry"
- androidprv:digit="7"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key8"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pukEntry"
- androidprv:digit="8"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key9"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- androidprv:textView="@+id/pukEntry"
- androidprv:digit="9"
- />
- </LinearLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
+ android:contentDescription="@string/keyguard_accessibility_sim_pin_area"
android:layout_gravity="center_horizontal"
- >
- <com.android.keyguard.NumPadButton
- android:id="@+id/delete_button"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- android:contentDescription="@string/keyboardview_keycode_delete"
- style="@style/NumPadKey.Delete"
- />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key0"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/num_pad_key_margin_end"
- androidprv:textView="@+id/pukEntry"
- androidprv:digit="0"
- />
- <com.android.keyguard.NumPadButton
- android:id="@+id/key_enter"
- android:layout_width="@dimen/num_pad_key_width"
- android:layout_height="match_parent"
- style="@style/NumPadKey.Enter"
- android:contentDescription="@string/keyboardview_keycode_enter"
- />
+ androidprv:scaledTextSize="@integer/scaled_password_text_size" />
</LinearLayout>
- </LinearLayout>
+
+ <androidx.constraintlayout.helper.widget.Flow
+ android:id="@+id/flow1"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:orientation="horizontal"
+ androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
+ androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end"
+ androidprv:flow_horizontalStyle="packed"
+ androidprv:flow_maxElementsWrap="3"
+ androidprv:flow_verticalBias="1.0"
+ androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
+ androidprv:flow_verticalStyle="packed"
+ androidprv:flow_wrapMode="aligned"
+ androidprv:layout_constraintBottom_toBottomOf="parent"
+ androidprv:layout_constraintEnd_toEndOf="parent"
+ androidprv:layout_constraintStart_toStartOf="parent"
+ androidprv:layout_constraintTop_toBottomOf="@id/pin_area" />
+
+ <com.android.keyguard.NumPadButton
+ android:id="@+id/delete_button"
+ style="@style/NumPadKey.Delete"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key0"
+ android:contentDescription="@string/keyboardview_keycode_delete" />
+
+ <com.android.keyguard.NumPadButton
+ android:id="@+id/key_enter"
+ style="@style/NumPadKey.Enter"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:contentDescription="@string/keyboardview_keycode_enter" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key1"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key2"
+ androidprv:digit="1"
+ androidprv:textView="@+id/pukEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key2"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key3"
+ androidprv:digit="2"
+ androidprv:textView="@+id/pukEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key3"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key4"
+ androidprv:digit="3"
+ androidprv:textView="@+id/pukEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key4"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key5"
+ androidprv:digit="4"
+ androidprv:textView="@+id/pukEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key5"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key6"
+ androidprv:digit="5"
+ androidprv:textView="@+id/pukEntry" />
+
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key6"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key7"
+ androidprv:digit="6"
+ androidprv:textView="@+id/pukEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key7"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key8"
+ androidprv:digit="7"
+ androidprv:textView="@+id/pukEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key8"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key9"
+ androidprv:digit="8"
+ androidprv:textView="@+id/pukEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key9"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/delete_button"
+ androidprv:digit="9"
+ androidprv:textView="@+id/pukEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key0"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key_enter"
+ androidprv:digit="0"
+ androidprv:textView="@+id/pukEntry" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
<include layout="@layout/keyguard_eca"
android:id="@+id/keyguard_selector_fade_container"
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 6cc5b9d7b7e8..992d143ff66d 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -78,7 +78,7 @@
<!-- The vertical margin between the date and the owner info. -->
<!-- The translation for disappearing security views after having solved them. -->
- <dimen name="disappear_y_translation">-32dp</dimen>
+ <dimen name="disappear_y_translation">-50dp</dimen>
<!-- Dimens for animation for the Bouncer PIN view -->
<dimen name="pin_view_trans_y_entry">120dp</dimen>
diff --git a/packages/SystemUI/res-product/values/strings.xml b/packages/SystemUI/res-product/values/strings.xml
index b71caef3f593..87b206ce57ac 100644
--- a/packages/SystemUI/res-product/values/strings.xml
+++ b/packages/SystemUI/res-product/values/strings.xml
@@ -122,6 +122,12 @@
Try again in <xliff:g id="number">%3$d</xliff:g> seconds.
</string>
+ <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (tablet) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]-->
+ <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet.\n\nPressing the power button turns off the screen.</string>
+ <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (device) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]-->
+ <string name="security_settings_sfps_enroll_find_sensor_message" product="device">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device.\n\nPressing the power button turns off the screen.</string>
+ <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (default) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]-->
+ <string name="security_settings_sfps_enroll_find_sensor_message" product="default">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone.\n\nPressing the power button turns off the screen.</string>
<!-- Text shown when viewing global actions while phone is locked and additional controls are hidden [CHAR LIMIT=NONE] -->
<string name="global_action_lock_message" product="default">Unlock your phone for more options</string>
@@ -134,4 +140,7 @@
<string name="media_transfer_playing_this_device" product="default">Playing on this phone</string>
<!-- Text informing the user that their media is now playing on this tablet device. [CHAR LIMIT=50] -->
<string name="media_transfer_playing_this_device" product="tablet">Playing on this tablet</string>
+
+
+
</resources>
diff --git a/packages/SystemUI/res/drawable/controls_panel_background.xml b/packages/SystemUI/res/drawable/controls_panel_background.xml
index 9092877fc6fa..fc108a5e1e06 100644
--- a/packages/SystemUI/res/drawable/controls_panel_background.xml
+++ b/packages/SystemUI/res/drawable/controls_panel_background.xml
@@ -18,5 +18,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#1F1F1F" />
- <corners android:radius="@dimen/notification_corner_radius" />
+ <corners android:radius="@dimen/controls_panel_corner_radius" />
</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_footer_edit_circle.xml b/packages/SystemUI/res/drawable/qs_footer_edit_circle.xml
new file mode 100644
index 000000000000..2e29cae0ca4f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_footer_edit_circle.xml
@@ -0,0 +1,36 @@
+<?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.
+ -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:inset="@dimen/qs_footer_action_inset">
+ <ripple
+ android:color="?android:attr/colorControlHighlight">
+ <item android:id="@android:id/mask">
+ <!-- We make this shape a rounded rectangle instead of a oval so that it can animate -->
+ <!-- properly into an app/dialog. -->
+ <shape android:shape="rectangle">
+ <solid android:color="@android:color/white"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
+ </shape>
+ </item>
+ <item>
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
+ </shape>
+ </item>
+
+ </ripple>
+</inset> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml b/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml
new file mode 100644
index 000000000000..de0a6201cb09
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_media_rec_scrim.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
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <!-- gradient from 25% in the center to 100% at edges -->
+ <gradient
+ android:type="radial"
+ android:gradientRadius="40%p"
+ android:startColor="#AE000000"
+ android:endColor="#00000000" />
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/controls_fullscreen.xml b/packages/SystemUI/res/layout/controls_fullscreen.xml
index e08e63b39e59..fa703038cc7e 100644
--- a/packages/SystemUI/res/layout/controls_fullscreen.xml
+++ b/packages/SystemUI/res/layout/controls_fullscreen.xml
@@ -15,19 +15,11 @@
limitations under the License.
-->
-<FrameLayout
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/control_detail_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
-
- <LinearLayout
- android:id="@+id/global_actions_controls"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:paddingHorizontal="@dimen/controls_padding_horizontal" />
-
-</FrameLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/controls_with_favorites.xml b/packages/SystemUI/res/layout/controls_with_favorites.xml
index aa211bf8cfdc..71561c07ebd3 100644
--- a/packages/SystemUI/res/layout/controls_with_favorites.xml
+++ b/packages/SystemUI/res/layout/controls_with_favorites.xml
@@ -13,82 +13,94 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<merge
- xmlns:android="http://schemas.android.com/apk/res/android">
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:orientation="vertical"
+ tools:parentTag="android.widget.LinearLayout">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_marginBottom="@dimen/controls_header_bottom_margin">
-
- <!-- make sure the header stays centered in the layout by adding a spacer -->
- <Space
- android:id="@+id/controls_spacer"
- android:layout_width="@dimen/controls_header_menu_size"
- android:layout_height="1dp"
- android:visibility="gone" />
-
- <ImageView
- android:id="@+id/controls_close"
- android:contentDescription="@string/accessibility_desc_close"
- android:src="@drawable/ic_close"
- android:background="?android:attr/selectableItemBackgroundBorderless"
- android:tint="@color/control_primary_text"
- android:layout_width="@dimen/controls_header_menu_size"
- android:layout_height="@dimen/controls_header_menu_size"
- android:padding="12dp"
- android:visibility="gone" />
- <!-- need to keep this outer view in order to have a correctly sized anchor
- for the dropdown menu, as well as dropdown background in the right place -->
<LinearLayout
- android:id="@+id/controls_header"
- android:orientation="horizontal"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:minHeight="48dp"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:gravity="center">
- <TextView
- style="@style/Control.Spinner.Header"
- android:clickable="false"
- android:id="@+id/app_or_structure_spinner"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center" />
+ android:paddingHorizontal="@dimen/controls_header_horizontal_padding"
+ android:layout_marginBottom="@dimen/controls_header_bottom_margin"
+ android:orientation="horizontal">
+
+ <!-- make sure the header stays centered in the layout by adding a spacer -->
+ <Space
+ android:id="@+id/controls_spacer"
+ android:layout_width="@dimen/controls_header_menu_button_size"
+ android:layout_height="1dp"
+ android:visibility="gone" />
+
+ <ImageView
+ android:id="@+id/controls_close"
+ android:layout_width="@dimen/controls_header_menu_button_size"
+ android:layout_height="@dimen/controls_header_menu_button_size"
+ android:layout_gravity="center_vertical"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@string/accessibility_desc_close"
+ android:padding="12dp"
+ android:src="@drawable/ic_close"
+ android:tint="@color/control_primary_text"
+ android:visibility="gone"
+ tools:visibility="visible" />
+
+ <!-- need to keep this outer view in order to have a correctly sized anchor
+ for the dropdown menu, as well as dropdown background in the right place -->
+ <LinearLayout
+ android:id="@+id/controls_header"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:minHeight="48dp"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/app_or_structure_spinner"
+ style="@style/Control.Spinner.Header"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:clickable="false"
+ tools:text="Test app" />
+ </LinearLayout>
+
+ <ImageView
+ android:id="@+id/controls_more"
+ android:layout_width="@dimen/controls_header_menu_button_size"
+ android:layout_height="@dimen/controls_header_menu_button_size"
+ android:layout_gravity="center_vertical"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@string/accessibility_menu"
+ android:padding="12dp"
+ android:src="@drawable/ic_more_vert"
+ android:tint="@color/control_more_vert" />
</LinearLayout>
- <ImageView
- android:id="@+id/controls_more"
- android:src="@drawable/ic_more_vert"
- android:layout_width="@dimen/controls_header_menu_size"
- android:layout_height="@dimen/controls_header_menu_size"
- android:padding="12dp"
- android:tint="@color/control_more_vert"
- android:layout_gravity="center"
- android:contentDescription="@string/accessibility_menu"
- android:background="?android:attr/selectableItemBackgroundBorderless" />
- </LinearLayout>
- <ScrollView
+ <ScrollView
android:id="@+id/controls_scroll_view"
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:layout_marginHorizontal="@dimen/controls_content_margin_horizontal"
android:layout_weight="1"
- android:orientation="vertical"
android:clipChildren="true"
+ android:orientation="vertical"
android:paddingHorizontal="16dp"
android:scrollbars="none">
- <include layout="@layout/global_actions_controls_list_view" />
- </ScrollView>
+ <include layout="@layout/global_actions_controls_list_view" />
+
+ </ScrollView>
- <FrameLayout
- android:id="@+id/controls_panel"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:background="@drawable/controls_panel_background"
- android:visibility="gone"
- />
+ <FrameLayout
+ android:id="@+id/controls_panel"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_marginHorizontal="@dimen/controls_content_margin_horizontal"
+ android:layout_weight="1"
+ android:background="@drawable/controls_panel_background"
+ android:visibility="gone"
+ tools:visibility="visible" />
</merge>
diff --git a/packages/SystemUI/res/layout/media_recommendation_view.xml b/packages/SystemUI/res/layout/media_recommendation_view.xml
index c54c4e48d13d..a4aeba1dbcd6 100644
--- a/packages/SystemUI/res/layout/media_recommendation_view.xml
+++ b/packages/SystemUI/res/layout/media_recommendation_view.xml
@@ -22,9 +22,10 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:translationZ="0dp"
- android:scaleType="centerCrop"
+ android:scaleType="matrix"
android:adjustViewBounds="true"
android:clipToOutline="true"
+ android:layerType="hardware"
android:background="@drawable/bg_smartspace_media_item"/>
<!-- App icon -->
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index b1d3ed05333b..745cfc6c1655 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -64,7 +64,7 @@
android:layout_width="@dimen/qs_footer_action_button_size"
android:layout_height="@dimen/qs_footer_action_button_size"
android:layout_gravity="center_vertical|end"
- android:background="?android:attr/selectableItemBackground"
+ android:background="@drawable/qs_footer_edit_circle"
android:clickable="true"
android:contentDescription="@string/accessibility_quick_settings_edit"
android:focusable="true"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 4a73390d17cc..c5d28eef688f 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Kennisgewingskerm."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Vinnige instellings."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Kitsinstellings en kennisgewingskerm."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Sluitskerm."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Werksluitskerm"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Maak toe"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index f629387f6971..135284120b03 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"مركز الإشعارات."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"الإعدادات السريعة."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"\"الإعدادات السريعة\" و\"مركز الإشعارات\""</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"شاشة القفل."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"شاشة قفل بيانات العمل"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"إغلاق"</string>
@@ -655,7 +654,7 @@
<string name="right_keycode" msgid="2480715509844798438">"رمز مفتاح اليمين"</string>
<string name="left_icon" msgid="5036278531966897006">"رمز اليسار"</string>
<string name="right_icon" msgid="1103955040645237425">"رمز اليمين"</string>
- <string name="drag_to_add_tiles" msgid="8933270127508303672">"اضغط باستمرار مع السحب لإضافة الميزات."</string>
+ <string name="drag_to_add_tiles" msgid="8933270127508303672">"اضغط باستمرار مع السحب لإضافة المربّعات"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"اضغط باستمرار مع السحب لإعادة ترتيب الميزات."</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"اسحب هنا للإزالة"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"الحدّ الأدنى من عدد المربعات الذي تحتاج إليه هو <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"التبديل إلى الملف الشخصي للعمل"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"إغلاق"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"إعدادات شاشة القفل"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"‏لا يتوفّر اتصال Wi-Fi."</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"استخدام الكاميرا محظور."</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"استخدام الكاميرا والميكروفون محظور."</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"استخدام الميكروفون محظور."</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"وضع الأولوية مفعّل."</string>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index aa198424065d..13acbde945b9 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"জাননী পেনেল।"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ক্ষিপ্ৰ ছেটিং।"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ক্ষিপ্ৰ ছেটিং জাননী পেনেল।"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"বন্ধ স্ক্ৰীন।"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"কৰ্মস্থানৰ প্ৰ\'ফাইলৰ লক স্ক্ৰীন"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"বন্ধ কৰক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index c3312412c978..6a8eb2cd1ff3 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bildiriş kölgəsi."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Tez ayarlar."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Sürətli ayarlar və Bildiriş göstərişi."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kilid ekranı."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ekran kilidi"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Qapadın"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index d2279bed089c..f045b59130d9 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Цень апавяшчэння.."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Хуткія налады."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Хуткія налады і шчыток апавяшчэнняў."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Экран блакіроўкі."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Экран блакіроўкі дзейнасці"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Закрыць"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Пераключыцца на працоўны профіль"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Закрыць"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Налады экрана блакіроўкі"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Сетка Wi-Fi недаступная"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камера заблакіравана"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера і мікрафон заблакіраваны"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Мікрафон заблакіраваны"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Прыярытэтны рэжым уключаны"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 36b3c8b8d44b..dfb0c5b37270 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Падащ панел с известия."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Бързи настройки."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Падащ панел с бързи настройки и известия."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заключване на екрана."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Заключен екран на служебния профил"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Затваряне"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 0f3f00c465e3..42e8492da33f 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"বিজ্ঞপ্তি শেড৷"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"দ্রুত সেটিংস৷"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"দ্রুত সেটিংস এবং বিজ্ঞপ্তি শেড।"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"লক স্ক্রিন।"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"কর্মস্থলের স্ক্রিন লক"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"বন্ধ করুন"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"অফিস প্রোফাইলে পাল্টে নিন"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"বন্ধ করুন"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"লক স্ক্রিন সেটিংস"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ওয়াই-ফাই উপলভ্য নয়"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ক্যামেরার অ্যাক্সেস ব্লক করা আছে"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ক্যামেরা এবং মাইক্রোফোনের অ্যাক্সেস ব্লক করা আছে"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"মাইক্রোফোনের অ্যাক্সেস ব্লক করা আছে"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"\'প্রায়োরিটি\' মোড চালু করা আছে"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 823b72367b95..6da19137ae70 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -197,7 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Obavještenja sa sjenčenjem."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Brze postavke."</string>
- <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Brze postavke i zaslon obavijesti."</string>
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Brze postavke i lokacija za obavještenja."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Zaključan ekran."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Zaključan ekran radnog profila"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Zatvori"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index d60722fc1d11..81903a7c2134 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Àrea de notificacions"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configuració ràpida"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Configuració ràpida i àrea de notificacions."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueig"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Pantalla de bloqueig per a la feina"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Tanca"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Canvia al perfil de treball"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Tanca"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Configuració pantalla de bloqueig"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"No hi ha cap Wi‑Fi disponible"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"La càmera està bloquejada"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"La càmera i el micròfon estan bloquejats"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"El micròfon està bloquejat"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"El mode Prioritat està activat"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 6662ca10ffc0..6369fe55c7f0 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Panel oznámení."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Rychlé nastavení."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Rychlé nastavení a panel oznámení"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Obrazovka uzamčení"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Obrazovka uzamčení pracovního profilu"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Zavřít"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index ee9d8a60b760..514e0cb07675 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notifikationspanel."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Kvikmenu."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Kvikmenu og notifikationspanel."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Låseskærm."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Låseskærm til arbejde"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Luk"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Skift til arbejdsprofil"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Luk"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Indstillinger for låseskærm"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi er ikke tilgængeligt"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kameraet er blokeret"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Der er blokeret for kameraet og mikrofonen"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonen er blokeret"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritetstilstand er aktiveret"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 66fa2317d284..c7f792c49cfe 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Benachrichtigungsleiste"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Schnelleinstellungen"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Schnelleinstellungen und Benachrichtigungsleiste."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Sperrbildschirm"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Sperrbildschirm für Arbeitsprofil"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Schließen"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 84d661021067..99fa0bfdc741 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Πλαίσιο σκίασης ειδοποιήσεων."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Γρήγορες ρυθμίσεις."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Γρήγορες ρυθμίσεις και πλαίσιο σκίασης ειδοποιήσεων."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Οθόνη κλειδώματος"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Οθόνη κλειδωμένης εργασίας"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Κλείσιμο"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 020b9e5ed206..ad386eceded3 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Pantalla de notificaciones"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configuración rápida"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Configuración rápida y panel de notificaciones."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueo"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Pantalla bloqueada del perfil de trabajo"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Cerrar"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Cambiar al perfil de trabajo"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Cerrar"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Config. de pantalla de bloqueo"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi no disponible"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"La cámara está bloqueada"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"La cámara y el micrófono están bloqueados"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"El micrófono está bloqueado"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"El modo de prioridad está activado"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index c8e9b23b83e8..e28f1944d70d 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Pantalla de notificaciones"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Ajustes rápidos"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Ajustes rápidos y pantalla de notificaciones."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueo."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Pantalla de bloqueo para el perfil de trabajo"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Cerrar"</string>
@@ -959,7 +958,7 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móviles"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string>
- <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Conectada temporalmente"</string>
+ <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Conectado temporalmente"</string>
<string name="mobile_data_poor_connection" msgid="819617772268371434">"Conexión inestable"</string>
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Los datos móviles no se conectarán automáticamente"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Sin conexión"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Cambiar al perfil de trabajo"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Cerrar"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Ajustes de pantalla de bloqueo"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Red Wi-Fi no disponible"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Cámara bloqueada"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Cámara y micrófono bloqueados"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micrófono bloqueado"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modo Prioridad activado"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index a46f53d9aaaf..5fc1abe17d15 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Märguande vari."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Kiirseaded."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Kiirseaded ja märguandeala."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kuva lukustamine."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Töö lukustuskuva"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Sulgemine"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Lülitu tööprofiilile"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Sule"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Lukustuskuva seaded"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"WiFi pole saadaval"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kaamera on blokeeritud"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kaamera ja mikrofon on blokeeritud"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon on blokeeritud"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioriteetne režiim on sisse lülitatud"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 53ec95e22d7a..a3dcbb62be2b 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -780,12 +780,9 @@
<string name="privacy_type_media_projection" msgid="8136723828804251547">"pantaila-grabaketa"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ez du izenik"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Egonean"</string>
- <!-- no translation found for font_scaling_dialog_title (6273107303850248375) -->
- <skip />
- <!-- no translation found for font_scaling_smaller (1012032217622008232) -->
- <skip />
- <!-- no translation found for font_scaling_larger (5476242157436806760) -->
- <skip />
+ <string name="font_scaling_dialog_title" msgid="6273107303850248375">"Letraren tamaina"</string>
+ <string name="font_scaling_smaller" msgid="1012032217622008232">"Txikitu"</string>
+ <string name="font_scaling_larger" msgid="5476242157436806760">"Handitu"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Lupa-leihoa"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Lupa-leihoaren aukerak"</string>
<string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Handitu"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 938bc82c2d19..d34573611124 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"مجموعه اعلان."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"تنظیمات سریع."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"تنظیمات فوری و کشوی اعلانات."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"صفحه قفل."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"صفحه قفل کاری"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"بستن"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 6f9b38bf0d9d..8aaafe104388 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Ilmoitusalue."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Pika-asetukset."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Pika-asetukset ja ilmoitusalue"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lukitse näyttö."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Työlukitusnäyttö"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Sulje"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index c6f8cab527a5..d45677ed62cc 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -780,12 +780,9 @@
<string name="privacy_type_media_projection" msgid="8136723828804251547">"enregistrement d\'écran"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sans titre"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Veille"</string>
- <!-- no translation found for font_scaling_dialog_title (6273107303850248375) -->
- <skip />
- <!-- no translation found for font_scaling_smaller (1012032217622008232) -->
- <skip />
- <!-- no translation found for font_scaling_larger (5476242157436806760) -->
- <skip />
+ <string name="font_scaling_dialog_title" msgid="6273107303850248375">"Taille de police"</string>
+ <string name="font_scaling_smaller" msgid="1012032217622008232">"Rapetisser"</string>
+ <string name="font_scaling_larger" msgid="5476242157436806760">"Agrandir"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fenêtre d\'agrandissement"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Commandes pour la fenêtre d\'agrandissement"</string>
<string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Effectuer un zoom avant"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index a191259b7f1e..0d612aab505a 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Volet des notifications"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Réglages rapides"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Réglages rapides et volet des notifications."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Écran de verrouillage"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Écran de verrouillage du profil professionnel"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Fermer"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Passer au profil professionnel"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Fermer"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Paramètres écran de verrouillage"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non disponible"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Caméra bloquée"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Caméra et micro bloqués"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micro bloqué"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Mode Prioritaire activé"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 2684b92581c9..b1eb70b0016f 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Panel despregable"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configuración rápida"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Configuración rápida e panel despregable."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueo."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Pantalla de bloqueo do perfil de traballo"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Pechar"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Cambiar ao perfil de traballo"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Pechar"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Configuración pantalla bloqueo"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi non dispoñible"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"A cámara está bloqueada"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"A cámara e o micrófono están bloqueados"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"O micrófono está bloqueado"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"O modo de prioridade está activado"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index cf1000d76a4c..cb2966ebcc4f 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"નોટિફિકેશન શેડ."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ઝડપી સેટિંગ."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ઝડપી સેટિંગ અને નોટિફિકેશન શેડ."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"લૉક સ્ક્રીન."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"કાર્ય લૉક સ્ક્રીન"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"બંધ કરો"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"ઑફિસની પ્રોફાઇલ પર સ્વિચ કરો"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"બંધ કરો"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"લૉક સ્ક્રીનના સેટિંગ"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"વાઇ-ફાઇ ઉપલબ્ધ નથી"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"કૅમેરા બ્લૉક કરેલો છે"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"કૅમેરા અને માઇક્રોફોન બ્લૉક કરેલા છે"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"માઇક્રોફોન બ્લૉક કરેલો છે"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"પ્રાધાન્યતા મોડ ચાલુ છે"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 7bab739d51d1..7bbd2d13ced1 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना शेड."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"त्वरित सेटिंग."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"क्विक सेटिंग और नोटिफ़िकेशन शेड."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"लॉक स्क्रीन."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"वर्क लॉक स्‍क्रीन"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"बंद करें"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 8a088a1bff9b..16761f59291d 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Értesítési felület."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Gyorsbeállítások."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Gyorsbeállítások és értesítési terület"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lezárási képernyő."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Munka lezárási képernyővel"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Bezárás"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Váltás munkaprofilra"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Bezárás"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Lezárási képernyő beállításai"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Nem áll rendelkezésre Wi-Fi"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera letiltva"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera és mikrofon letiltva"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon letiltva"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritás mód bekapcsolva"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 819a02990183..7d2d638f92cc 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Ծանուցումների վահանակ:"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Արագ կարգավորումներ:"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Արագ կարգավորումներ և ծանուցումների վահանակ։"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Էկրանի կողպում:"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Աշխատանքային պրոֆիլի կողպէկրան"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Փակել"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Անցնել աշխատանքային պրոֆիլ"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Փակել"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Կողպէկրանի կարգավորումներ"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ցանց հասանելի չէ"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Տեսախցիկն արգելափակված է"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Տեսախցիկն ու խոսափողը արգելափակված են"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Խոսափողն արգելափակված է"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Առաջնահերթության ռեժիմը միացված է"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index b70173a73829..97e231675407 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bayangan pemberitahuan."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Setelan cepat."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Setelan cepat dan Menu notifikasi."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Layar kunci."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Layar kunci kantor"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Tutup"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Beralih ke profil kerja"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Tutup"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Setelan layar kunci"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi tidak tersedia"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera diblokir"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dan mikrofon diblokir"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon diblokir"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Mode prioritas diaktifkan"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 85b435ec23cc..28f1fb63aa0e 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Tilkynningasvæði."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Flýtistillingar."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Flýtistillingar og tilkynningagluggi."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lásskjár."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Vinnulásskjár"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Loka"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Skipta yfir í vinnusnið"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Loka"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Stillingar fyrir lásskjá"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi er ekki til staðar"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Lokað fyrir myndavél"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Lokað fyrir myndavél og hljóðnema"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Lokað fyrir hljóðnema"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Kveikt er á forgangsstillingu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 8c25677fce78..5c8ce7c1bbd1 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -1043,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Passa a profilo di lavoro"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Chiudi"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Impostazioni schermata di blocco"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non disponibile"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Videocamera bloccata"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Videocamera e microfono bloccati"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfono bloccato"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modalità priorità attivata"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 1237ba66f18a..c2392d944974 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"לוח התראות."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"הגדרות מהירות."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"הגדרות מהירות ולוח ההתראות."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"מסך נעילה."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"מסך נעילה של עבודה"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"סגירה"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 2ce2f536571a..630f1f807e1c 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知シェード"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"クイック設定"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"クイック設定と通知シェード。"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ロック画面"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"仕事用プロファイルのロック画面"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"閉じる"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 59febea1bc91..76277bdf5001 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"შეტყობინებების ფარდა"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"სწრაფი პარამეტრები"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"სწრაფი პარამეტრები და შეტყობინებების ფარდა"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ეკრანის დაბლოკვა."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"სამსახურის ჩაკეტილი ეკრანი"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"დახურვა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 6bdb0aa41925..d7c24cf0c75a 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Хабарландыру тақтасы"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Жылдам параметрлер."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Жылдам параметрлер мен хабарландыру тақтасы."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Бекіту экраны."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Әрекетті құлыптау экраны"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Жабу"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Жұмыс профиліне ауысу"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Жабу"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Экран құлпының параметрлері"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi қолжетімсіз."</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камера бөгелген."</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера мен микрофон бөгелген."</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофон бөгелген."</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"\"Маңызды\" режимі қосулы."</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 080769a4dd6a..521302eef76a 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ពណ៌​ការ​ជូន​ដំណឹង"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ការ​កំណត់​រហ័ស។"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ការកំណត់រហ័ស និងផ្ទាំងជូនដំណឹង។"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ចាក់​សោ​អេក្រង់។"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"អេក្រង់​ចាក់​សោ​លក្ខណៈ​ការងារ"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"បិទ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 4a8bbd862dd2..9f47e94d85cc 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ಅಧಿಸೂಚನೆಯ ಛಾಯೆ."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳು."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳು ಮತ್ತು ಅಧಿಸೂಚನೆಯ ಪರದೆ."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ಲಾಕ್‌ ಸ್ಕ್ರೀನ್."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ಕೆಲಸದ ಲಾಕ್ ಪರದೆ"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"ಮುಚ್ಚು"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index dd68c5a30e22..9d90602dce1b 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"알림 세부정보"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"빠른 설정"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"빠른 설정 및 알림 창입니다."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"화면을 잠급니다."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"업무용 잠금 화면"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"닫기"</string>
@@ -780,12 +779,9 @@
<string name="privacy_type_media_projection" msgid="8136723828804251547">"화면 녹화"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"제목 없음"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"대기"</string>
- <!-- no translation found for font_scaling_dialog_title (6273107303850248375) -->
- <skip />
- <!-- no translation found for font_scaling_smaller (1012032217622008232) -->
- <skip />
- <!-- no translation found for font_scaling_larger (5476242157436806760) -->
- <skip />
+ <string name="font_scaling_dialog_title" msgid="6273107303850248375">"글꼴 크기"</string>
+ <string name="font_scaling_smaller" msgid="1012032217622008232">"축소"</string>
+ <string name="font_scaling_larger" msgid="5476242157436806760">"확대"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"확대 창"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"확대 창 컨트롤"</string>
<string name="accessibility_control_zoom_in" msgid="1189272315480097417">"확대"</string>
@@ -1047,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"직장 프로필로 전환"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"닫기"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"잠금 화면 설정"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi를 사용할 수 없음"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"카메라 차단됨"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"카메라 및 마이크 차단됨"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"마이크 차단됨"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"우선순위 모드 설정됨"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index efd9c086ddd3..0b89bd3fb471 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Билдирмелер тактасы."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Тез тууралоолор."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Ыкчам параметрлер жана билдирмелер тактасы."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Кулпуланган экран."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Жумуштун кулпуланган экраны"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Жабуу"</string>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index bc63c9f46a5b..4f38e6058723 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -64,5 +64,6 @@
<dimen name="qs_panel_padding_top">@dimen/qqs_layout_margin_top</dimen>
- <dimen name="controls_padding_horizontal">16dp</dimen>
+ <dimen name="controls_header_horizontal_padding">12dp</dimen>
+ <dimen name="controls_content_margin_horizontal">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 00190ec716fe..85910fdd7178 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ໜ້າຈໍແຈ້ງເຕືອນ."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ການຕັ້ງຄ່າດ່ວນ."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ການຕັ້ງຄ່າດ່ວນ ແລະ ເງົາການແຈ້ງເຕືອນ."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ລັອກ​ໜ້າ​ຈໍ."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ໜ້າຈໍລັອກວຽກ"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"ປິດ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 5bcd893af655..8161025142ad 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Pranešimų gaubtas."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Spartieji nustatymai."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Spartieji nustatymai ir pranešimų skydelis."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Užrakinimo ekranas."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Darbo profilio užrakinimo ekranas"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Uždaryti"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 4dcb45413ac7..72ca07192d95 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Paziņojumu panelis"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Ātrie iestatījumi"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Ātrie iestatījumi un paziņojumu panelis."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Bloķēšanas ekrāns."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Darba profila bloķēšanas ekrāns"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Aizvērt"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Pārslēgties uz darba profilu"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Aizvērt"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Bloķēšanas ekrāna iestatījumi"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi nav pieejams"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera ir bloķēta"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameras un mikrofona lietošana ir bloķēta"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofons ir bloķēts"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritātes režīms ir ieslēgts"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index e80be9248e88..e16812148a88 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панел за известување"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Брзи поставки."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"„Брзи поставки“ и „Панел со известувања“."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заклучи екран."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Работен заклучен екран"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Затвори"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Префрли се на работен профил"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Затвори"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Поставки за заклучен екран"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi не е достапно"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камерата е блокирана"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камерата и микрофонот се блокирани"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофонот е блокиран"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Приоритетниот режим е вклучен"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 6622fb90be17..36c1a5f2c837 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"അറിയിപ്പ് ഷെയ്‌ഡ്."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ദ്രുത ക്രമീകരണങ്ങൾ."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"അറിയിപ്പ് ഷെയ്‌ഡിനുള്ള ദ്രുത ക്രമീകരണം."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ലോക്ക് സ്‌ക്രീൻ."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ഔദ്യോഗിക ലോക്ക് സ്ക്രീൻ"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"അവസാനിപ്പിക്കുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 5e875d1e31b0..9042bf5c104f 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Мэдэгдлийн хураангуй самбар"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Шуурхай тохиргоо."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Шуурхай тохиргоо болон мэдэгдлийн хураангуй самбар."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Дэлгэц түгжих."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ажлын түгжигдсэн дэлгэц"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Хаах"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 9f3680dbdbed..43fed36e80c7 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना शेड."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"क्विक सेटिंग्ज."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"क्विक सेटिंग्ज आणि सूचना शेड."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"लॉक स्क्रीन."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"कार्य लॉक स्क्रीन"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"बंद करा"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"कार्य प्रोफाइलवर स्विच करा"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"बंद करा"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"लॉक स्क्रीन सेटिंग्ज"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"वाय-फाय उपलब्ध नाही"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"कॅमेरा ब्लॉक केला"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"कॅमेरा आणि मायक्रोफोन ब्लॉक केले आहेत"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"मायक्रोफोन ब्लॉक केला"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"प्राधान्य मोड सुरू आहे"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 109d5193c5ee..5a6ee921c9f8 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bidai pemberitahuan."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Tetapan pantas."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Tetapan pantas dan Bidai pemberitahuan."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kunci skrin."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Skrin kunci kerja"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Tutup"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 4fa84eb0d933..7fe024472ed7 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"အ​ကြောင်းကြားစာအကွက်"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"အမြန်လုပ် အပြင်အဆင်"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"‘အမြန်ဆက်တင်များ’ နှင့် ‘အကြောင်းကြားစာအကွက်’။"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"မျက်နှာပြင် သော့ပိတ်ရန်"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"အလုပ်သုံး လော့ခ်မျက်နှာပြင်"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"ပိတ်ရန်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 7e8e5f0c7d06..887cf9d3de53 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Varselskygge."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Hurtiginnstillinger."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Hurtiginnstillinger og varselpanelet"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Låseskjerm."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Låseskjerm for arbeid"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Lukk"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index db4c1a2cffe0..c37aef3a1ff9 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना कक्ष।"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"द्रुत सेटिङहरू"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"द्रुत सेटिङ तथा सूचना कक्ष।"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"स्क्रीन बन्द गर्नुहोस्।"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"कार्य प्रोफाइलको लक स्क्रिन"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"बन्द गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 28a78e1355d0..ee055d7779d1 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Meldingenpaneel."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Snelle instellingen."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Snelle instellingen en meldingenpaneel."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Vergrendelscherm."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Vergrendelscherm voor werk"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Sluiten"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index d3ce6fcfcd37..4252f49a056b 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ବିଜ୍ଞପ୍ତି ଶେଡ୍‍।"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"କ୍ୱିକ୍ ସେଟିଂସ୍।"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"କୁଇକ ସେଟିଂସ ଏବଂ ବିଜ୍ଞପ୍ତି ସେଡ।"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ଲକ୍‌ ସ୍କ୍ରୀନ୍‌।"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ୱର୍କ ଲକ୍‍ ସ୍କ୍ରୀନ୍‍"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"ବନ୍ଦ କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 70e15b8fec45..ea8bd3d88d8c 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ਸੂਚਨਾ ਸ਼ੇਡ।"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ।"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸੂਚਨਾ ਸ਼ੇਡ।"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">" ਲਾਕ ਸਕ੍ਰੀਨ।"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ਕਾਰਜ-ਸਥਾਨ ਲਾਕ ਸਕ੍ਰੀਨ"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"ਬੰਦ ਕਰੋ"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਜਾਓ"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"ਬੰਦ ਕਰੋ"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"ਲਾਕ ਸਕ੍ਰੀਨ ਸੈਟਿੰਗਾਂ"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ਵਾਈ-ਫਾਈ ਉਪਲਬਧ ਨਹੀਂ"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ਕੈਮਰਾ ਬਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ਕੈਮਰਾ ਅਤੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਬਲਾਕ ਕੀਤੇ ਗਏ"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਬਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ਤਰਜੀਹ ਮੋਡ ਚਾਲੂ ਹੈ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index b67bd0036df9..aa117db339aa 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Obszar powiadomień."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Szybkie ustawienia."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Szybkie ustawienia i obszar powiadomień."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ekran blokady."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ekran blokady wyświetlany podczas działania"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Zamknij"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Przełącz na profil służbowy"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Zamknij"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Ustawienia ekranu blokady"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Sieć Wi-Fi jest niedostępna"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera jest zablokowana"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon są zablokowane"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon jest zablokowany"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Tryb priorytetowy jest włączony"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index f3ef1523a7e6..5b3efde20363 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Aba de notificações."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configurações rápidas."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Configurações rápidas e aba de notificações."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Tela de bloqueio."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Tela de bloqueio de trabalho"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Fechar"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index ac7886c56b35..eb314bae993d 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Painel de notificações."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Definições rápidas."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Definições rápidas e painel de notificações."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ecrã de bloqueio."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ecrã de bloqueio de trabalho"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Fechar"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index f3ef1523a7e6..5b3efde20363 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Aba de notificações."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configurações rápidas."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Configurações rápidas e aba de notificações."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Tela de bloqueio."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Tela de bloqueio de trabalho"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Fechar"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 4bdbbc4ee91d..aced6bd29bc9 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Fereastră pentru notificări."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Setări rapide."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Fereastră de Setări rapide și notificări."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ecranul de blocare."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ecran de blocare pentru serviciu"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Închide"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index f1a0cc38d8f7..f6459bb07341 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панель уведомлений"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Быстрые настройки"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Быстрые настройки и панель уведомлений."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Экран блокировки."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Заблокировано"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Закрыть"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index c3351897d912..e4838f982e5b 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"දැනුම්දීම් ආවරණය."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ක්ෂණික සැකසීම්."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ඉක්මන් සැකසීම් සහ දැනුම්දීම් ඡායිතය."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"අගුළු තිරය."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"කාර්යාල අගුලු තිරය"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"වසන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 1174755f6793..db3b7655fdbf 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Panel upozornení."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Rýchle nastavenia."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Rýchle nastavenia a panel upozornení"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Uzamknutá obrazovka"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Uzamknutá obrazovka pracovného profilu"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Zavrieť"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index ffb74aeb164a..1d9c77ca1449 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Zaslon z obvestili."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Hitre nastavitve."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Hitre nastavitve in zaslon z obvestili"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Zaklenjen zaslon"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Zaklenjen zaslon delovnega profila"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Zapri"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 84a5f96f4b3d..5524812055bc 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Streha e njoftimeve."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Cilësimet e shpejta."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"\"Cilësimet e shpejta\" dhe \"Streha e njoftimeve\"."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ekrani i kyçjes."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ekrani i kyçjes së punës"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Mbylle"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index be4f200e9bbd..3ef8f3563bb8 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Meddelandepanel."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Snabbinställningar."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Snabbinställningar och meddelandepanel."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Låsskärm."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Låsskärm för arbete"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Stäng"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 4e04b6467820..46ffaa523470 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Kivuli cha arifa."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Mipangilio ya haraka."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Mipangilio ya haraka na Sehemu ya arifa."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Skrini iliyofungwa."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Skrini iliyofungwa ya kazini"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Funga"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Tumia wasifu wa kazini"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Funga"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Mipangilio ya skrini iliyofungwa"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi haipatikani"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera imezuiwa"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera na maikrofoni zimezuiwa"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Maikrofoni imezuiwa"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Hali ya kipaumbele imewashwa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 7cd147099e9c..59becc69506c 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -87,4 +87,7 @@
<!-- Biometric Auth pattern view size, better to align keyguard_security_width -->
<dimen name="biometric_auth_pattern_view_size">348dp</dimen>
+
+ <dimen name="controls_header_horizontal_padding">12dp</dimen>
+ <dimen name="controls_content_margin_horizontal">24dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
index 9ed936050aa2..8583f0549960 100644
--- a/packages/SystemUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
@@ -37,6 +37,8 @@
<dimen name="qs_media_rec_album_size">112dp</dimen>
<dimen name="qs_media_rec_album_side_margin">16dp</dimen>
+ <dimen name="controls_panel_corner_radius">40dp</dimen>
+
<dimen name="lockscreen_shade_max_over_scroll_amount">42dp</dimen>
<!-- Roughly the same distance as media on LS to media on QS. We will translate by this value
diff --git a/packages/SystemUI/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
index 8b41a44b9ba3..9248d585bba7 100644
--- a/packages/SystemUI/res/values-sw720dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
@@ -33,5 +33,7 @@
side -->
<dimen name="qs_tiles_page_horizontal_margin">60dp</dimen>
+ <dimen name="controls_panel_corner_radius">46dp</dimen>
+
<dimen name="notification_section_divider_height">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index 8f59df655c3a..20864591ae5a 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -19,7 +19,8 @@
<!-- gap on either side of status bar notification icons -->
<dimen name="status_bar_icon_padding">1dp</dimen>
- <dimen name="controls_padding_horizontal">40dp</dimen>
+ <dimen name="controls_header_horizontal_padding">28dp</dimen>
+ <dimen name="controls_content_margin_horizontal">40dp</dimen>
<dimen name="large_screen_shade_header_height">56dp</dimen>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 9ddbe9b6d491..a07cad6c7dba 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"నోటిఫికేషన్ షేడ్."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"శీఘ్ర సెట్టింగ్‌లు."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"క్విక్ సెట్టింగ్‌లు, నోటిఫికేషన్ తెర."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"లాక్ స్క్రీన్."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"కార్యాలయ లాక్ స్క్రీన్"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"మూసివేస్తుంది"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index c01929bec67b..33678874b7c5 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -1043,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"สลับไปใช้โปรไฟล์งาน"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"ปิด"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"การตั้งค่าหน้าจอล็อก"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ไม่พร้อมใช้งาน"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"กล้องถูกบล็อกอยู่"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"กล้องและไมโครโฟนถูกบล็อกอยู่"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ไมโครโฟนถูกบล็อกอยู่"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"โหมดลำดับความสำคัญเปิดอยู่"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index d65704a89281..0c8bd82b8145 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notification shade."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Mga mabilisang setting."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Mga mabilisang setting at Notification shade."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lock screen."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Lock screen sa trabaho"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Isara"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 34b3b1f862ea..86d38da3ace4 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bildirim gölgesi."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Hızlı ayarlar."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Hızlı ayarlar ve Bildirim gölgesi."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kilit ekranı"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"İş profili kilit ekranı"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Kapat"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index e439bec78585..f544fcd545ca 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панель сповіщень."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Швидке налаштування."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Швидкі налаштування й панель сповіщень."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заблокований екран."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Екран блокування завдання"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Закрити"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Перейти в робочий профіль"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Закрити"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Параметри заблокованого екрана"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Мережа Wi-Fi недоступна"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камеру заблоковано"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камеру й мікрофон заблоковано"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Мікрофон заблоковано"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Режим пріоритету ввімкнено"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 1d4385d60c46..0cc29aa94fe4 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"اطلاعاتی شیڈ۔"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"فوری ترتیبات۔"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"فوری ترتیبات اور اطلاعاتی شیڈ۔"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"مقفل اسکرین۔"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"دفتری مقفل اسکرین"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"بند کریں"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 1cb78ceecdf7..ec893ed3f519 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bóng thông báo."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Cài đặt nhanh."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Cài đặt nhanh và ngăn thông báo."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Màn hình khóa."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Màn hình khóa công việc"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Đóng"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Chuyển sang hồ sơ công việc"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Đóng"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Cài đặt màn hình khoá"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Không có Wi-Fi"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Máy ảnh bị chặn"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Máy ảnh và micrô bị chặn"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micrô bị chặn"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Chế độ ưu tiên đang bật"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 25ea39d1f75e..7edc6ced44a2 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知栏。"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"快捷设置。"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"快捷设置和通知栏。"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"锁定屏幕。"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"工作锁定屏幕"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"关闭"</string>
@@ -959,7 +958,7 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"移动数据网络"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"已连接"</string>
- <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"暂时已连接"</string>
+ <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"已暂时连接"</string>
<string name="mobile_data_poor_connection" msgid="819617772268371434">"连接状况不佳"</string>
<string name="mobile_data_off_summary" msgid="3663995422004150567">"系统将不会自动连接到移动数据网络"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"无网络连接"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 2bb1ab896522..a84a3f91291f 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知欄。"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"快速設定。"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"快速設定和通知欄。"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"上鎖畫面。"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"工作螢幕鎖定"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"關閉"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 612005e20fd9..bb6e2d5b6d72 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知欄。"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"快捷設定。"</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"快速設定和通知欄。"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"螢幕鎖定。"</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Work 螢幕鎖定"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"關閉"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index b3f96b03a9f1..77dfa881a19a 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -197,8 +197,7 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Umthunzi wesaziso."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Izilingiselelo ezisheshayo."</string>
- <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
- <skip />
+ <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Amasethingi asheshayo Nomthunzi wezaziso."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Khiya isikrini."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ukukhiya isikrini somsebenzi"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"Vala"</string>
@@ -1044,14 +1043,9 @@
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Shintshela kuphrofayela yomsebenzi"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Vala"</string>
<string name="lock_screen_settings" msgid="9197175446592718435">"Amasethingi okukhiya isikrini"</string>
- <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
- <skip />
- <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
- <skip />
- <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
- <skip />
- <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
- <skip />
- <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
- <skip />
+ <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"I-Wi-Fi ayitholakali"</string>
+ <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Ikhamera ivinjiwe"</string>
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Ikhamera nemakrofoni zivinjiwe"</string>
+ <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Imakrofoni ivinjiwe"</string>
+ <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Imodi ebalulekile ivuliwe"</string>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 3f84ddb2a067..f545dae05b56 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -774,7 +774,7 @@
<!-- Duration in milliseconds of the dream in complications fade-in animation. -->
<integer name="config_dreamOverlayInComplicationsDurationMs">250</integer>
<!-- Duration in milliseconds of the y-translation animation when entering a dream -->
- <integer name="config_dreamOverlayInTranslationYDurationMs">917</integer>
+ <integer name="config_dreamOverlayInTranslationYDurationMs">1167</integer>
<!-- Delay in milliseconds before switching to the dock user and dreaming if a secondary user is
active when the device is locked and docked. 0 indicates disabled. Default is 1 minute. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f7310b045744..3b8f1a7d1e4d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -196,9 +196,6 @@
<!-- Increased height of a small notification in the status bar -->
<dimen name="notification_min_height_increased">146dp</dimen>
- <!-- Increased height of a collapsed media notification in the status bar -->
- <dimen name="notification_min_height_media">160dp</dimen>
-
<!-- Height of a small notification in the status bar which was used before android N -->
<dimen name="notification_min_height_legacy">64dp</dimen>
@@ -576,7 +573,7 @@
<dimen name="qs_tile_margin_horizontal">8dp</dimen>
<dimen name="qs_tile_margin_vertical">@dimen/qs_tile_margin_horizontal</dimen>
<dimen name="qs_tile_margin_top_bottom">4dp</dimen>
- <dimen name="qs_brightness_margin_top">12dp</dimen>
+ <dimen name="qs_brightness_margin_top">8dp</dimen>
<dimen name="qs_brightness_margin_bottom">16dp</dimen>
<dimen name="qqs_layout_margin_top">16dp</dimen>
<dimen name="qqs_layout_padding_bottom">24dp</dimen>
@@ -628,7 +625,7 @@
<dimen name="qs_header_row_min_height">48dp</dimen>
<dimen name="qs_header_non_clickable_element_height">24dp</dimen>
- <dimen name="new_qs_header_non_clickable_element_height">20dp</dimen>
+ <dimen name="new_qs_header_non_clickable_element_height">24dp</dimen>
<dimen name="qs_footer_padding">20dp</dimen>
<dimen name="qs_security_footer_height">88dp</dimen>
@@ -1153,11 +1150,13 @@
<!-- Home Controls -->
<dimen name="controls_header_menu_size">48dp</dimen>
+ <dimen name="controls_header_menu_button_size">48dp</dimen>
<dimen name="controls_header_bottom_margin">16dp</dimen>
+ <dimen name="controls_header_horizontal_padding">12dp</dimen>
<dimen name="controls_header_app_icon_size">24dp</dimen>
<dimen name="controls_top_margin">48dp</dimen>
- <dimen name="controls_padding_horizontal">0dp</dimen>
- <dimen name="control_header_text_size">20sp</dimen>
+ <dimen name="controls_content_margin_horizontal">0dp</dimen>
+ <dimen name="control_header_text_size">24sp</dimen>
<dimen name="control_item_text_size">16sp</dimen>
<dimen name="control_menu_item_text_size">16sp</dimen>
<dimen name="control_menu_item_min_height">56dp</dimen>
@@ -1188,6 +1187,8 @@
<item name="controls_task_view_width_percentage" translatable="false" format="float" type="dimen">1.0</item>
<dimen name="controls_task_view_right_margin">0dp</dimen>
+ <dimen name="controls_panel_corner_radius">42dp</dimen>
+
<!-- Home Controls activity view detail panel-->
<dimen name="controls_activity_view_corner_radius">@*android:dimen/config_bottomDialogCornerRadius</dimen>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index 6354752e1b22..763930db1d55 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -30,9 +30,6 @@
<bool name="flag_charging_ripple">false</bool>
- <!-- Whether to show chipbar UI whenever the device is unlocked by ActiveUnlock. -->
- <bool name="flag_active_unlock_chipbar">true</bool>
-
<!-- Whether the user switcher chip shows in the status bar. When true, the multi user
avatar will no longer show on the lockscreen -->
<bool name="flag_user_switcher_chip">false</bool>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 464ce0333fd1..9a9f5106b7d8 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -405,8 +405,6 @@
<!-- Message shown when the system-provided fingerprint dialog is shown, asking for authentication -->
<string name="fingerprint_dialog_touch_sensor">Touch the fingerprint sensor</string>
- <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_fingerprint_dialog_fingerprint_icon">Fingerprint icon</string>
<!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] -->
<string name="fingerprint_dialog_use_fingerprint_instead">Can\u2019t recognize face. Use fingerprint instead.</string>
<!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] -->
@@ -2260,7 +2258,11 @@
<!-- Shows in a dialog presented to the user to authorize this app to display a Device controls
panel (embedded activity) instead of controls rendered by SystemUI [CHAR LIMIT=NONE] -->
- <string name="controls_panel_authorization">When you add <xliff:g id="appName" example="My app">%s</xliff:g>, it can add controls and content to this panel. In some apps, you can choose which controls show up here.</string>
+ <string name="controls_panel_authorization"><xliff:g id="appName" example="My app">%s</xliff:g>can choose which controls and content show here.</string>
+
+ <!-- Shows in a dialog presented to the user to authorize this app removal from a Device
+ controls panel [CHAR LIMIT=NONE] -->
+ <string name="controls_panel_remove_app_authorization">Remove controls for <xliff:g example="My app" id="appName">%s</xliff:g>?</string>
<!-- a11y state description for a control that is currently favorited [CHAR LIMIT=NONE] -->
<string name="accessibility_control_favorite">Favorited</string>
@@ -2302,6 +2304,8 @@
<string name="controls_dialog_title">Add to device controls</string>
<!-- Controls dialog add to favorites [CHAR LIMIT=40] -->
<string name="controls_dialog_ok">Add</string>
+ <!-- Controls dialog remove app from a panel [CHAR LIMIT=40] -->
+ <string name="controls_dialog_remove">Remove</string>
<!-- Controls dialog message. Indicates app that suggested this control [CHAR LIMIT=NONE] -->
<string name="controls_dialog_message">Suggested by <xliff:g id="app" example="System UI">%s</xliff:g></string>
<!-- Controls tile secondary label when device is locked and user does not want access to controls from lockscreen [CHAR LIMIT=20] -->
@@ -2314,7 +2318,7 @@
<!-- Title of the dialog to control certain devices from lock screen without auth [CHAR LIMIT=NONE] -->
<string name="controls_settings_trivial_controls_dialog_title">Control devices from lock screen?</string>
<!-- Message of the dialog to control certain devices from lock screen without auth [CHAR LIMIT=NONE] -->
- <string name="controls_settings_trivial_controls_dialog_message">You can control some devices without unlocking your phone or tablet.\n\nYour device app determines which devices can be controlled in this way.</string>
+ <string name="controls_settings_trivial_controls_dialog_message">You can control some devices without unlocking your phone or tablet. Your device app determines which devices can be controlled in this way.</string>
<!-- Neutral button title of the controls dialog [CHAR LIMIT=NONE] -->
<string name="controls_settings_dialog_neutral_button">No thanks</string>
<!-- Positive button title of the controls dialog [CHAR LIMIT=NONE] -->
@@ -2419,6 +2423,8 @@
<string name="controls_menu_edit">Edit controls</string>
<!-- Controls menu, add another app [CHAR LIMIT=30] -->
<string name="controls_menu_add_another_app">Add app</string>
+ <!-- Controls menu, remove app [CHAR_LIMIT=30] -->
+ <string name="controls_menu_remove">Remove app</string>
<!-- Title for the media output dialog with media related devices [CHAR LIMIT=50] -->
<string name="media_output_dialog_add_output">Add outputs</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt
index 12e0b9ab835a..c5979cc50c3c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt
@@ -65,35 +65,40 @@ class UnfoldConstantTranslateAnimator(
} else {
1
}
- viewsToTranslate.forEach { (view, direction, shouldBeAnimated) ->
- if (shouldBeAnimated()) {
- view.get()?.translationX = xTrans * direction.multiplier * rtlMultiplier
- }
+ viewsToTranslate.forEach { (view, direction) ->
+ view.get()?.translationX = xTrans * direction.multiplier * rtlMultiplier
}
}
/** Finds in [parent] all views specified by [ids] and register them for the animation. */
private fun registerViewsForAnimation(parent: ViewGroup, ids: Set<ViewIdToTranslate>) {
viewsToTranslate =
- ids.mapNotNull { (id, dir, pred) ->
- parent.findViewById<View>(id)?.let { view ->
- ViewToTranslate(WeakReference(view), dir, pred)
+ ids.asSequence()
+ .filter { it.shouldBeAnimated() }
+ .mapNotNull {
+ parent.findViewById<View>(it.viewId)?.let { view ->
+ ViewToTranslate(WeakReference(view), it.direction)
+ }
}
- }
+ .toList()
}
- /** Represents a view to animate. [rootView] should contain a view with [viewId] inside. */
+ /**
+ * Represents a view to animate. [rootView] should contain a view with [viewId] inside.
+ * [shouldBeAnimated] is only evaluated when the viewsToTranslate is registered in
+ * [registerViewsForAnimation].
+ */
data class ViewIdToTranslate(
val viewId: Int,
val direction: Direction,
val shouldBeAnimated: () -> Boolean = { true }
)
- private data class ViewToTranslate(
- val view: WeakReference<View>,
- val direction: Direction,
- val shouldBeAnimated: () -> Boolean
- )
+ /**
+ * Represents a view whose animation process is in-progress. It should be immutable because the
+ * started animation should be completed.
+ */
+ private data class ViewToTranslate(val view: WeakReference<View>, val direction: Direction)
/** Direction of the animation. */
enum class Direction(val multiplier: Float) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Evaluator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Evaluator.kt
index 23742c503ed3..454294f36d2a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Evaluator.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Evaluator.kt
@@ -87,7 +87,7 @@ internal object Evaluator {
* Helper for evaluating 3-valued logical AND/OR.
*
* @param returnValueIfAnyMatches AND returns false if any value is false. OR returns true if
- * any value is true.
+ * any value is true.
*/
private fun threeValuedAndOrOr(
conditions: Collection<Condition>,
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 6bfaf5e49820..b2add4f661cb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -18,7 +18,6 @@ package com.android.systemui.shared.system;
import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
import static android.app.ActivityTaskManager.getService;
import android.annotation.NonNull;
@@ -45,6 +44,7 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
+import android.view.Display;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;
@@ -112,6 +112,13 @@ public class ActivityManagerWrapper {
}
/**
+ * @see #getRunningTasks(boolean , int)
+ */
+ public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) {
+ return getRunningTasks(filterOnlyVisibleRecents, Display.INVALID_DISPLAY);
+ }
+
+ /**
* We ask for {@link #NUM_RECENT_ACTIVITIES_REQUEST} activities because when in split screen,
* we'll get back 2 activities for each split app and one for launcher. Launcher might be more
* "recently" used than one of the split apps so if we only request 2 tasks, then we might miss
@@ -120,10 +127,12 @@ public class ActivityManagerWrapper {
* @return an array of up to {@link #NUM_RECENT_ACTIVITIES_REQUEST} running tasks
* filtering only for tasks that can be visible in the recent tasks list.
*/
- public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) {
+ public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents,
+ int displayId) {
// Note: The set of running tasks from the system is ordered by recency
List<ActivityManager.RunningTaskInfo> tasks =
- mAtm.getTasks(NUM_RECENT_ACTIVITIES_REQUEST, filterOnlyVisibleRecents);
+ mAtm.getTasks(NUM_RECENT_ACTIVITIES_REQUEST,
+ filterOnlyVisibleRecents, /* keepInExtras= */ false, displayId);
return tasks.toArray(new RunningTaskInfo[tasks.size()]);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index a25b281f807c..c5a06b48e015 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -24,7 +24,6 @@ import android.view.ViewConfiguration;
import android.widget.Button;
import com.android.internal.util.EmergencyAffordanceManager;
-import com.android.internal.widget.LockPatternUtils;
/**
* This class implements a smart emergency button that updates itself based
@@ -40,8 +39,6 @@ public class EmergencyButton extends Button {
private int mDownY;
private boolean mLongPressWasDragged;
- private LockPatternUtils mLockPatternUtils;
-
private final boolean mEnableEmergencyCallWhileSimLocked;
public EmergencyButton(Context context) {
@@ -58,7 +55,6 @@ public class EmergencyButton extends Button {
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mLockPatternUtils = new LockPatternUtils(mContext);
if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
setOnLongClickListener(v -> {
if (!mLongPressWasDragged
@@ -95,7 +91,8 @@ public class EmergencyButton extends Button {
return super.performLongClick();
}
- void updateEmergencyCallButton(boolean isInCall, boolean hasTelephonyRadio, boolean simLocked) {
+ void updateEmergencyCallButton(boolean isInCall, boolean hasTelephonyRadio, boolean simLocked,
+ boolean isSecure) {
boolean visible = false;
if (hasTelephonyRadio) {
// Emergency calling requires a telephony radio.
@@ -107,7 +104,7 @@ public class EmergencyButton extends Button {
visible = mEnableEmergencyCallWhileSimLocked;
} else {
// Only show if there is a secure screen (pin/pattern/SIM pin/SIM puk);
- visible = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser());
+ visible = isSecure;
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java
index ea808eb19b90..f7e8eb492584 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java
@@ -18,6 +18,7 @@ package com.android.keyguard;
import static com.android.systemui.DejankUtils.whitelistIpcs;
+import android.annotation.SuppressLint;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.content.Intent;
@@ -31,16 +32,22 @@ import android.telephony.TelephonyManager;
import android.util.Log;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.dagger.KeyguardBouncerScope;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.util.EmergencyDialerConstants;
import com.android.systemui.util.ViewController;
+import java.util.concurrent.Executor;
+
import javax.inject.Inject;
/** View Controller for {@link com.android.keyguard.EmergencyButton}. */
@@ -57,6 +64,9 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> {
private final MetricsLogger mMetricsLogger;
private EmergencyButtonCallback mEmergencyButtonCallback;
+ private LockPatternUtils mLockPatternUtils;
+ private Executor mMainExecutor;
+ private Executor mBackgroundExecutor;
private final KeyguardUpdateMonitorCallback mInfoCallback =
new KeyguardUpdateMonitorCallback() {
@@ -78,12 +88,15 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> {
}
};
- private EmergencyButtonController(@Nullable EmergencyButton view,
+ @VisibleForTesting
+ public EmergencyButtonController(@Nullable EmergencyButton view,
ConfigurationController configurationController,
KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager,
PowerManager powerManager, ActivityTaskManager activityTaskManager,
ShadeController shadeController,
- @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger) {
+ @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger,
+ LockPatternUtils lockPatternUtils,
+ Executor mainExecutor, Executor backgroundExecutor) {
super(view);
mConfigurationController = configurationController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -93,6 +106,9 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> {
mShadeController = shadeController;
mTelecomManager = telecomManager;
mMetricsLogger = metricsLogger;
+ mLockPatternUtils = lockPatternUtils;
+ mMainExecutor = mainExecutor;
+ mBackgroundExecutor = backgroundExecutor;
}
@Override
@@ -113,13 +129,27 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> {
mConfigurationController.removeCallback(mConfigurationListener);
}
- private void updateEmergencyCallButton() {
+ /**
+ * Updates the visibility of the emergency button.
+ *
+ * This method runs binder calls in a background thread.
+ */
+ @VisibleForTesting
+ @SuppressLint("MissingPermission")
+ public void updateEmergencyCallButton() {
if (mView != null) {
- mView.updateEmergencyCallButton(
- mTelecomManager != null && mTelecomManager.isInCall(),
- getContext().getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_TELEPHONY),
- mKeyguardUpdateMonitor.isSimPinVoiceSecure());
+ // Run in bg thread to avoid throttling the main thread with binder call.
+ mBackgroundExecutor.execute(() -> {
+ boolean isInCall = mTelecomManager != null && mTelecomManager.isInCall();
+ boolean isSecure = mLockPatternUtils
+ .isSecure(KeyguardUpdateMonitor.getCurrentUser());
+ mMainExecutor.execute(() -> mView.updateEmergencyCallButton(
+ /* isInCall= */ isInCall,
+ /* hasTelephonyRadio= */ getContext().getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_TELEPHONY),
+ /* simLocked= */ mKeyguardUpdateMonitor.isSimPinVoiceSecure(),
+ /* isSecure= */ isSecure));
+ });
}
}
@@ -129,6 +159,7 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> {
/**
* Shows the emergency dialer or returns the user to the existing call.
*/
+ @SuppressLint("MissingPermission")
public void takeEmergencyCallAction() {
mMetricsLogger.action(MetricsEvent.ACTION_EMERGENCY_CALL);
if (mPowerManager != null) {
@@ -136,29 +167,35 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> {
}
mActivityTaskManager.stopSystemLockTaskMode();
mShadeController.collapseShade(false);
- if (mTelecomManager != null && mTelecomManager.isInCall()) {
- mTelecomManager.showInCallScreen(false);
- if (mEmergencyButtonCallback != null) {
- mEmergencyButtonCallback.onEmergencyButtonClickedWhenInCall();
- }
- } else {
- mKeyguardUpdateMonitor.reportEmergencyCallAction(true /* bypassHandler */);
- if (mTelecomManager == null) {
- Log.wtf(LOG_TAG, "TelecomManager was null, cannot launch emergency dialer");
- return;
- }
- Intent emergencyDialIntent =
- mTelecomManager.createLaunchEmergencyDialerIntent(null /* number*/)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
- | Intent.FLAG_ACTIVITY_CLEAR_TOP)
- .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
- EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON);
-
- getContext().startActivityAsUser(emergencyDialIntent,
- ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(),
- new UserHandle(KeyguardUpdateMonitor.getCurrentUser()));
- }
+ // Run in bg thread to avoid throttling the main thread with binder call.
+ mBackgroundExecutor.execute(() -> {
+ boolean isInCall = mTelecomManager != null && mTelecomManager.isInCall();
+ mMainExecutor.execute(() -> {
+ if (isInCall) {
+ mTelecomManager.showInCallScreen(false);
+ if (mEmergencyButtonCallback != null) {
+ mEmergencyButtonCallback.onEmergencyButtonClickedWhenInCall();
+ }
+ } else {
+ mKeyguardUpdateMonitor.reportEmergencyCallAction(true /* bypassHandler */);
+ if (mTelecomManager == null) {
+ Log.wtf(LOG_TAG, "TelecomManager was null, cannot launch emergency dialer");
+ return;
+ }
+ Intent emergencyDialIntent =
+ mTelecomManager.createLaunchEmergencyDialerIntent(null /* number*/)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
+ EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON);
+
+ getContext().startActivityAsUser(emergencyDialIntent,
+ ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(),
+ new UserHandle(KeyguardUpdateMonitor.getCurrentUser()));
+ }
+ });
+ });
}
/** */
@@ -178,13 +215,19 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> {
@Nullable
private final TelecomManager mTelecomManager;
private final MetricsLogger mMetricsLogger;
+ private final LockPatternUtils mLockPatternUtils;
+ private final Executor mMainExecutor;
+ private final Executor mBackgroundExecutor;
@Inject
public Factory(ConfigurationController configurationController,
KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager,
PowerManager powerManager, ActivityTaskManager activityTaskManager,
ShadeController shadeController,
- @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger) {
+ @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger,
+ LockPatternUtils lockPatternUtils,
+ @Main Executor mainExecutor,
+ @Background Executor backgroundExecutor) {
mConfigurationController = configurationController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -194,14 +237,17 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> {
mShadeController = shadeController;
mTelecomManager = telecomManager;
mMetricsLogger = metricsLogger;
+ mLockPatternUtils = lockPatternUtils;
+ mMainExecutor = mainExecutor;
+ mBackgroundExecutor = backgroundExecutor;
}
/** Construct an {@link com.android.keyguard.EmergencyButtonController}. */
public EmergencyButtonController create(EmergencyButton view) {
return new EmergencyButtonController(view, mConfigurationController,
mKeyguardUpdateMonitor, mTelephonyManager, mPowerManager, mActivityTaskManager,
- mShadeController,
- mTelecomManager, mMetricsLogger);
+ mShadeController, mTelecomManager, mMetricsLogger, mLockPatternUtils,
+ mMainExecutor, mBackgroundExecutor);
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
index e0cf7b6a2bc4..d8085b9f9f2e 100644
--- a/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
+++ b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
@@ -132,6 +132,7 @@ private object InternalFaceAuthReasons {
/**
* UiEvents that are logged to identify why face auth is being triggered.
+ *
* @param extraInfo is logged as the position. See [UiEventLogger#logWithInstanceIdAndPosition]
*/
enum class FaceAuthUiEvent
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
index fe8b8c944d13..c98e9b40e7ab 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
@@ -40,7 +40,7 @@ data class KeyguardFaceListenModel(
var keyguardGoingAway: Boolean = false,
var listeningForFaceAssistant: Boolean = false,
var occludingAppRequestingFaceAuth: Boolean = false,
- val postureAllowsListening: Boolean = false,
+ var postureAllowsListening: Boolean = false,
var primaryUser: Boolean = false,
var secureCameraLaunched: Boolean = false,
var supportsDetect: Boolean = false,
@@ -70,6 +70,7 @@ data class KeyguardFaceListenModel(
listeningForFaceAssistant.toString(),
occludingAppRequestingFaceAuth.toString(),
primaryUser.toString(),
+ postureAllowsListening.toString(),
secureCameraLaunched.toString(),
supportsDetect.toString(),
switchingUser.toString(),
@@ -109,6 +110,7 @@ data class KeyguardFaceListenModel(
listeningForFaceAssistant = model.listeningForFaceAssistant
occludingAppRequestingFaceAuth = model.occludingAppRequestingFaceAuth
primaryUser = model.primaryUser
+ postureAllowsListening = model.postureAllowsListening
secureCameraLaunched = model.secureCameraLaunched
supportsDetect = model.supportsDetect
switchingUser = model.switchingUser
@@ -152,6 +154,7 @@ data class KeyguardFaceListenModel(
"listeningForFaceAssistant",
"occludingAppRequestingFaceAuth",
"primaryUser",
+ "postureAllowsListening",
"secureCameraLaunched",
"supportsDetect",
"switchingUser",
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index c1fae9e44bd3..33bea027cd20 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -69,6 +69,7 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
private Interpolator mLinearOutSlowInInterpolator;
private Interpolator mFastOutLinearInInterpolator;
+ private DisappearAnimationListener mDisappearAnimationListener;
public KeyguardPasswordView(Context context) {
this(context, null);
@@ -186,9 +187,13 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
return;
}
Insets shownInsets = controller.getShownStateInsets();
- Insets insets = Insets.add(shownInsets, Insets.of(0, 0, 0,
- (int) (-shownInsets.bottom / 4
- * anim.getAnimatedFraction())));
+ int dist = (int) (-shownInsets.bottom / 4
+ * anim.getAnimatedFraction());
+ Insets insets = Insets.add(shownInsets, Insets.of(0, 0, 0, dist));
+ if (mDisappearAnimationListener != null) {
+ mDisappearAnimationListener.setTranslationY(-dist);
+ }
+
controller.setInsetsAndAlpha(insets,
(float) animation.getAnimatedValue(),
anim.getAnimatedFraction());
@@ -209,6 +214,7 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
controller.finish(false);
runOnFinishImeAnimationRunnable();
finishRunnable.run();
+ mDisappearAnimationListener = null;
Trace.endSection();
});
}
@@ -286,4 +292,19 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
}
});
}
+
+ /**
+ * Listens to the progress of the disappear animation and handles it.
+ */
+ interface DisappearAnimationListener {
+ void setTranslationY(int transY);
+ }
+
+ /**
+ * Set an instance of the disappear animation listener to this class. This will be
+ * removed when the animation completes.
+ */
+ public void setDisappearAnimationListener(DisappearAnimationListener listener) {
+ mDisappearAnimationListener = listener;
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
index d221e22a4fcd..a010c9a16517 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
@@ -26,6 +26,7 @@ import android.text.method.TextKeyListener;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
+import android.view.WindowInsets;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
@@ -156,6 +157,15 @@ public class KeyguardPasswordViewController
// TODO: Remove this workaround by ensuring such a race condition never happens.
mMainExecutor.executeDelayed(
this::updateSwitchImeButton, DELAY_MILLIS_TO_REEVALUATE_IME_SWITCH_ICON);
+ mView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
+ @Override
+ public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
+ if (!mKeyguardViewController.isBouncerShowing()) {
+ mView.hideKeyboard();
+ }
+ return insets;
+ }
+ });
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index f164e7d33642..66d5d097ab04 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -39,7 +39,6 @@ import static java.lang.Integer.max;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
@@ -174,6 +173,17 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
private @Mode int mCurrentMode = MODE_UNINITIALIZED;
private int mWidth = -1;
+ /**
+ * This callback is used to animate KeyguardSecurityContainer and its child views based on
+ * the interaction with the ime. After
+ * {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)},
+ * {@link #onApplyWindowInsets} is called where we
+ * set the bottom padding to be the height of the keyboard. We use this padding to determine
+ * the delta of vertical distance for y-translation animations.
+ * Note that bottom padding is not set when the disappear animation is started because
+ * we are deferring the y translation logic to the animator in
+ * {@link KeyguardPasswordView#startDisappearAnimation(Runnable)}
+ */
private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
@@ -214,7 +224,6 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
continue;
}
interpolatedFraction = animation.getInterpolatedFraction();
-
final int paddingBottom = (int) MathUtils.lerp(
start, end,
interpolatedFraction);
@@ -569,13 +578,21 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
*/
public void startDisappearAnimation(SecurityMode securitySelection) {
mDisappearAnimRunning = true;
- mViewMode.startDisappearAnimation(securitySelection);
+ if (securitySelection == SecurityMode.Password
+ && mSecurityViewFlipper.getSecurityView() instanceof KeyguardPasswordView) {
+ ((KeyguardPasswordView) mSecurityViewFlipper.getSecurityView())
+ .setDisappearAnimationListener(this::setTranslationY);
+ } else {
+ mViewMode.startDisappearAnimation(securitySelection);
+ }
}
/**
* This will run when the bouncer shows in all cases except when the user drags the bouncer up.
*/
public void startAppearAnimation(SecurityMode securityMode) {
+ setTranslationY(0f);
+ setAlpha(1f);
updateChildren(0 /* translationY */, 1f /* alpha */);
mViewMode.startAppearAnimation(securityMode);
}
@@ -624,7 +641,13 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
int inset = max(bottomInset, imeInset);
int paddingBottom = max(inset, getContext().getResources()
.getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin));
- setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom);
+ // If security mode is password, we rely on the animation value of defined in
+ // KeyguardPasswordView to determine the y translation animation.
+ // This means that we will prevent the WindowInsetsAnimationCallback from setting any y
+ // translation values by preventing the setting of the padding here.
+ if (!mDisappearAnimRunning) {
+ setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom);
+ }
return insets.inset(0, 0, 0, inset);
}
@@ -1044,13 +1067,10 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
int yTranslation = mResources.getDimensionPixelSize(R.dimen.disappear_y_translation);
- AnimatorSet anims = new AnimatorSet();
ObjectAnimator yAnim = ObjectAnimator.ofFloat(mView, View.TRANSLATION_Y, yTranslation);
- ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(mView, View.ALPHA, 0f);
-
- anims.setInterpolator(Interpolators.STANDARD_ACCELERATE);
- anims.playTogether(alphaAnim, yAnim);
- anims.start();
+ yAnim.setInterpolator(Interpolators.STANDARD_ACCELERATE);
+ yAnim.setDuration(500);
+ yAnim.start();
}
private void setupUserSwitcher() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index b8bb2603fa03..c32b8530d589 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -636,12 +636,17 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
public void startAppearAnimation() {
if (mCurrentSecurityMode != SecurityMode.None) {
- mView.setAlpha(1f);
+ setAlpha(1f);
mView.startAppearAnimation(mCurrentSecurityMode);
getCurrentSecurityController().startAppearAnimation();
}
}
+ /** Set the alpha of the security container view */
+ public void setAlpha(float alpha) {
+ mView.setAlpha(alpha);
+ }
+
public boolean startDisappearAnimation(Runnable onFinishRunnable) {
boolean didRunAnimation = false;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index b53b868025e8..f4c581552bc4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -21,8 +21,6 @@ import android.util.Slog;
import com.android.keyguard.KeyguardClockSwitch.ClockSize;
import com.android.keyguard.logging.KeyguardLogger;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ClockAnimations;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -62,7 +60,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
KeyguardUpdateMonitor keyguardUpdateMonitor,
ConfigurationController configurationController,
DozeParameters dozeParameters,
- FeatureFlags featureFlags,
ScreenOffAnimationController screenOffAnimationController,
KeyguardLogger logger) {
super(keyguardStatusView);
@@ -73,8 +70,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController,
dozeParameters, screenOffAnimationController, /* animateYPos= */ true,
logger.getBuffer());
- mKeyguardVisibilityHelper.setOcclusionTransitionFlagEnabled(
- featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION));
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index b2d4215b388a..2370c8a27da7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -73,11 +73,9 @@ import static com.android.systemui.statusbar.policy.DevicePostureController.DEVI
import android.annotation.AnyThread;
import android.annotation.MainThread;
import android.annotation.SuppressLint;
-import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager.RootTaskInfo;
import android.app.AlarmManager;
-import android.app.UserSwitchObserver;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
@@ -104,7 +102,6 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.nfc.NfcAdapter;
import android.os.CancellationSignal;
import android.os.Handler;
-import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
@@ -156,6 +153,7 @@ import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.DevicePostureController;
+import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.Assert;
import com.android.systemui.util.settings.SecureSettings;
@@ -175,6 +173,7 @@ import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.TimeZone;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
@@ -361,7 +360,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private final FaceManager mFaceManager;
private final LockPatternUtils mLockPatternUtils;
@VisibleForTesting
- @DevicePostureController.DevicePostureInt
+ @DevicePostureInt
protected int mConfigFaceAuthSupportedPosture;
private KeyguardBypassController mKeyguardBypassController;
@@ -678,7 +677,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
public void onTrustManagedChanged(boolean managed, int userId) {
Assert.isMainThread();
mUserTrustIsManaged.put(userId, managed);
- mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId));
+ boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userId);
+ mLogger.logTrustUsuallyManagedUpdated(userId, mUserTrustIsUsuallyManaged.get(userId),
+ trustUsuallyManaged, "onTrustManagedChanged");
+ mUserTrustIsUsuallyManaged.put(userId, trustUsuallyManaged);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -816,6 +818,19 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
}
+ private void onBiometricDetected(int userId, BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) {
+ Assert.isMainThread();
+ Trace.beginSection("KeyGuardUpdateMonitor#onBiometricDetected");
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onBiometricDetected(userId, biometricSourceType, isStrongBiometric);
+ }
+ }
+ Trace.endSection();
+ }
+
@VisibleForTesting
protected void onFingerprintAuthenticated(int userId, boolean isStrongBiometric) {
Assert.isMainThread();
@@ -853,7 +868,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
mBackgroundExecutor.execute(
- () -> mLockPatternUtils.reportSuccessfulBiometricUnlock(isStrongBiometric, userId));
+ () -> {
+ mLogger.logReportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+ mLockPatternUtils.reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+ });
}
private void handleFingerprintAuthFailed() {
@@ -892,6 +910,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
}
+ private void handleBiometricDetected(int authUserId, BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) {
+ Trace.beginSection("KeyGuardUpdateMonitor#handlerBiometricDetected");
+ onBiometricDetected(authUserId, biometricSourceType, isStrongBiometric);
+ if (biometricSourceType == FINGERPRINT) {
+ mLogger.logFingerprintDetected(authUserId, isStrongBiometric);
+ } else if (biometricSourceType == FACE) {
+ mLogger.logFaceDetected(authUserId, isStrongBiometric);
+ setFaceRunningState(BIOMETRIC_STATE_STOPPED);
+ }
+
+ Trace.endSection();
+ }
+
private void handleFingerprintAuthenticated(int authUserId, boolean isStrongBiometric) {
Trace.beginSection("KeyGuardUpdateMonitor#handlerFingerPrintAuthenticated");
if (mHandler.hasCallbacks(mFpCancelNotReceived)) {
@@ -943,8 +975,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private void onFingerprintCancelNotReceived() {
mLogger.e("Fp cancellation not received, transitioning to STOPPED");
+ final boolean wasCancellingRestarting = mFingerprintRunningState
+ == BIOMETRIC_STATE_CANCELLING_RESTARTING;
mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
- KeyguardUpdateMonitor.this.updateFingerprintListeningState(BIOMETRIC_ACTION_STOP);
+ if (wasCancellingRestarting) {
+ KeyguardUpdateMonitor.this.updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
+ } else {
+ KeyguardUpdateMonitor.this.updateFingerprintListeningState(BIOMETRIC_ACTION_STOP);
+ }
}
private void handleFingerprintError(int msgId, String errString) {
@@ -1031,6 +1069,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
() -> updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE),
getBiometricLockoutDelay());
} else {
+ boolean temporaryLockoutReset = wasLockout && !mFingerprintLockedOut;
+ if (temporaryLockoutReset) {
+ mLogger.d("temporaryLockoutReset - stopListeningForFingerprint() to stop"
+ + " detectFingerprint");
+ stopListeningForFingerprint();
+ }
updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
@@ -1730,10 +1774,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
};
+ private final FingerprintManager.FingerprintDetectionCallback mFingerprintDetectionCallback =
+ (sensorId, userId, isStrongBiometric) -> {
+ // Trigger the fingerprint detected path so the bouncer can be shown
+ handleBiometricDetected(userId, FINGERPRINT, isStrongBiometric);
+ };
+
private final FaceManager.FaceDetectionCallback mFaceDetectionCallback
= (sensorId, userId, isStrongBiometric) -> {
- // Trigger the face success path so the bouncer can be shown
- handleFaceAuthenticated(userId, isStrongBiometric);
+ // Trigger the face detected path so the bouncer can be shown
+ handleBiometricDetected(userId, FACE, isStrongBiometric);
};
@VisibleForTesting
@@ -1797,10 +1847,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
final DevicePostureController.Callback mPostureCallback =
new DevicePostureController.Callback() {
@Override
- public void onPostureChanged(int posture) {
+ public void onPostureChanged(@DevicePostureInt int posture) {
+ boolean currentPostureAllowsFaceAuth = doesPostureAllowFaceAuth(mPostureState);
+ boolean newPostureAllowsFaceAuth = doesPostureAllowFaceAuth(posture);
mPostureState = posture;
- updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_UPDATED_POSTURE_CHANGED);
+ if (currentPostureAllowsFaceAuth && !newPostureAllowsFaceAuth) {
+ mLogger.d("New posture does not allow face auth, stopping it");
+ updateFaceListeningState(BIOMETRIC_ACTION_STOP,
+ FACE_AUTH_UPDATED_POSTURE_CHANGED);
+ }
}
};
@@ -2158,7 +2213,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
handleDevicePolicyManagerStateChanged(msg.arg1);
break;
case MSG_USER_SWITCHING:
- handleUserSwitching(msg.arg1, (IRemoteCallback) msg.obj);
+ handleUserSwitching(msg.arg1, (CountDownLatch) msg.obj);
break;
case MSG_USER_SWITCH_COMPLETE:
handleUserSwitchComplete(msg.arg1);
@@ -2283,11 +2338,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mHandler, UserHandle.ALL);
mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
- try {
- ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG);
- } catch (RemoteException e) {
- e.rethrowAsRuntimeException();
- }
+ mUserTracker.addCallback(mUserChangedCallback, mainExecutor);
mTrustManager.registerTrustListener(this);
@@ -2333,8 +2384,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
updateSecondaryLockscreenRequirement(user);
List<UserInfo> allUsers = mUserManager.getUsers();
for (UserInfo userInfo : allUsers) {
+ boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userInfo.id);
+ mLogger.logTrustUsuallyManagedUpdated(userInfo.id,
+ mUserTrustIsUsuallyManaged.get(userInfo.id),
+ trustUsuallyManaged, "init from constructor");
mUserTrustIsUsuallyManaged.put(userInfo.id,
- mTrustManager.isTrustUsuallyManaged(userInfo.id));
+ trustUsuallyManaged);
}
updateAirplaneModeState();
@@ -2374,10 +2429,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
private void updateFaceEnrolled(int userId) {
- mIsFaceEnrolled = whitelistIpcs(
+ Boolean isFaceEnrolled = whitelistIpcs(
() -> mFaceManager != null && mFaceManager.isHardwareDetected()
&& mFaceManager.hasEnrolledTemplates(userId)
&& mBiometricEnabledForUser.get(userId));
+ mIsFaceEnrolled = isFaceEnrolled;
+ mLogger.logFaceEnrolledUpdated(mIsFaceEnrolled, isFaceEnrolled);
}
public boolean isFaceSupported() {
@@ -2423,17 +2480,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
return mIsFaceEnrolled;
}
- private final UserSwitchObserver mUserSwitchObserver = new UserSwitchObserver() {
+ private final UserTracker.Callback mUserChangedCallback = new UserTracker.Callback() {
@Override
- public void onUserSwitching(int newUserId, IRemoteCallback reply) {
+ public void onUserChanging(int newUser, Context userContext, CountDownLatch latch) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHING,
- newUserId, 0, reply));
+ newUser, 0, latch));
}
@Override
- public void onUserSwitchComplete(int newUserId) {
+ public void onUserChanged(int newUser, Context userContext) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCH_COMPLETE,
- newUserId, 0));
+ newUser, 0));
}
};
@@ -2456,11 +2513,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
// If this message exists, we should not authenticate again until this message is
// consumed by the handler
if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
+ mLogger.logHandlerHasAuthContinueMsgs(action);
return;
}
// don't start running fingerprint until they're registered
if (!mAuthController.areAllFingerprintAuthenticatorsRegistered()) {
+ mLogger.d("All FP authenticators not registered, skipping FP listening state update");
return;
}
final boolean shouldListenForFingerprint = shouldListenForFingerprint(isUdfpsSupported());
@@ -2765,8 +2824,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
boolean shouldListen = shouldListenKeyguardState && shouldListenUserState
&& shouldListenBouncerState && shouldListenUdfpsState
- && shouldListenSideFpsState
- && !isFingerprintLockedOut();
+ && shouldListenSideFpsState;
logListenerModelData(
new KeyguardFingerprintListenModel(
System.currentTimeMillis(),
@@ -2834,9 +2892,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
final boolean biometricEnabledForUser = mBiometricEnabledForUser.get(user);
final boolean shouldListenForFaceAssistant = shouldListenForFaceAssistant();
final boolean isUdfpsFingerDown = mAuthController.isUdfpsFingerDown();
- final boolean isPostureAllowedForFaceAuth =
- mConfigFaceAuthSupportedPosture == 0 /* DEVICE_POSTURE_UNKNOWN */ ? true
- : (mPostureState == mConfigFaceAuthSupportedPosture);
+ final boolean isPostureAllowedForFaceAuth = doesPostureAllowFaceAuth(mPostureState);
// Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
// instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
final boolean shouldListen =
@@ -2885,6 +2941,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
return shouldListen;
}
+ private boolean doesPostureAllowFaceAuth(@DevicePostureInt int posture) {
+ return mConfigFaceAuthSupportedPosture == DEVICE_POSTURE_UNKNOWN
+ || (posture == mConfigFaceAuthSupportedPosture);
+ }
+
private void logListenerModelData(@NonNull KeyguardListenModel model) {
mLogger.logKeyguardListenerModel(model);
if (model instanceof KeyguardFingerprintListenModel) {
@@ -2921,11 +2982,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mLogger.v("startListeningForFingerprint - detect");
mFpm.detectFingerprint(
mFingerprintCancelSignal,
- (sensorId, user, isStrongBiometric) -> {
- mLogger.d("fingerprint detected");
- // Trigger the fingerprint success path so the bouncer can be shown
- handleFingerprintAuthenticated(user, isStrongBiometric);
- },
+ mFingerprintDetectionCallback,
userId);
} else {
mLogger.v("startListeningForFingerprint - authenticate");
@@ -3037,8 +3094,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@VisibleForTesting
boolean isUnlockWithFingerprintPossible(int userId) {
// TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once.
- mIsUnlockWithFingerprintPossible.put(userId, mFpm != null && mFpm.isHardwareDetected()
- && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId));
+ boolean fpEnrolled = mFpm != null && mFpm.isHardwareDetected()
+ && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId);
+ mLogger.logFpEnrolledUpdated(userId,
+ mIsUnlockWithFingerprintPossible.getOrDefault(userId, false),
+ fpEnrolled);
+ mIsUnlockWithFingerprintPossible.put(userId, fpEnrolled);
return mIsUnlockWithFingerprintPossible.get(userId);
}
@@ -3151,21 +3212,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
* Handle {@link #MSG_USER_SWITCHING}
*/
@VisibleForTesting
- void handleUserSwitching(int userId, IRemoteCallback reply) {
+ void handleUserSwitching(int userId, CountDownLatch latch) {
Assert.isMainThread();
clearBiometricRecognized();
- mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId));
+ boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userId);
+ mLogger.logTrustUsuallyManagedUpdated(userId, mUserTrustIsUsuallyManaged.get(userId),
+ trustUsuallyManaged, "userSwitching");
+ mUserTrustIsUsuallyManaged.put(userId, trustUsuallyManaged);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onUserSwitching(userId);
}
}
- try {
- reply.sendResult(null);
- } catch (RemoteException e) {
- mLogger.logException(e, "Ignored exception while userSwitching");
- }
+ latch.countDown();
}
/**
@@ -3935,13 +3995,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mContext.getContentResolver().unregisterContentObserver(mTimeFormatChangeObserver);
}
- try {
- ActivityManager.getService().unregisterUserSwitchObserver(mUserSwitchObserver);
- } catch (RemoteException e) {
- mLogger.logException(
- e,
- "RemoteException onDestroy. cannot unregister userSwitchObserver");
- }
+ mUserTracker.removeCallback(mUserChangedCallback);
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 38f3e5065eec..0d4889a4c39f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -214,7 +214,7 @@ public class KeyguardUpdateMonitorCallback {
public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) { }
/**
- * Called when a biometric is recognized.
+ * Called when a biometric is authenticated.
* @param userId the user id for which the biometric sample was authenticated
* @param biometricSourceType
*/
@@ -222,6 +222,14 @@ public class KeyguardUpdateMonitorCallback {
boolean isStrongBiometric) { }
/**
+ * Called when a biometric is detected but not successfully authenticated.
+ * @param userId the user id for which the biometric sample was detected
+ * @param biometricSourceType
+ */
+ public void onBiometricDetected(int userId, BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) { }
+
+ /**
* Called when biometric authentication provides help string (e.g. "Try again")
* @param msgId
* @param helpString
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
index 7e48193bfc62..a678edc0eb06 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
@@ -28,7 +28,6 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
-import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -49,7 +48,6 @@ public class KeyguardVisibilityHelper {
private boolean mAnimateYPos;
private boolean mKeyguardViewVisibilityAnimating;
private boolean mLastOccludedState = false;
- private boolean mIsUnoccludeTransitionFlagEnabled = false;
private final AnimationProperties mAnimationProperties = new AnimationProperties();
private final LogBuffer mLogBuffer;
@@ -77,10 +75,6 @@ public class KeyguardVisibilityHelper {
return mKeyguardViewVisibilityAnimating;
}
- public void setOcclusionTransitionFlagEnabled(boolean enabled) {
- mIsUnoccludeTransitionFlagEnabled = enabled;
- }
-
/**
* Set the visibility of a keyguard view based on some new state.
*/
@@ -156,24 +150,9 @@ public class KeyguardVisibilityHelper {
// since it may need to be cancelled due to keyguard lifecycle events.
mScreenOffAnimationController.animateInKeyguard(
mView, mAnimateKeyguardStatusViewVisibleEndRunnable);
- } else if (!mIsUnoccludeTransitionFlagEnabled && mLastOccludedState && !isOccluded) {
- // An activity was displayed over the lock screen, and has now gone away
- log("Unoccluded transition");
- mView.setVisibility(View.VISIBLE);
- mView.setAlpha(0f);
-
- mView.animate()
- .setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .alpha(1f)
- .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable)
- .start();
} else {
log("Direct set Visibility to VISIBLE");
mView.setVisibility(View.VISIBLE);
- if (!mIsUnoccludeTransitionFlagEnabled) {
- mView.setAlpha(1f);
- }
}
} else {
log("Direct set Visibility to GONE");
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
index b30a0e010e4b..ad669099284f 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -51,7 +51,6 @@ class NumPadAnimator {
private float mStartRadius;
private float mEndRadius;
private int mHeight;
- private boolean mInitialized;
private static final int EXPAND_ANIMATION_MS = 100;
private static final int EXPAND_COLOR_ANIMATION_MS = 50;
@@ -93,15 +92,15 @@ class NumPadAnimator {
}
void onLayout(int height) {
+ boolean shouldUpdateHeight = height != mHeight;
mHeight = height;
mStartRadius = height / 2f;
mEndRadius = height / 4f;
mExpandAnimator.setFloatValues(mStartRadius, mEndRadius);
mContractAnimator.setFloatValues(mEndRadius, mStartRadius);
// Set initial corner radius.
- if (!mInitialized) {
+ if (shouldUpdateHeight) {
mBackground.setCornerRadius(mStartRadius);
- mInitialized = true;
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 0a4880e1ce66..3b0644eaab82 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -33,7 +33,6 @@ import android.widget.TextView;
import androidx.annotation.Nullable;
-import com.android.internal.widget.LockPatternUtils;
import com.android.settingslib.Utils;
import com.android.systemui.R;
@@ -46,7 +45,6 @@ public class NumPadKey extends ViewGroup implements NumPadAnimationListener {
private final TextView mDigitText;
private final TextView mKlondikeText;
- private final LockPatternUtils mLockPatternUtils;
private final PowerManager mPM;
private int mDigit = -1;
@@ -107,7 +105,6 @@ public class NumPadKey extends ViewGroup implements NumPadAnimationListener {
setOnHoverListener(new LiftToActivateListener(
(AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE)));
- mLockPatternUtils = new LockPatternUtils(context);
mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
index bc0bd8c53d26..20f90072161b 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
@@ -16,6 +16,7 @@
package com.android.keyguard.logging
+import android.hardware.biometrics.BiometricSourceType
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.dagger.BiometricLog
import com.android.systemui.plugins.log.LogBuffer
@@ -157,6 +158,36 @@ class BiometricUnlockLogger @Inject constructor(@BiometricLog private val logBuf
}
)
}
+
+ fun deferringAuthenticationDueToSleep(
+ userId: Int,
+ biometricSourceType: BiometricSourceType,
+ alreadyPendingAuth: Boolean
+ ) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = userId
+ str1 = biometricSourceType.name
+ bool2 = alreadyPendingAuth
+ },
+ {
+ "onBiometricAuthenticated, deferring auth: userId: $int1, " +
+ "biometricSourceType: $str1, " +
+ "goingToSleep: true, " +
+ "mPendingAuthentication != null: $bool2"
+ }
+ )
+ }
+
+ fun finishedGoingToSleepWithPendingAuth() {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ "onFinishedGoingToSleep with pendingAuthenticated != null"
+ )
+ }
}
private fun wakeAndUnlockModeToString(mode: Int): String {
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
index 379c78ad8d0e..51aca070b180 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
@@ -16,6 +16,7 @@
package com.android.keyguard.logging
+import com.android.systemui.biometrics.AuthRippleController
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController
import com.android.systemui.log.dagger.KeyguardLog
import com.android.systemui.plugins.log.LogBuffer
@@ -120,4 +121,29 @@ constructor(
"type=${KeyguardIndicationRotateTextViewController.indicationTypeToString(type)}"
}
}
+
+ fun notShowingUnlockRipple(keyguardNotShowing: Boolean, unlockNotAllowed: Boolean) {
+ buffer.log(
+ AuthRippleController.TAG,
+ LogLevel.DEBUG,
+ {
+ bool1 = keyguardNotShowing
+ bool2 = unlockNotAllowed
+ },
+ { "Not showing unlock ripple: keyguardNotShowing: $bool1, unlockNotAllowed: $bool2" }
+ )
+ }
+
+ fun showingUnlockRippleAt(x: Int, y: Int, context: String) {
+ buffer.log(
+ AuthRippleController.TAG,
+ LogLevel.DEBUG,
+ {
+ int1 = x
+ int2 = y
+ str1 = context
+ },
+ { "Showing unlock ripple with center (x, y): ($int1, $int2), context: $str1" }
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index c414c088529c..2403d1116360 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -26,6 +26,7 @@ import com.android.keyguard.FaceAuthUiEvent
import com.android.keyguard.KeyguardListenModel
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.keyguard.TrustGrantFlags
+import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.plugins.log.LogLevel.DEBUG
@@ -33,18 +34,15 @@ import com.android.systemui.plugins.log.LogLevel.ERROR
import com.android.systemui.plugins.log.LogLevel.INFO
import com.android.systemui.plugins.log.LogLevel.VERBOSE
import com.android.systemui.plugins.log.LogLevel.WARNING
-import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
private const val TAG = "KeyguardUpdateMonitorLog"
-/**
- * Helper class for logging for [com.android.keyguard.KeyguardUpdateMonitor]
- */
-class KeyguardUpdateMonitorLogger @Inject constructor(
- @KeyguardUpdateMonitorLog private val logBuffer: LogBuffer
-) {
+/** Helper class for logging for [com.android.keyguard.KeyguardUpdateMonitor] */
+class KeyguardUpdateMonitorLogger
+@Inject
+constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) {
fun d(@CompileTimeConstant msg: String) = log(msg, DEBUG)
fun e(@CompileTimeConstant msg: String) = log(msg, ERROR)
@@ -56,15 +54,16 @@ class KeyguardUpdateMonitorLogger @Inject constructor(
fun log(@CompileTimeConstant msg: String, level: LogLevel) = logBuffer.log(TAG, level, msg)
fun logActiveUnlockTriggered(reason: String?) {
- logBuffer.log("ActiveUnlock", DEBUG,
- { str1 = reason },
- { "initiate active unlock triggerReason=$str1" })
+ logBuffer.log(
+ "ActiveUnlock",
+ DEBUG,
+ { str1 = reason },
+ { "initiate active unlock triggerReason=$str1" }
+ )
}
fun logAuthInterruptDetected(active: Boolean) {
- logBuffer.log(TAG, DEBUG,
- { bool1 = active },
- { "onAuthInterruptDetected($bool1)" })
+ logBuffer.log(TAG, DEBUG, { bool1 = active }, { "onAuthInterruptDetected($bool1)" })
}
fun logBroadcastReceived(action: String?) {
@@ -72,9 +71,12 @@ class KeyguardUpdateMonitorLogger @Inject constructor(
}
fun logDeviceProvisionedState(deviceProvisioned: Boolean) {
- logBuffer.log(TAG, DEBUG,
- { bool1 = deviceProvisioned },
- { "DEVICE_PROVISIONED state = $bool1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { bool1 = deviceProvisioned },
+ { "DEVICE_PROVISIONED state = $bool1" }
+ )
}
fun logException(ex: Exception, @CompileTimeConstant logMsg: String) {
@@ -82,46 +84,56 @@ class KeyguardUpdateMonitorLogger @Inject constructor(
}
fun logFaceAcquired(acquireInfo: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = acquireInfo },
- { "Face acquired acquireInfo=$int1" })
+ logBuffer.log(TAG, DEBUG, { int1 = acquireInfo }, { "Face acquired acquireInfo=$int1" })
}
fun logFaceAuthDisabledForUser(userId: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = userId },
- { "Face authentication disabled by DPM for userId: $int1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { int1 = userId },
+ { "Face authentication disabled by DPM for userId: $int1" }
+ )
}
fun logFaceAuthError(msgId: Int, originalErrMsg: String) {
- logBuffer.log(TAG, DEBUG, {
- str1 = originalErrMsg
- int1 = msgId
- }, { "Face error received: $str1 msgId= $int1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = originalErrMsg
+ int1 = msgId
+ },
+ { "Face error received: $str1 msgId= $int1" }
+ )
}
fun logFaceAuthForWrongUser(authUserId: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = authUserId },
- { "Face authenticated for wrong user: $int1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { int1 = authUserId },
+ { "Face authenticated for wrong user: $int1" }
+ )
}
fun logFaceAuthHelpMsg(msgId: Int, helpMsg: String?) {
- logBuffer.log(TAG, DEBUG, {
- int1 = msgId
- str1 = helpMsg
- }, { "Face help received, msgId: $int1 msg: $str1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = msgId
+ str1 = helpMsg
+ },
+ { "Face help received, msgId: $int1 msg: $str1" }
+ )
}
fun logFaceAuthRequested(reason: String?) {
- logBuffer.log(TAG, DEBUG, {
- str1 = reason
- }, { "requestFaceAuth() reason=$str1" })
+ logBuffer.log(TAG, DEBUG, { str1 = reason }, { "requestFaceAuth() reason=$str1" })
}
fun logFaceAuthSuccess(userId: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = userId },
- { "Face auth succeeded for user $int1" })
+ logBuffer.log(TAG, DEBUG, { int1 = userId }, { "Face auth succeeded for user $int1" })
}
fun logFaceLockoutReset(@LockoutMode mode: Int) {
@@ -133,21 +145,30 @@ class KeyguardUpdateMonitorLogger @Inject constructor(
}
fun logFaceUnlockPossible(isFaceUnlockPossible: Boolean) {
- logBuffer.log(TAG, DEBUG,
- { bool1 = isFaceUnlockPossible },
- {"isUnlockWithFacePossible: $bool1"})
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { bool1 = isFaceUnlockPossible },
+ { "isUnlockWithFacePossible: $bool1" }
+ )
}
fun logFingerprintAuthForWrongUser(authUserId: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = authUserId },
- { "Fingerprint authenticated for wrong user: $int1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { int1 = authUserId },
+ { "Fingerprint authenticated for wrong user: $int1" }
+ )
}
fun logFingerprintDisabledForUser(userId: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = userId },
- { "Fingerprint disabled by DPM for userId: $int1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { int1 = userId },
+ { "Fingerprint disabled by DPM for userId: $int1" }
+ )
}
fun logFingerprintLockoutReset(@LockoutMode mode: Int) {
@@ -155,42 +176,77 @@ class KeyguardUpdateMonitorLogger @Inject constructor(
}
fun logFingerprintRunningState(fingerprintRunningState: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = fingerprintRunningState },
- { "fingerprintRunningState: $int1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { int1 = fingerprintRunningState },
+ { "fingerprintRunningState: $int1" }
+ )
}
fun logFingerprintSuccess(userId: Int, isStrongBiometric: Boolean) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = userId
+ bool1 = isStrongBiometric
+ },
+ { "Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1" }
+ )
+ }
+
+ fun logFaceDetected(userId: Int, isStrongBiometric: Boolean) {
logBuffer.log(TAG, DEBUG, {
int1 = userId
bool1 = isStrongBiometric
- }, {"Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1"})
+ }, {"Face detected: userId: $int1, isStrongBiometric: $bool1"})
}
- fun logFingerprintError(msgId: Int, originalErrMsg: String) {
+ fun logFingerprintDetected(userId: Int, isStrongBiometric: Boolean) {
logBuffer.log(TAG, DEBUG, {
- str1 = originalErrMsg
- int1 = msgId
- }, { "Fingerprint error received: $str1 msgId= $int1" })
+ int1 = userId
+ bool1 = isStrongBiometric
+ }, {"Fingerprint detected: userId: $int1, isStrongBiometric: $bool1"})
+ }
+
+ fun logFingerprintError(msgId: Int, originalErrMsg: String) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = originalErrMsg
+ int1 = msgId
+ },
+ { "Fingerprint error received: $str1 msgId= $int1" }
+ )
}
fun logInvalidSubId(subId: Int) {
- logBuffer.log(TAG, INFO,
- { int1 = subId },
- { "Previously active sub id $int1 is now invalid, will remove" })
+ logBuffer.log(
+ TAG,
+ INFO,
+ { int1 = subId },
+ { "Previously active sub id $int1 is now invalid, will remove" }
+ )
}
fun logPrimaryKeyguardBouncerChanged(
- primaryBouncerIsOrWillBeShowing: Boolean,
- primaryBouncerFullyShown: Boolean
+ primaryBouncerIsOrWillBeShowing: Boolean,
+ primaryBouncerFullyShown: Boolean
) {
- logBuffer.log(TAG, DEBUG, {
- bool1 = primaryBouncerIsOrWillBeShowing
- bool2 = primaryBouncerFullyShown
- }, {
- "handlePrimaryBouncerChanged " +
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = primaryBouncerIsOrWillBeShowing
+ bool2 = primaryBouncerFullyShown
+ },
+ {
+ "handlePrimaryBouncerChanged " +
"primaryBouncerIsOrWillBeShowing=$bool1 primaryBouncerFullyShown=$bool2"
- })
+ }
+ )
}
fun logKeyguardListenerModel(model: KeyguardListenModel) {
@@ -198,98 +254,134 @@ class KeyguardUpdateMonitorLogger @Inject constructor(
}
fun logKeyguardShowingChanged(showing: Boolean, occluded: Boolean, visible: Boolean) {
- logBuffer.log(TAG, DEBUG, {
- bool1 = showing
- bool2 = occluded
- bool3 = visible
- }, {
- "keyguardShowingChanged(showing=$bool1 occluded=$bool2 visible=$bool3)"
- })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = showing
+ bool2 = occluded
+ bool3 = visible
+ },
+ { "keyguardShowingChanged(showing=$bool1 occluded=$bool2 visible=$bool3)" }
+ )
}
fun logMissingSupervisorAppError(userId: Int) {
- logBuffer.log(TAG, ERROR,
- { int1 = userId },
- { "No Profile Owner or Device Owner supervision app found for User $int1" })
+ logBuffer.log(
+ TAG,
+ ERROR,
+ { int1 = userId },
+ { "No Profile Owner or Device Owner supervision app found for User $int1" }
+ )
}
fun logPhoneStateChanged(newState: String?) {
- logBuffer.log(TAG, DEBUG,
- { str1 = newState },
- { "handlePhoneStateChanged($str1)" })
+ logBuffer.log(TAG, DEBUG, { str1 = newState }, { "handlePhoneStateChanged($str1)" })
}
fun logRegisterCallback(callback: KeyguardUpdateMonitorCallback?) {
- logBuffer.log(TAG, VERBOSE,
- { str1 = "$callback" },
- { "*** register callback for $str1" })
+ logBuffer.log(TAG, VERBOSE, { str1 = "$callback" }, { "*** register callback for $str1" })
}
fun logRetryingAfterFaceHwUnavailable(retryCount: Int) {
- logBuffer.log(TAG, WARNING,
- { int1 = retryCount },
- { "Retrying face after HW unavailable, attempt $int1" })
+ logBuffer.log(
+ TAG,
+ WARNING,
+ { int1 = retryCount },
+ { "Retrying face after HW unavailable, attempt $int1" }
+ )
}
fun logRetryAfterFpErrorWithDelay(msgId: Int, errString: String?, delay: Int) {
- logBuffer.log(TAG, DEBUG, {
- int1 = msgId
- int2 = delay
- str1 = "$errString"
- }, {
- "Fingerprint scheduling retry auth after $int2 ms due to($int1) -> $str1"
- })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = msgId
+ int2 = delay
+ str1 = "$errString"
+ },
+ { "Fingerprint scheduling retry auth after $int2 ms due to($int1) -> $str1" }
+ )
}
fun logRetryAfterFpHwUnavailable(retryCount: Int) {
- logBuffer.log(TAG, WARNING,
- { int1 = retryCount },
- { "Retrying fingerprint attempt: $int1" })
+ logBuffer.log(
+ TAG,
+ WARNING,
+ { int1 = retryCount },
+ { "Retrying fingerprint attempt: $int1" }
+ )
}
fun logSendPrimaryBouncerChanged(
primaryBouncerIsOrWillBeShowing: Boolean,
primaryBouncerFullyShown: Boolean,
) {
- logBuffer.log(TAG, DEBUG, {
- bool1 = primaryBouncerIsOrWillBeShowing
- bool2 = primaryBouncerFullyShown
- }, {
- "sendPrimaryBouncerChanged primaryBouncerIsOrWillBeShowing=$bool1 " +
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = primaryBouncerIsOrWillBeShowing
+ bool2 = primaryBouncerFullyShown
+ },
+ {
+ "sendPrimaryBouncerChanged primaryBouncerIsOrWillBeShowing=$bool1 " +
"primaryBouncerFullyShown=$bool2"
- })
+ }
+ )
}
fun logServiceStateChange(subId: Int, serviceState: ServiceState?) {
- logBuffer.log(TAG, DEBUG, {
- int1 = subId
- str1 = "$serviceState"
- }, { "handleServiceStateChange(subId=$int1, serviceState=$str1)" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = subId
+ str1 = "$serviceState"
+ },
+ { "handleServiceStateChange(subId=$int1, serviceState=$str1)" }
+ )
}
fun logServiceStateIntent(action: String?, serviceState: ServiceState?, subId: Int) {
- logBuffer.log(TAG, VERBOSE, {
- str1 = action
- str2 = "$serviceState"
- int1 = subId
- }, { "action $str1 serviceState=$str2 subId=$int1" })
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ {
+ str1 = action
+ str2 = "$serviceState"
+ int1 = subId
+ },
+ { "action $str1 serviceState=$str2 subId=$int1" }
+ )
}
fun logSimState(subId: Int, slotId: Int, state: Int) {
- logBuffer.log(TAG, DEBUG, {
- int1 = subId
- int2 = slotId
- long1 = state.toLong()
- }, { "handleSimStateChange(subId=$int1, slotId=$int2, state=$long1)" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = subId
+ int2 = slotId
+ long1 = state.toLong()
+ },
+ { "handleSimStateChange(subId=$int1, slotId=$int2, state=$long1)" }
+ )
}
fun logSimStateFromIntent(action: String?, extraSimState: String?, slotId: Int, subId: Int) {
- logBuffer.log(TAG, VERBOSE, {
- str1 = action
- str2 = extraSimState
- int1 = slotId
- int2 = subId
- }, { "action $str1 state: $str2 slotId: $int1 subid: $int2" })
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ {
+ str1 = action
+ str2 = extraSimState
+ int1 = slotId
+ int2 = subId
+ },
+ { "action $str1 state: $str2 slotId: $int1 subid: $int2" }
+ )
}
fun logSimUnlocked(subId: Int) {
@@ -297,78 +389,98 @@ class KeyguardUpdateMonitorLogger @Inject constructor(
}
fun logStartedListeningForFace(faceRunningState: Int, faceAuthUiEvent: FaceAuthUiEvent) {
- logBuffer.log(TAG, VERBOSE, {
- int1 = faceRunningState
- str1 = faceAuthUiEvent.reason
- str2 = faceAuthUiEvent.extraInfoToString()
- }, { "startListeningForFace(): $int1, reason: $str1 $str2" })
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ {
+ int1 = faceRunningState
+ str1 = faceAuthUiEvent.reason
+ str2 = faceAuthUiEvent.extraInfoToString()
+ },
+ { "startListeningForFace(): $int1, reason: $str1 $str2" }
+ )
}
fun logStartedListeningForFaceFromWakeUp(faceRunningState: Int, @WakeReason pmWakeReason: Int) {
- logBuffer.log(TAG, VERBOSE, {
- int1 = faceRunningState
- str1 = PowerManager.wakeReasonToString(pmWakeReason)
- }, { "startListeningForFace(): $int1, reason: wakeUp-$str1" })
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ {
+ int1 = faceRunningState
+ str1 = PowerManager.wakeReasonToString(pmWakeReason)
+ },
+ { "startListeningForFace(): $int1, reason: wakeUp-$str1" }
+ )
}
fun logStoppedListeningForFace(faceRunningState: Int, faceAuthReason: String) {
- logBuffer.log(TAG, VERBOSE, {
- int1 = faceRunningState
- str1 = faceAuthReason
- }, { "stopListeningForFace(): currentFaceRunningState: $int1, reason: $str1" })
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ {
+ int1 = faceRunningState
+ str1 = faceAuthReason
+ },
+ { "stopListeningForFace(): currentFaceRunningState: $int1, reason: $str1" }
+ )
}
fun logSubInfo(subInfo: SubscriptionInfo?) {
- logBuffer.log(TAG, VERBOSE,
- { str1 = "$subInfo" },
- { "SubInfo:$str1" })
+ logBuffer.log(TAG, VERBOSE, { str1 = "$subInfo" }, { "SubInfo:$str1" })
}
fun logTimeFormatChanged(newTimeFormat: String?) {
- logBuffer.log(TAG, DEBUG,
- { str1 = newTimeFormat },
- { "handleTimeFormatUpdate timeFormat=$str1" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { str1 = newTimeFormat },
+ { "handleTimeFormatUpdate timeFormat=$str1" }
+ )
}
fun logUdfpsPointerDown(sensorId: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = sensorId },
- { "onUdfpsPointerDown, sensorId: $int1" })
+ logBuffer.log(TAG, DEBUG, { int1 = sensorId }, { "onUdfpsPointerDown, sensorId: $int1" })
}
fun logUdfpsPointerUp(sensorId: Int) {
- logBuffer.log(TAG, DEBUG,
- { int1 = sensorId },
- { "onUdfpsPointerUp, sensorId: $int1" })
+ logBuffer.log(TAG, DEBUG, { int1 = sensorId }, { "onUdfpsPointerUp, sensorId: $int1" })
}
fun logUnexpectedFaceCancellationSignalState(faceRunningState: Int, unlockPossible: Boolean) {
- logBuffer.log(TAG, ERROR, {
- int1 = faceRunningState
- bool1 = unlockPossible
- }, {
- "Cancellation signal is not null, high chance of bug in " +
- "face auth lifecycle management. " +
- "Face state: $int1, unlockPossible: $bool1"
- })
+ logBuffer.log(
+ TAG,
+ ERROR,
+ {
+ int1 = faceRunningState
+ bool1 = unlockPossible
+ },
+ {
+ "Cancellation signal is not null, high chance of bug in " +
+ "face auth lifecycle management. " +
+ "Face state: $int1, unlockPossible: $bool1"
+ }
+ )
}
fun logUnexpectedFpCancellationSignalState(
fingerprintRunningState: Int,
unlockPossible: Boolean
) {
- logBuffer.log(TAG, ERROR, {
- int1 = fingerprintRunningState
- bool1 = unlockPossible
- }, {
- "Cancellation signal is not null, high chance of bug in " +
- "fp auth lifecycle management. FP state: $int1, unlockPossible: $bool1"
- })
+ logBuffer.log(
+ TAG,
+ ERROR,
+ {
+ int1 = fingerprintRunningState
+ bool1 = unlockPossible
+ },
+ {
+ "Cancellation signal is not null, high chance of bug in " +
+ "fp auth lifecycle management. FP state: $int1, unlockPossible: $bool1"
+ }
+ )
}
fun logUnregisterCallback(callback: KeyguardUpdateMonitorCallback?) {
- logBuffer.log(TAG, VERBOSE,
- { str1 = "$callback" },
- { "*** unregister callback for $str1" })
+ logBuffer.log(TAG, VERBOSE, { str1 = "$callback" }, { "*** unregister callback for $str1" })
}
fun logUserRequestedUnlock(
@@ -376,75 +488,173 @@ class KeyguardUpdateMonitorLogger @Inject constructor(
reason: String?,
dismissKeyguard: Boolean
) {
- logBuffer.log("ActiveUnlock", DEBUG, {
- str1 = requestOrigin?.name
- str2 = reason
- bool1 = dismissKeyguard
- }, { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" })
+ logBuffer.log(
+ "ActiveUnlock",
+ DEBUG,
+ {
+ str1 = requestOrigin?.name
+ str2 = reason
+ bool1 = dismissKeyguard
+ },
+ { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" }
+ )
}
fun logTrustGrantedWithFlags(
- flags: Int,
- newlyUnlocked: Boolean,
- userId: Int,
- message: String?
+ flags: Int,
+ newlyUnlocked: Boolean,
+ userId: Int,
+ message: String?
) {
- logBuffer.log(TAG, DEBUG, {
- int1 = flags
- bool1 = newlyUnlocked
- int2 = userId
- str1 = message
- }, { "trustGrantedWithFlags[user=$int2] newlyUnlocked=$bool1 " +
- "flags=${TrustGrantFlags(int1)} message=$str1" })
- }
-
- fun logTrustChanged(
- wasTrusted: Boolean,
- isNowTrusted: Boolean,
- userId: Int
- ) {
- logBuffer.log(TAG, DEBUG, {
- bool1 = wasTrusted
- bool2 = isNowTrusted
- int1 = userId
- }, { "onTrustChanged[user=$int1] wasTrusted=$bool1 isNowTrusted=$bool2" })
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = flags
+ bool1 = newlyUnlocked
+ int2 = userId
+ str1 = message
+ },
+ {
+ "trustGrantedWithFlags[user=$int2] newlyUnlocked=$bool1 " +
+ "flags=${TrustGrantFlags(int1)} message=$str1"
+ }
+ )
+ }
+
+ fun logTrustChanged(wasTrusted: Boolean, isNowTrusted: Boolean, userId: Int) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = wasTrusted
+ bool2 = isNowTrusted
+ int1 = userId
+ },
+ { "onTrustChanged[user=$int1] wasTrusted=$bool1 isNowTrusted=$bool2" }
+ )
}
fun logKeyguardStateUpdate(
- secure: Boolean,
- canDismissLockScreen: Boolean,
- trusted: Boolean,
- trustManaged: Boolean
-
+ secure: Boolean,
+ canDismissLockScreen: Boolean,
+ trusted: Boolean,
+ trustManaged: Boolean
) {
- logBuffer.log("KeyguardState", DEBUG, {
- bool1 = secure
- bool2 = canDismissLockScreen
- bool3 = trusted
- bool4 = trustManaged
- }, { "#update secure=$bool1 canDismissKeyguard=$bool2" +
- " trusted=$bool3 trustManaged=$bool4" })
+ logBuffer.log(
+ "KeyguardState",
+ DEBUG,
+ {
+ bool1 = secure
+ bool2 = canDismissLockScreen
+ bool3 = trusted
+ bool4 = trustManaged
+ },
+ {
+ "#update secure=$bool1 canDismissKeyguard=$bool2" +
+ " trusted=$bool3 trustManaged=$bool4"
+ }
+ )
}
fun logSkipUpdateFaceListeningOnWakeup(@WakeReason pmWakeReason: Int) {
- logBuffer.log(TAG, VERBOSE, {
- str1 = PowerManager.wakeReasonToString(pmWakeReason)
- }, { "Skip updating face listening state on wakeup from $str1"})
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ { str1 = PowerManager.wakeReasonToString(pmWakeReason) },
+ { "Skip updating face listening state on wakeup from $str1" }
+ )
}
fun logTaskStackChangedForAssistant(assistantVisible: Boolean) {
- logBuffer.log(TAG, VERBOSE, {
- bool1 = assistantVisible
- }, {
- "TaskStackChanged for ACTIVITY_TYPE_ASSISTANT, assistant visible: $bool1"
- })
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ { bool1 = assistantVisible },
+ { "TaskStackChanged for ACTIVITY_TYPE_ASSISTANT, assistant visible: $bool1" }
+ )
}
fun logAssistantVisible(assistantVisible: Boolean) {
- logBuffer.log(TAG, VERBOSE, {
- bool1 = assistantVisible
- }, {
- "Updating mAssistantVisible to new value: $bool1"
- })
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ { bool1 = assistantVisible },
+ { "Updating mAssistantVisible to new value: $bool1" }
+ )
+ }
+
+ fun logReportSuccessfulBiometricUnlock(isStrongBiometric: Boolean, userId: Int) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = isStrongBiometric
+ int1 = userId
+ },
+ { "reporting successful biometric unlock: isStrongBiometric: $bool1, userId: $int1" }
+ )
+ }
+
+ fun logHandlerHasAuthContinueMsgs(action: Int) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { int1 = action },
+ {
+ "MSG_BIOMETRIC_AUTHENTICATION_CONTINUE already queued up, " +
+ "ignoring updating FP listening state to $int1"
+ }
+ )
+ }
+
+ fun logFaceEnrolledUpdated(oldValue: Boolean, newValue: Boolean) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = oldValue
+ bool2 = newValue
+ },
+ { "Face enrolled state changed: old: $bool1, new: $bool2" }
+ )
+ }
+
+ fun logFpEnrolledUpdated(userId: Int, oldValue: Boolean, newValue: Boolean) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = userId
+ bool1 = oldValue
+ bool2 = newValue
+ },
+ { "Fp enrolled state changed for userId: $int1 old: $bool1, new: $bool2" }
+ )
+ }
+
+ fun logTrustUsuallyManagedUpdated(
+ userId: Int,
+ oldValue: Boolean,
+ newValue: Boolean,
+ context: String
+ ) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = userId
+ bool1 = oldValue
+ bool2 = newValue
+ str1 = context
+ },
+ {
+ "trustUsuallyManaged changed for " +
+ "userId: $int1 " +
+ "old: $bool1, " +
+ "new: $bool2 " +
+ "context: $context"
+ }
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index ce4253477a41..0002ae95f476 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -38,7 +38,6 @@ import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
-import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -347,10 +346,9 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver {
}
if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
updatePercentText();
- addView(mBatteryPercentView,
- new ViewGroup.LayoutParams(
- LayoutParams.WRAP_CONTENT,
- LayoutParams.MATCH_PARENT));
+ addView(mBatteryPercentView, new LayoutParams(
+ LayoutParams.WRAP_CONTENT,
+ LayoutParams.MATCH_PARENT));
}
} else {
if (showing) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
index 709ddf5ce748..52312b8e8add 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
@@ -97,7 +97,6 @@ open class AuthBiometricFingerprintIconController(
val iconContentDescription = getIconContentDescription(newState)
if (iconContentDescription != null) {
iconView.contentDescription = iconContentDescription
- iconViewOverlay.contentDescription = iconContentDescription
}
iconView.frame = 0
@@ -152,7 +151,7 @@ open class AuthBiometricFingerprintIconController(
STATE_AUTHENTICATING_ANIMATING_IN,
STATE_AUTHENTICATING,
STATE_PENDING_CONFIRMATION,
- STATE_AUTHENTICATED -> R.string.accessibility_fingerprint_dialog_fingerprint_icon
+ STATE_AUTHENTICATED -> R.string.security_settings_sfps_enroll_find_sensor_message
STATE_ERROR,
STATE_HELP -> R.string.biometric_dialog_try_again
else -> null
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index d68fcd0a5922..8f6b5c956853 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -26,6 +26,7 @@ import android.hardware.biometrics.BiometricSourceType
import androidx.annotation.VisibleForTesting
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.keyguard.logging.KeyguardLogger
import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.animation.Interpolators
@@ -74,6 +75,7 @@ class AuthRippleController @Inject constructor(
private val udfpsControllerProvider: Provider<UdfpsController>,
private val statusBarStateController: StatusBarStateController,
private val featureFlags: FeatureFlags,
+ private val logger: KeyguardLogger,
rippleView: AuthRippleView?
) : ViewController<AuthRippleView>(rippleView), KeyguardStateController.Callback,
WakefulnessLifecycle.Observer {
@@ -120,8 +122,11 @@ class AuthRippleController @Inject constructor(
}
fun showUnlockRipple(biometricSourceType: BiometricSourceType) {
- if (!keyguardStateController.isShowing ||
- !keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(biometricSourceType)) {
+ val keyguardNotShowing = !keyguardStateController.isShowing
+ val unlockNotAllowed = !keyguardUpdateMonitor
+ .isUnlockingWithBiometricAllowed(biometricSourceType)
+ if (keyguardNotShowing || unlockNotAllowed) {
+ logger.notShowingUnlockRipple(keyguardNotShowing, unlockNotAllowed)
return
}
@@ -138,6 +143,7 @@ class AuthRippleController @Inject constructor(
Math.max(it.y, centralSurfaces.displayHeight.toInt() - it.y)
)
)
+ logger.showingUnlockRippleAt(it.x, it.y, "FP sensor radius: $udfpsRadius")
showUnlockedRipple()
}
} else if (biometricSourceType == BiometricSourceType.FACE) {
@@ -155,6 +161,7 @@ class AuthRippleController @Inject constructor(
Math.max(it.y, centralSurfaces.displayHeight.toInt() - it.y)
)
)
+ logger.showingUnlockRippleAt(it.x, it.y, "Face unlock ripple")
showUnlockedRipple()
}
}
@@ -391,5 +398,6 @@ class AuthRippleController @Inject constructor(
companion object {
const val RIPPLE_ANIMATION_DURATION: Long = 1533
+ const val TAG = "AuthRippleController"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt b/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt
index fabc1c1bb908..e16121d1104e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt
@@ -49,8 +49,8 @@ constructor(
/**
* @property messagesToDefer messages that shouldn't show immediately when received, but may be
- * shown later if the message is the most frequent acquiredInfo processed and meets [threshold]
- * percentage of all passed acquired frames.
+ * shown later if the message is the most frequent acquiredInfo processed and meets [threshold]
+ * percentage of all passed acquired frames.
*/
open class BiometricMessageDeferral(
private val messagesToDefer: Set<Int>,
@@ -127,8 +127,9 @@ open class BiometricMessageDeferral(
/**
* Get the most frequent deferred message that meets the [threshold] percentage of processed
* frames.
+ *
* @return null if no acquiredInfo have been deferred OR deferred messages didn't meet the
- * [threshold] percentage.
+ * [threshold] percentage.
*/
fun getDeferredMessage(): CharSequence? {
mostFrequentAcquiredInfoToDefer?.let {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index ac6a22c1474b..f7d87fc69e55 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -492,7 +492,9 @@ class OrientationReasonListener(
displayManager,
handler,
BiometricDisplayListener.SensorType.SideFingerprint(sensorProps)
- ) { onOrientationChanged(reason) }
+ ) {
+ onOrientationChanged(reason)
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
index addbee954fea..71cb35f3041c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
@@ -347,6 +347,7 @@ constructor(
/**
* Overrides non-bouncer show logic in shouldPauseAuth to still show icon.
+ *
* @return whether the udfpsBouncer has been newly shown or hidden
*/
private fun showUdfpsBouncer(show: Boolean): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
index 98a3e4b55256..f6217f16d054 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
@@ -129,8 +129,7 @@ final class WirelessChargingLayout extends FrameLayout {
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(textSizeAnimator, textOpacityAnimator, textFadeAnimator);
- // For tablet docking animation, we don't play the background scrim.
- // TODO(b/270524780): use utility to check for tablet instead.
+ // For large screens docking animation, we don't play the background scrim.
if (!Utilities.isLargeScreen(context)) {
ValueAnimator scrimFadeInAnimator = ObjectAnimator.ofArgb(this,
"backgroundColor", Color.TRANSPARENT, SCRIM_COLOR);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index bc0f9950f865..f83885b7bb32 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -38,6 +38,7 @@ import javax.inject.Inject;
public class FalsingDataProvider {
private static final long MOTION_EVENT_AGE_MS = 1000;
+ private static final long DROP_EVENT_THRESHOLD_MS = 50;
private static final float THREE_HUNDRED_SIXTY_DEG = (float) (2 * Math.PI);
private final int mWidthPixels;
@@ -60,6 +61,7 @@ public class FalsingDataProvider {
private float mAngle = 0;
private MotionEvent mFirstRecentMotionEvent;
private MotionEvent mLastMotionEvent;
+ private boolean mDropLastEvent;
private boolean mJustUnlockedWithFace;
private boolean mA11YAction;
@@ -95,6 +97,12 @@ public class FalsingDataProvider {
// Ensure prior gesture was completed. May be a no-op.
completePriorGesture();
}
+
+ // Drop the gesture closing event if it is close in time to a previous ACTION_MOVE event.
+ // The reason is that the closing ACTION_UP event of a swipe can be a bit offseted from the
+ // previous ACTION_MOVE event and when it happens, it makes some classifiers fail.
+ mDropLastEvent = shouldDropEvent(motionEvent);
+
mRecentMotionEvents.addAll(motionEvents);
FalsingClassifier.logVerbose("Size: " + mRecentMotionEvents.size());
@@ -129,6 +137,7 @@ public class FalsingDataProvider {
mPriorMotionEvents = mRecentMotionEvents;
mRecentMotionEvents = new TimeLimitedMotionEventBuffer(MOTION_EVENT_AGE_MS);
}
+ mDropLastEvent = false;
mA11YAction = false;
}
@@ -150,8 +159,18 @@ public class FalsingDataProvider {
return mYdpi;
}
+ /**
+ * Get the {@link MotionEvent}s of the most recent gesture.
+ *
+ * Note that this list may not include the last recorded event.
+ * @see #mDropLastEvent
+ */
public List<MotionEvent> getRecentMotionEvents() {
- return mRecentMotionEvents;
+ if (!mDropLastEvent || mRecentMotionEvents.isEmpty()) {
+ return mRecentMotionEvents;
+ } else {
+ return mRecentMotionEvents.subList(0, mRecentMotionEvents.size() - 1);
+ }
}
public List<MotionEvent> getPriorMotionEvents() {
@@ -169,7 +188,12 @@ public class FalsingDataProvider {
return mFirstRecentMotionEvent;
}
- /** Get the last recorded {@link MotionEvent}. */
+ /**
+ * Get the last {@link MotionEvent} of the most recent gesture.
+ *
+ * Note that this may be the event prior to the last recorded event.
+ * @see #mDropLastEvent
+ */
public MotionEvent getLastMotionEvent() {
recalculateData();
return mLastMotionEvent;
@@ -236,12 +260,13 @@ public class FalsingDataProvider {
return;
}
- if (mRecentMotionEvents.isEmpty()) {
+ List<MotionEvent> recentMotionEvents = getRecentMotionEvents();
+ if (recentMotionEvents.isEmpty()) {
mFirstRecentMotionEvent = null;
mLastMotionEvent = null;
} else {
- mFirstRecentMotionEvent = mRecentMotionEvents.get(0);
- mLastMotionEvent = mRecentMotionEvents.get(mRecentMotionEvents.size() - 1);
+ mFirstRecentMotionEvent = recentMotionEvents.get(0);
+ mLastMotionEvent = recentMotionEvents.get(recentMotionEvents.size() - 1);
}
calculateAngleInternal();
@@ -249,6 +274,17 @@ public class FalsingDataProvider {
mDirty = false;
}
+ private boolean shouldDropEvent(MotionEvent event) {
+ if (mRecentMotionEvents.size() < 3) return false;
+
+ MotionEvent lastEvent = mRecentMotionEvents.get(mRecentMotionEvents.size() - 1);
+ boolean isCompletingGesture = event.getActionMasked() == MotionEvent.ACTION_UP
+ && lastEvent.getActionMasked() == MotionEvent.ACTION_MOVE;
+ boolean isRecentEvent =
+ event.getEventTime() - lastEvent.getEventTime() < DROP_EVENT_THRESHOLD_MS;
+ return isCompletingGesture && isRecentEvent;
+ }
+
private void calculateAngleInternal() {
if (mRecentMotionEvents.size() < 2) {
mAngle = Float.MAX_VALUE;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java
index e5da38936593..addd8e26490a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java
@@ -183,7 +183,7 @@ public class TimeLimitedMotionEventBuffer implements List<MotionEvent> {
@Override
public List<MotionEvent> subList(int fromIndex, int toIndex) {
- throw new UnsupportedOperationException();
+ return mMotionEvents.subList(fromIndex, toIndex);
}
class Iter implements ListIterator<MotionEvent> {
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index c214f5341450..e049ae09b1de 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -263,10 +263,11 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
@Override // ClipboardListener.ClipboardOverlay
public void setClipData(ClipData data, String source) {
ClipboardModel model = ClipboardModel.fromClipData(mContext, mClipboardUtils, data, source);
- if (mExitAnimator != null && mExitAnimator.isRunning()) {
+ boolean wasExiting = (mExitAnimator != null && mExitAnimator.isRunning());
+ if (wasExiting) {
mExitAnimator.cancel();
}
- boolean shouldAnimate = !model.dataMatches(mClipboardModel);
+ boolean shouldAnimate = !model.dataMatches(mClipboardModel) || wasExiting;
mClipboardModel = model;
mClipboardLogger.setClipSource(mClipboardModel.getSource());
if (shouldAnimate) {
@@ -313,15 +314,19 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
mOnPreviewTapped = this::editText;
break;
case IMAGE:
- if (model.isSensitive() || model.loadThumbnail(mContext) != null) {
- mView.showImagePreview(
- model.isSensitive() ? null : model.loadThumbnail(mContext));
- mView.setEditAccessibilityAction(true);
- mOnPreviewTapped = () -> editImage(model.getUri());
- } else {
- // image loading failed
- mView.showDefaultTextPreview();
- }
+ mBgExecutor.execute(() -> {
+ if (model.isSensitive() || model.loadThumbnail(mContext) != null) {
+ mView.post(() -> {
+ mView.showImagePreview(
+ model.isSensitive() ? null : model.loadThumbnail(mContext));
+ mView.setEditAccessibilityAction(true);
+ });
+ mOnPreviewTapped = () -> editImage(model.getUri());
+ } else {
+ // image loading failed
+ mView.post(mView::showDefaultTextPreview);
+ }
+ });
break;
case URI:
case OTHER:
@@ -346,9 +351,20 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
}
private void animateFromMinimized() {
- mIsMinimized = false;
- setExpandedView();
- animateIn();
+ if (mEnterAnimator != null && mEnterAnimator.isRunning()) {
+ mEnterAnimator.cancel();
+ }
+ mEnterAnimator = mView.getMinimizedFadeoutAnimation();
+ mEnterAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mIsMinimized = false;
+ setExpandedView();
+ animateIn();
+ }
+ });
+ mEnterAnimator.start();
}
private String getAccessibilityAnnouncement(ClipboardModel.Type type) {
@@ -363,15 +379,15 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
private void classifyText(ClipboardModel model) {
mBgExecutor.execute(() -> {
- Optional<RemoteAction> remoteAction = mClipboardUtils.getAction(
- model.getText(), model.getTextLinks(), model.getSource());
+ Optional<RemoteAction> remoteAction =
+ mClipboardUtils.getAction(model.getTextLinks(), model.getSource());
if (model.equals(mClipboardModel)) {
remoteAction.ifPresent(action -> {
mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_ACTION_SHOWN);
- mView.setActionChip(action, () -> {
+ mView.post(() -> mView.setActionChip(action, () -> {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED);
animateOut();
- });
+ }));
});
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java
index a85f8b9357f5..25caaeac2c38 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java
@@ -39,6 +39,9 @@ import javax.inject.Inject;
class ClipboardOverlayUtils {
+ // minimum proportion of entire text an entity must take up, to be considered for smart actions
+ private static final float MINIMUM_ENTITY_PROPORTION = .8f;
+
private final TextClassifier mTextClassifier;
@Inject
@@ -65,19 +68,23 @@ class ClipboardOverlayUtils {
return false;
}
- public Optional<RemoteAction> getAction(CharSequence text, TextLinks textLinks, String source) {
- return getActions(text, textLinks).stream().filter(remoteAction -> {
+ public Optional<RemoteAction> getAction(TextLinks textLinks, String source) {
+ return getActions(textLinks).stream().filter(remoteAction -> {
ComponentName component = remoteAction.getActionIntent().getIntent().getComponent();
return component != null && !TextUtils.equals(source, component.getPackageName());
}).findFirst();
}
- private ArrayList<RemoteAction> getActions(CharSequence text, TextLinks textLinks) {
+ private ArrayList<RemoteAction> getActions(TextLinks textLinks) {
ArrayList<RemoteAction> actions = new ArrayList<>();
for (TextLinks.TextLink link : textLinks.getLinks()) {
- TextClassification classification = mTextClassifier.classifyText(
- text, link.getStart(), link.getEnd(), null);
- actions.addAll(classification.getActions());
+ // skip classification for incidental entities
+ if (link.getEnd() - link.getStart()
+ >= textLinks.getText().length() * MINIMUM_ENTITY_PROPORTION) {
+ TextClassification classification = mTextClassifier.classifyText(
+ textLinks.getText(), link.getStart(), link.getEnd(), null);
+ actions.addAll(classification.getActions());
+ }
}
return actions;
}
@@ -92,9 +99,13 @@ class ClipboardOverlayUtils {
private ArrayList<RemoteAction> getActions(ClipData.Item item) {
ArrayList<RemoteAction> actions = new ArrayList<>();
for (TextLinks.TextLink link : item.getTextLinks().getLinks()) {
- TextClassification classification = mTextClassifier.classifyText(
- item.getText(), link.getStart(), link.getEnd(), null);
- actions.addAll(classification.getActions());
+ // skip classification for incidental entities
+ if (link.getEnd() - link.getStart()
+ >= item.getText().length() * MINIMUM_ENTITY_PROPORTION) {
+ TextClassification classification = mTextClassifier.classifyText(
+ item.getText(), link.getStart(), link.getEnd(), null);
+ actions.addAll(classification.getActions());
+ }
}
return actions;
}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
index f372bb4bc7f2..28c57d31a4f3 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
@@ -21,6 +21,7 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
@@ -286,6 +287,20 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
mActionChips.clear();
}
+ Animator getMinimizedFadeoutAnimation() {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(mMinimizedPreview, "alpha", 1, 0);
+ anim.setDuration(66);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mMinimizedPreview.setVisibility(View.GONE);
+ mMinimizedPreview.setAlpha(1);
+ }
+ });
+ return anim;
+ }
+
Animator getEnterAnimation() {
if (mAccessibilityManager.isEnabled()) {
mDismissButton.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/common/coroutine/ChannelExt.kt b/packages/SystemUI/src/com/android/systemui/common/coroutine/ChannelExt.kt
index a0b19dc5c96e..c0e1717ea014 100644
--- a/packages/SystemUI/src/com/android/systemui/common/coroutine/ChannelExt.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/coroutine/ChannelExt.kt
@@ -26,7 +26,6 @@ object ChannelExt {
/**
* Convenience wrapper around [SendChannel.trySend] that also logs on failure. This is the
* equivalent of calling:
- *
* ```
* sendChannel.trySend(element).onFailure {
* Log.e(
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt
index b3c18fb3cd98..3744344421a9 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt
@@ -86,6 +86,7 @@ internal constructor(wrapper: ControlsFavoritePersistenceWrapper) {
*
* When the favorites for that application are returned, they will be removed from the auxiliary
* file immediately, so they won't be retrieved again.
+ *
* @param componentName the name of the service that provided the controls
* @return a list of structures with favorites
*/
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
index 822190f21da1..2d37c292a6b8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
@@ -166,6 +166,13 @@ interface ControlsController : UserAwareController {
)
/**
+ * Removes favorites for a given component
+ * @param componentName the name of the service that provides the [Control]
+ * @return true when favorites is scheduled for deletion
+ */
+ fun removeFavorites(componentName: ComponentName): Boolean
+
+ /**
* Replaces the favorites for the given structure.
*
* Calling this method will eliminate the previous selection of favorites and replace it with a
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index 278ee7079720..e8c97bf77271 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -37,6 +37,7 @@ import com.android.systemui.controls.ControlStatus
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
+import com.android.systemui.controls.panels.SelectedComponentRepository
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.controls.ui.SelectedItem
import com.android.systemui.dagger.SysUISingleton
@@ -55,16 +56,17 @@ import javax.inject.Inject
@SysUISingleton
class ControlsControllerImpl @Inject constructor (
- private val context: Context,
- @Background private val executor: DelayableExecutor,
- private val uiController: ControlsUiController,
- private val bindingController: ControlsBindingController,
- private val listingController: ControlsListingController,
- private val userFileManager: UserFileManager,
- private val userTracker: UserTracker,
- private val authorizedPanelsRepository: AuthorizedPanelsRepository,
- optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>,
- dumpManager: DumpManager,
+ private val context: Context,
+ @Background private val executor: DelayableExecutor,
+ private val uiController: ControlsUiController,
+ private val selectedComponentRepository: SelectedComponentRepository,
+ private val bindingController: ControlsBindingController,
+ private val listingController: ControlsListingController,
+ private val userFileManager: UserFileManager,
+ private val userTracker: UserTracker,
+ private val authorizedPanelsRepository: AuthorizedPanelsRepository,
+ optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>,
+ dumpManager: DumpManager,
) : Dumpable, ControlsController {
companion object {
@@ -497,6 +499,18 @@ class ControlsControllerImpl @Inject constructor (
}
}
+ override fun removeFavorites(componentName: ComponentName): Boolean {
+ if (!confirmAvailability()) return false
+
+ executor.execute {
+ if (Favorites.removeStructures(componentName)) {
+ persistenceWrapper.storeFavorites(Favorites.getAllStructures())
+ }
+ authorizedPanelsRepository.removeAuthorizedPanels(setOf(componentName.packageName))
+ }
+ return true
+ }
+
override fun replaceFavoritesForStructure(structureInfo: StructureInfo) {
if (!confirmAvailability()) return
executor.execute {
@@ -559,7 +573,9 @@ class ControlsControllerImpl @Inject constructor (
}
override fun setPreferredSelection(selectedItem: SelectedItem) {
- uiController.updatePreferences(selectedItem)
+ selectedComponentRepository.setSelectedComponent(
+ SelectedComponentRepository.SelectedComponent(selectedItem)
+ )
}
override fun dump(pw: PrintWriter, args: Array<out String>) {
@@ -655,10 +671,11 @@ private object Favorites {
return true
}
- fun removeStructures(componentName: ComponentName) {
+ fun removeStructures(componentName: ComponentName): Boolean {
val newFavMap = favMap.toMutableMap()
- newFavMap.remove(componentName)
+ val removed = newFavMap.remove(componentName) != null
favMap = newFavMap
+ return removed
}
fun addFavorite(
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
index 72c3a943c30b..217f4d89e24c 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
@@ -84,7 +84,7 @@ class ControlsProviderLifecycleManager(
private val BIND_FLAGS_PANEL = Context.BIND_AUTO_CREATE or Context.BIND_NOT_PERCEPTIBLE
}
- private val intent = Intent().apply {
+ private val intent = Intent(ControlsProviderService.SERVICE_CONTROLS).apply {
component = componentName
putExtra(CALLBACK_BUNDLE, Bundle().apply {
putBinder(CALLBACK_TOKEN, token)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
index d949d1119222..2af49aa5fa1a 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
@@ -36,6 +36,8 @@ import com.android.systemui.controls.management.ControlsProviderSelectorActivity
import com.android.systemui.controls.management.ControlsRequestDialog
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
import com.android.systemui.controls.panels.AuthorizedPanelsRepositoryImpl
+import com.android.systemui.controls.panels.SelectedComponentRepository
+import com.android.systemui.controls.panels.SelectedComponentRepositoryImpl
import com.android.systemui.controls.settings.ControlsSettingsDialogManager
import com.android.systemui.controls.settings.ControlsSettingsDialogManagerImpl
import com.android.systemui.controls.ui.ControlActionCoordinator
@@ -114,6 +116,11 @@ abstract class ControlsModule {
repository: AuthorizedPanelsRepositoryImpl
): AuthorizedPanelsRepository
+ @Binds
+ abstract fun providePreferredPanelRepository(
+ repository: SelectedComponentRepositoryImpl
+ ): SelectedComponentRepository
+
@BindsOptionalOf
abstract fun optionalPersistenceWrapper(): ControlsFavoritePersistenceWrapper
diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepository.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepository.kt
index 3e672f391e81..ae9c37aa0e7b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepository.kt
@@ -26,6 +26,14 @@ interface AuthorizedPanelsRepository {
/** A set of package names that the user has previously authorized to show panels. */
fun getAuthorizedPanels(): Set<String>
+ /** Preferred applications to query controls suggestions from */
+ fun getPreferredPackages(): Set<String>
+
/** Adds [packageNames] to the set of packages that the user has authorized to show panels. */
fun addAuthorizedPanels(packageNames: Set<String>)
+
+ /**
+ * Removes [packageNames] from the set of packages that the user has authorized to show panels.
+ */
+ fun removeAuthorizedPanels(packageNames: Set<String>)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt
index f7e43a77b573..5c2402ba4149 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt
@@ -20,6 +20,8 @@ package com.android.systemui.controls.panels
import android.content.Context
import android.content.SharedPreferences
import com.android.systemui.R
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
@@ -30,17 +32,28 @@ class AuthorizedPanelsRepositoryImpl
constructor(
private val context: Context,
private val userFileManager: UserFileManager,
- private val userTracker: UserTracker
+ private val userTracker: UserTracker,
+ private val featureFlags: FeatureFlags,
) : AuthorizedPanelsRepository {
override fun getAuthorizedPanels(): Set<String> {
return getAuthorizedPanelsInternal(instantiateSharedPrefs())
}
+ override fun getPreferredPackages(): Set<String> =
+ context.resources.getStringArray(R.array.config_controlsPreferredPackages).toSet()
+
override fun addAuthorizedPanels(packageNames: Set<String>) {
addAuthorizedPanelsInternal(instantiateSharedPrefs(), packageNames)
}
+ override fun removeAuthorizedPanels(packageNames: Set<String>) {
+ with(instantiateSharedPrefs()) {
+ val currentSet = getAuthorizedPanelsInternal(this)
+ edit().putStringSet(KEY, currentSet - packageNames).apply()
+ }
+ }
+
private fun getAuthorizedPanelsInternal(sharedPreferences: SharedPreferences): Set<String> {
return sharedPreferences.getStringSet(KEY, emptySet())!!
}
@@ -61,17 +74,19 @@ constructor(
userTracker.userId,
)
- // If we've never run this (i.e., the key doesn't exist), add the default packages
- if (sharedPref.getStringSet(KEY, null) == null) {
- sharedPref
- .edit()
- .putStringSet(
- KEY,
- context.resources
- .getStringArray(R.array.config_controlsPreferredPackages)
- .toSet()
- )
- .apply()
+ // We should add default packages in two cases:
+ // 1) We've never run this
+ // 2) APP_PANELS_REMOVE_APPS_ALLOWED got disabled after user removed all apps
+ val needToSetup =
+ if (featureFlags.isEnabled(Flags.APP_PANELS_REMOVE_APPS_ALLOWED)) {
+ sharedPref.getStringSet(KEY, null) == null
+ } else {
+ // There might be an empty set that need to be overridden after the feature has been
+ // turned off after being turned on
+ sharedPref.getStringSet(KEY, null).isNullOrEmpty()
+ }
+ if (needToSetup) {
+ sharedPref.edit().putStringSet(KEY, getPreferredPackages()).apply()
}
return sharedPref
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepository.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepository.kt
new file mode 100644
index 000000000000..5bb6eece9098
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepository.kt
@@ -0,0 +1,64 @@
+/*
+ * 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.controls.panels
+
+import android.content.ComponentName
+import com.android.systemui.controls.ui.ControlsUiController
+import com.android.systemui.controls.ui.SelectedItem
+import com.android.systemui.flags.Flags
+
+/** Stores user-selected preferred component. */
+interface SelectedComponentRepository {
+
+ /**
+ * Returns currently set preferred component, or null when nothing is set. Consider using
+ * [ControlsUiController.getPreferredSelectedItem] to get domain specific data
+ */
+ fun getSelectedComponent(): SelectedComponent?
+
+ /** Sets preferred component. Use [getSelectedComponent] to get current one */
+ fun setSelectedComponent(selectedComponent: SelectedComponent)
+
+ /** Clears current preferred component. [getSelectedComponent] will return null afterwards */
+ fun removeSelectedComponent()
+
+ /**
+ * Return true when default preferred component should be set up and false the otherwise. This
+ * is always true when [Flags.APP_PANELS_REMOVE_APPS_ALLOWED] is disabled
+ */
+ fun shouldAddDefaultComponent(): Boolean
+
+ /**
+ * Sets if default component should be added. This is ignored when
+ * [Flags.APP_PANELS_REMOVE_APPS_ALLOWED] is disabled
+ */
+ fun setShouldAddDefaultComponent(shouldAdd: Boolean)
+
+ data class SelectedComponent(
+ val name: String,
+ val componentName: ComponentName?,
+ val isPanel: Boolean,
+ ) {
+ constructor(
+ selectedItem: SelectedItem
+ ) : this(
+ name = selectedItem.name.toString(),
+ componentName = selectedItem.componentName,
+ isPanel = selectedItem is SelectedItem.PanelItem,
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt
new file mode 100644
index 000000000000..0fb5b66ef93c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.controls.panels
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.SharedPreferences
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.settings.UserFileManager
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
+import javax.inject.Inject
+
+@SysUISingleton
+class SelectedComponentRepositoryImpl
+@Inject
+constructor(
+ private val userFileManager: UserFileManager,
+ private val userTracker: UserTracker,
+ private val featureFlags: FeatureFlags,
+) : SelectedComponentRepository {
+
+ private companion object {
+ const val PREF_COMPONENT = "controls_component"
+ const val PREF_STRUCTURE_OR_APP_NAME = "controls_structure"
+ const val PREF_IS_PANEL = "controls_is_panel"
+ const val SHOULD_ADD_DEFAULT_PANEL = "should_add_default_panel"
+ }
+
+ private val sharedPreferences: SharedPreferences
+ get() =
+ userFileManager.getSharedPreferences(
+ fileName = DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
+ mode = Context.MODE_PRIVATE,
+ userId = userTracker.userId
+ )
+
+ override fun getSelectedComponent(): SelectedComponentRepository.SelectedComponent? {
+ with(sharedPreferences) {
+ val componentString = getString(PREF_COMPONENT, null) ?: return null
+ return SelectedComponentRepository.SelectedComponent(
+ name = getString(PREF_STRUCTURE_OR_APP_NAME, "")!!,
+ componentName = ComponentName.unflattenFromString(componentString),
+ isPanel = getBoolean(PREF_IS_PANEL, false)
+ )
+ }
+ }
+
+ override fun setSelectedComponent(
+ selectedComponent: SelectedComponentRepository.SelectedComponent
+ ) {
+ sharedPreferences
+ .edit()
+ .putString(PREF_COMPONENT, selectedComponent.componentName?.flattenToString())
+ .putString(PREF_STRUCTURE_OR_APP_NAME, selectedComponent.name)
+ .putBoolean(PREF_IS_PANEL, selectedComponent.isPanel)
+ .apply()
+ }
+
+ override fun removeSelectedComponent() {
+ sharedPreferences
+ .edit()
+ .remove(PREF_COMPONENT)
+ .remove(PREF_STRUCTURE_OR_APP_NAME)
+ .remove(PREF_IS_PANEL)
+ .apply()
+ }
+
+ override fun shouldAddDefaultComponent(): Boolean =
+ if (featureFlags.isEnabled(Flags.APP_PANELS_REMOVE_APPS_ALLOWED)) {
+ sharedPreferences.getBoolean(SHOULD_ADD_DEFAULT_PANEL, true)
+ } else {
+ true
+ }
+
+ override fun setShouldAddDefaultComponent(shouldAdd: Boolean) {
+ sharedPreferences.edit().putBoolean(SHOULD_ADD_DEFAULT_PANEL, shouldAdd).apply()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt b/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt
index bb2e2d701aa0..06d4a0888197 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt
@@ -38,7 +38,6 @@ import javax.inject.Inject
/**
* Manager to display a dialog to prompt user to enable controls related Settings:
- *
* * [Settings.Secure.LOCKSCREEN_SHOW_CONTROLS]
* * [Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS]
*/
@@ -46,20 +45,19 @@ interface ControlsSettingsDialogManager {
/**
* Shows the corresponding dialog. In order for a dialog to appear, the following must be true
- *
* * At least one of the Settings in [ControlsSettingsRepository] are `false`.
* * The dialog has not been seen by the user too many times (as defined by
- * [MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG]).
+ * [MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG]).
*
* When the dialogs are shown, the following outcomes are possible:
* * User cancels the dialog by clicking outside or going back: we register that the dialog was
- * seen but the settings don't change.
+ * seen but the settings don't change.
* * User responds negatively to the dialog: we register that the user doesn't want to change
- * the settings (dialog will not appear again) and the settings don't change.
+ * the settings (dialog will not appear again) and the settings don't change.
* * User responds positively to the dialog: the settings are set to `true` and the dialog will
- * not appear again.
+ * not appear again.
* * SystemUI closes the dialogs (for example, the activity showing it is closed). In this case,
- * we don't modify anything.
+ * we don't modify anything.
*
* Of those four scenarios, only the first three will cause [onAttemptCompleted] to be called.
* It will also be called if the dialogs are not shown.
diff --git a/packages/SystemUI/src/com/android/systemui/controls/start/ControlsStartable.kt b/packages/SystemUI/src/com/android/systemui/controls/start/ControlsStartable.kt
index 9d99253de741..3a4a00c0ccd3 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/start/ControlsStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/start/ControlsStartable.kt
@@ -18,17 +18,16 @@
package com.android.systemui.controls.start
import android.content.Context
-import android.content.res.Resources
import android.os.UserHandle
import com.android.systemui.CoreStartable
-import com.android.systemui.R
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.dagger.ControlsComponent
import com.android.systemui.controls.management.ControlsListingController
+import com.android.systemui.controls.panels.AuthorizedPanelsRepository
+import com.android.systemui.controls.panels.SelectedComponentRepository
import com.android.systemui.controls.ui.SelectedItem
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.settings.UserTracker
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -37,7 +36,7 @@ import javax.inject.Inject
* Started with SystemUI to perform early operations for device controls subsystem (only if enabled)
*
* In particular, it will perform the following:
- * * If there is no preferred selection for provider and at least one of the preferred packages
+ * * If there is no preferred selection for provider and at least one of the preferred packages
* provides a panel, it will select the first one that does.
* * If the preferred selection provides a panel, it will bind to that service (to reduce latency on
* displaying the panel).
@@ -48,10 +47,11 @@ import javax.inject.Inject
class ControlsStartable
@Inject
constructor(
- @Main private val resources: Resources,
- @Background private val executor: Executor,
- private val controlsComponent: ControlsComponent,
- private val userTracker: UserTracker
+ @Background private val executor: Executor,
+ private val controlsComponent: ControlsComponent,
+ private val userTracker: UserTracker,
+ private val authorizedPanelsRepository: AuthorizedPanelsRepository,
+ private val selectedComponentRepository: SelectedComponentRepository,
) : CoreStartable {
// These two controllers can only be accessed after `start` method once we've checked if the
@@ -85,12 +85,15 @@ constructor(
}
private fun selectDefaultPanelIfNecessary() {
+ if (!selectedComponentRepository.shouldAddDefaultComponent()) {
+ return
+ }
val currentSelection = controlsController.getPreferredSelection()
if (currentSelection == SelectedItem.EMPTY_SELECTION) {
val availableServices = controlsListingController.getCurrentServices()
val panels = availableServices.filter { it.panelActivity != null }
- resources
- .getStringArray(R.array.config_controlsPreferredPackages)
+ authorizedPanelsRepository
+ .getPreferredPackages()
// Looking for the first element in the string array such that there is one package
// that has a panel. It will return null if there are no packages in the array,
// or if no packages in the array have a panel associated with it.
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
index 3a3f9b4e5265..bf0a69296dfd 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
@@ -68,7 +68,7 @@ class ControlsActivity @Inject constructor(
getLifecycle().addObserver(
ControlsAnimations.observerForAnimations(
- requireViewById<ViewGroup>(R.id.control_detail_root),
+ requireViewById(R.id.control_detail_root),
window,
intent,
!featureFlags.isEnabled(Flags.USE_APP_PANELS)
@@ -95,7 +95,7 @@ class ControlsActivity @Inject constructor(
override fun onStart() {
super.onStart()
- parent = requireViewById<ViewGroup>(R.id.global_actions_controls)
+ parent = requireViewById(R.id.control_detail_root)
parent.alpha = 0f
if (featureFlags.isEnabled(Flags.USE_APP_PANELS) && !keyguardStateController.isUnlocked) {
controlsSettingsDialogManager.maybeShowDialog(this) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialogsFactory.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialogsFactory.kt
new file mode 100644
index 000000000000..d6cfb79101d7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialogsFactory.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.controls.ui
+
+import android.app.Dialog
+import android.content.Context
+import android.content.DialogInterface
+import com.android.systemui.R
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import java.util.function.Consumer
+import javax.inject.Inject
+
+class ControlsDialogsFactory(private val internalDialogFactory: (Context) -> SystemUIDialog) {
+
+ @Inject constructor() : this({ SystemUIDialog(it) })
+
+ fun createRemoveAppDialog(
+ context: Context,
+ appName: CharSequence,
+ response: Consumer<Boolean>
+ ): Dialog {
+ val listener =
+ DialogInterface.OnClickListener { _, which ->
+ response.accept(which == DialogInterface.BUTTON_POSITIVE)
+ }
+ return internalDialogFactory(context).apply {
+ setTitle(context.getString(R.string.controls_panel_remove_app_authorization, appName))
+ setCanceledOnTouchOutside(true)
+ setOnCancelListener { response.accept(false) }
+ setPositiveButton(R.string.controls_dialog_remove, listener)
+ setNeutralButton(R.string.cancel, listener)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
index 58673bb6f567..0d5311752ab9 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
@@ -64,8 +64,6 @@ interface ControlsUiController {
* This element will be the one that appears when the user first opens the controls activity.
*/
fun getPreferredSelectedItem(structures: List<StructureInfo>): SelectedItem
-
- fun updatePreferences(selectedItem: SelectedItem)
}
sealed class SelectedItem {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 9405c602caf7..5da86de933e6 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter
import android.animation.ObjectAnimator
import android.app.Activity
import android.app.ActivityOptions
+import android.app.Dialog
import android.app.PendingIntent
import android.content.ComponentName
import android.content.Context
@@ -52,7 +53,6 @@ import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.controls.ControlsMetricsLogger
import com.android.systemui.controls.ControlsServiceInfo
-import com.android.systemui.controls.settings.ControlsSettingsRepository
import com.android.systemui.controls.CustomIconCache
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.controller.StructureInfo
@@ -64,6 +64,8 @@ import com.android.systemui.controls.management.ControlsFavoritingActivity
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
+import com.android.systemui.controls.panels.SelectedComponentRepository
+import com.android.systemui.controls.settings.ControlsSettingsRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -72,9 +74,7 @@ import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.globalactions.GlobalActionsPopupMenu
import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.asIndenting
import com.android.systemui.util.concurrency.DelayableExecutor
@@ -97,24 +97,22 @@ class ControlsUiControllerImpl @Inject constructor (
@Main val uiExecutor: DelayableExecutor,
@Background val bgExecutor: DelayableExecutor,
val controlsListingController: Lazy<ControlsListingController>,
- val controlActionCoordinator: ControlActionCoordinator,
+ private val controlActionCoordinator: ControlActionCoordinator,
private val activityStarter: ActivityStarter,
private val iconCache: CustomIconCache,
private val controlsMetricsLogger: ControlsMetricsLogger,
private val keyguardStateController: KeyguardStateController,
- private val userFileManager: UserFileManager,
private val userTracker: UserTracker,
private val taskViewFactory: Optional<TaskViewFactory>,
private val controlsSettingsRepository: ControlsSettingsRepository,
private val authorizedPanelsRepository: AuthorizedPanelsRepository,
+ private val selectedComponentRepository: SelectedComponentRepository,
private val featureFlags: FeatureFlags,
+ private val dialogsFactory: ControlsDialogsFactory,
dumpManager: DumpManager
) : ControlsUiController, Dumpable {
companion object {
- private const val PREF_COMPONENT = "controls_component"
- private const val PREF_STRUCTURE_OR_APP_NAME = "controls_structure"
- private const val PREF_IS_PANEL = "controls_is_panel"
private const val FADE_IN_MILLIS = 200L
@@ -122,6 +120,7 @@ class ControlsUiControllerImpl @Inject constructor (
private const val ADD_CONTROLS_ID = 1L
private const val ADD_APP_ID = 2L
private const val EDIT_CONTROLS_ID = 3L
+ private const val REMOVE_APP_ID = 4L
}
private var selectedItem: SelectedItem = SelectedItem.EMPTY_SELECTION
@@ -135,12 +134,6 @@ class ControlsUiControllerImpl @Inject constructor (
private val popupThemedContext = ContextThemeWrapper(context, R.style.Control_ListPopupWindow)
private var retainCache = false
private var lastSelections = emptyList<SelectionItem>()
- private val sharedPreferences
- get() = userFileManager.getSharedPreferences(
- fileName = DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
- mode = 0,
- userId = userTracker.userId
- )
private var taskViewController: PanelTaskViewController? = null
@@ -151,6 +144,7 @@ class ControlsUiControllerImpl @Inject constructor (
private var openAppIntent: Intent? = null
private var overflowMenuAdapter: BaseAdapter? = null
+ private var removeAppDialog: Dialog? = null
private val onSeedingComplete = Consumer<Boolean> {
accepted ->
@@ -330,6 +324,29 @@ class ControlsUiControllerImpl @Inject constructor (
}
}
+ @VisibleForTesting
+ internal fun startRemovingApp(componentName: ComponentName, appName: CharSequence) {
+ removeAppDialog?.cancel()
+ removeAppDialog = dialogsFactory.createRemoveAppDialog(context, appName) {
+ if (!controlsController.get().removeFavorites(componentName)) {
+ return@createRemoveAppDialog
+ }
+
+ if (selectedComponentRepository.getSelectedComponent()?.componentName ==
+ componentName) {
+ selectedComponentRepository.removeSelectedComponent()
+ }
+
+ val selectedItem = getPreferredSelectedItem(controlsController.get().getFavorites())
+ if (selectedItem == SelectedItem.EMPTY_SELECTION) {
+ // User removed the last panel. In this case we start app selection flow and don't
+ // want to auto-add it again
+ selectedComponentRepository.setShouldAddDefaultComponent(false)
+ }
+ reload(parent)
+ }.apply { show() }
+ }
+
private fun startTargetedActivity(si: StructureInfo, klazz: Class<*>) {
val i = Intent(activityContext, klazz)
putIntentExtras(i, si)
@@ -433,7 +450,10 @@ class ControlsUiControllerImpl @Inject constructor (
val currentApps = panelsAndStructures.map { it.componentName }.toSet()
val allApps = controlsListingController.get()
.getCurrentServices().map { it.componentName }.toSet()
- createMenu(extraApps = (allApps - currentApps).isNotEmpty())
+ createMenu(
+ selectionItem = selectionItem,
+ extraApps = (allApps - currentApps).isNotEmpty(),
+ )
}
private fun createPanelView(componentName: ComponentName) {
@@ -472,7 +492,7 @@ class ControlsUiControllerImpl @Inject constructor (
}
}
- private fun createMenu(extraApps: Boolean) {
+ private fun createMenu(selectionItem: SelectionItem, extraApps: Boolean) {
val isPanel = selectedItem is SelectedItem.PanelItem
val selectedStructure = (selectedItem as? SelectedItem.StructureItem)?.structure
?: EMPTY_STRUCTURE
@@ -490,6 +510,12 @@ class ControlsUiControllerImpl @Inject constructor (
ADD_APP_ID
))
}
+ if (featureFlags.isEnabled(Flags.APP_PANELS_REMOVE_APPS_ALLOWED)) {
+ add(OverflowMenuAdapter.MenuItem(
+ context.getText(R.string.controls_menu_remove),
+ REMOVE_APP_ID,
+ ))
+ }
} else {
add(OverflowMenuAdapter.MenuItem(
context.getText(R.string.controls_menu_add),
@@ -529,6 +555,9 @@ class ControlsUiControllerImpl @Inject constructor (
ADD_APP_ID -> startProviderSelectorActivity()
ADD_CONTROLS_ID -> startFavoritingActivity(selectedStructure)
EDIT_CONTROLS_ID -> startEditingActivity(selectedStructure)
+ REMOVE_APP_ID -> startRemovingApp(
+ selectionItem.componentName, selectionItem.appName
+ )
}
dismiss()
}
@@ -546,8 +575,12 @@ class ControlsUiControllerImpl @Inject constructor (
RenderInfo.registerComponentIcon(it.componentName, it.icon)
}
- var adapter = ItemAdapter(context, R.layout.controls_spinner_item).apply {
- addAll(items)
+ val adapter = ItemAdapter(context, R.layout.controls_spinner_item).apply {
+ add(selected)
+ addAll(items
+ .filter { it !== selected }
+ .sortedBy { it.appName.toString() }
+ )
}
val iconSize = context.resources
@@ -668,29 +701,22 @@ class ControlsUiControllerImpl @Inject constructor (
}
override fun getPreferredSelectedItem(structures: List<StructureInfo>): SelectedItem {
- val sp = sharedPreferences
-
- val component = sp.getString(PREF_COMPONENT, null)?.let {
- ComponentName.unflattenFromString(it)
- } ?: EMPTY_COMPONENT
- val name = sp.getString(PREF_STRUCTURE_OR_APP_NAME, "")!!
- val isPanel = sp.getBoolean(PREF_IS_PANEL, false)
- return if (isPanel) {
- SelectedItem.PanelItem(name, component)
+ val preferredPanel = selectedComponentRepository.getSelectedComponent()
+ val component = preferredPanel?.componentName ?: EMPTY_COMPONENT
+ return if (preferredPanel?.isPanel == true) {
+ SelectedItem.PanelItem(preferredPanel.name, component)
} else {
if (structures.isEmpty()) return SelectedItem.EMPTY_SELECTION
SelectedItem.StructureItem(structures.firstOrNull {
- component == it.componentName && name == it.structure
- } ?: structures.get(0))
+ component == it.componentName && preferredPanel?.name == it.structure
+ } ?: structures[0])
}
}
- override fun updatePreferences(selectedItem: SelectedItem) {
- sharedPreferences.edit()
- .putString(PREF_COMPONENT, selectedItem.componentName.flattenToString())
- .putString(PREF_STRUCTURE_OR_APP_NAME, selectedItem.name.toString())
- .putBoolean(PREF_IS_PANEL, selectedItem is SelectedItem.PanelItem)
- .apply()
+ private fun updatePreferences(selectedItem: SelectedItem) {
+ selectedComponentRepository.setSelectedComponent(
+ SelectedComponentRepository.SelectedComponent(selectedItem)
+ )
}
private fun maybeUpdateSelectedItem(item: SelectionItem): Boolean {
@@ -728,6 +754,7 @@ class ControlsUiControllerImpl @Inject constructor (
it.value.dismiss()
}
controlActionCoordinator.closeDialogs()
+ removeAppDialog?.cancel()
}
override fun hide(parent: ViewGroup) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt
index 3b6ab20e39d4..78e87cafc4f2 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt
@@ -71,7 +71,7 @@ class PanelTaskViewController(
taskView.post {
val roundedCorner =
activityContext.resources.getDimensionPixelSize(
- R.dimen.notification_corner_radius
+ R.dimen.controls_panel_corner_radius
)
val radii = FloatArray(8) { roundedCorner.toFloat() }
taskView.background =
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index fb016911f913..cb2d6732b130 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -29,6 +29,7 @@ import com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity;
import com.android.systemui.settings.brightness.BrightnessDialog;
import com.android.systemui.statusbar.tv.notifications.TvNotificationPanelActivity;
import com.android.systemui.tuner.TunerActivity;
+import com.android.systemui.usb.UsbAccessoryUriActivity;
import com.android.systemui.usb.UsbConfirmActivity;
import com.android.systemui.usb.UsbDebuggingActivity;
import com.android.systemui.usb.UsbDebuggingSecondaryUserActivity;
@@ -94,6 +95,12 @@ public abstract class DefaultActivityBinder {
@ClassKey(UsbConfirmActivity.class)
public abstract Activity bindUsbConfirmActivity(UsbConfirmActivity activity);
+ /** Inject into UsbAccessoryUriActivity. */
+ @Binds
+ @IntoMap
+ @ClassKey(UsbAccessoryUriActivity.class)
+ public abstract Activity bindUsbAccessoryUriActivity(UsbAccessoryUriActivity activity);
+
/** Inject into CreateUserActivity. */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index f0ee44305b10..cedc226ae0a9 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -75,6 +75,7 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.connectivity.ConnectivityModule;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
@@ -256,9 +257,7 @@ public abstract class SystemUIModule {
abstract FingerprintInteractiveToAuthProvider optionalFingerprintInteractiveToAuthProvider();
@BindsOptionalOf
- //TODO(b/269430792 remove full qualifier. Full qualifier is used to avoid merge conflict.)
- abstract com.android.systemui.statusbar.events.SystemStatusAnimationScheduler
- optionalSystemStatusAnimationScheduler();
+ abstract SystemStatusAnimationScheduler optionalSystemStatusAnimationScheduler();
@SysUISingleton
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/demomode/DemoModeController.kt b/packages/SystemUI/src/com/android/systemui/demomode/DemoModeController.kt
index 84f83f1ae956..45ff963c2a9f 100644
--- a/packages/SystemUI/src/com/android/systemui/demomode/DemoModeController.kt
+++ b/packages/SystemUI/src/com/android/systemui/demomode/DemoModeController.kt
@@ -128,7 +128,6 @@ constructor(
*
* This is equivalent of creating a listener manually and adding an event handler for the given
* command, like so:
- *
* ```
* class Demoable {
* private val demoHandler = object : DemoMode {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index c3bd5d96590e..d0a92f0846d0 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -43,7 +43,6 @@ import com.android.systemui.util.concurrency.DelayableExecutor
import javax.inject.Inject
import javax.inject.Named
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.launch
@@ -131,9 +130,17 @@ constructor(
}
}
- /** Starts the dream content and dream overlay entry animations. */
+ /**
+ * Starts the dream content and dream overlay entry animations.
+ *
+ * @param downwards if true, the entry animation translations downwards into position rather
+ * than upwards.
+ */
@JvmOverloads
- fun startEntryAnimations(animatorBuilder: () -> AnimatorSet = { AnimatorSet() }) {
+ fun startEntryAnimations(
+ downwards: Boolean,
+ animatorBuilder: () -> AnimatorSet = { AnimatorSet() }
+ ) {
cancelAnimations()
mAnimator =
@@ -153,7 +160,7 @@ constructor(
interpolator = Interpolators.LINEAR
),
translationYAnimator(
- from = mDreamInTranslationYDistance.toFloat(),
+ from = mDreamInTranslationYDistance.toFloat() * (if (downwards) -1 else 1),
to = 0f,
durationMs = mDreamInTranslationYDurationMs,
interpolator = Interpolators.EMPHASIZED_DECELERATE
@@ -167,6 +174,71 @@ constructor(
}
}
+ /**
+ * Starts the dream content and dream overlay exit animations.
+ *
+ * This should only be used when the low light dream is entering, animations to/from other SysUI
+ * views is controlled by `transitionViewModel`.
+ */
+ // TODO(b/256916668): integrate with the keyguard transition model once dream surfaces work is
+ // done.
+ @JvmOverloads
+ fun startExitAnimations(animatorBuilder: () -> AnimatorSet = { AnimatorSet() }): Animator {
+ cancelAnimations()
+
+ mAnimator =
+ animatorBuilder().apply {
+ playTogether(
+ translationYAnimator(
+ from = 0f,
+ to = -mDreamInTranslationYDistance.toFloat(),
+ durationMs = mDreamInTranslationYDurationMs,
+ delayMs = 0,
+ interpolator = Interpolators.EMPHASIZED
+ ),
+ alphaAnimator(
+ from =
+ mCurrentAlphaAtPosition.getOrDefault(
+ key = POSITION_BOTTOM,
+ defaultValue = 1f
+ ),
+ to = 0f,
+ durationMs = mDreamInComplicationsAnimDurationMs,
+ delayMs = 0,
+ positions = POSITION_BOTTOM
+ )
+ .apply {
+ doOnEnd {
+ // The logical end of the animation is once the alpha and blur
+ // animations finish, end the animation so that any listeners are
+ // notified. The Y translation animation is much longer than all of
+ // the other animations due to how the spec is defined, but is not
+ // expected to run to completion.
+ mAnimator?.end()
+ }
+ },
+ alphaAnimator(
+ from =
+ mCurrentAlphaAtPosition.getOrDefault(
+ key = POSITION_TOP,
+ defaultValue = 1f
+ ),
+ to = 0f,
+ durationMs = mDreamInComplicationsAnimDurationMs,
+ delayMs = 0,
+ positions = POSITION_TOP
+ )
+ )
+ doOnEnd {
+ mAnimator = null
+ mOverlayStateController.setExitAnimationsRunning(false)
+ }
+ start()
+ }
+ mOverlayStateController.setExitAnimationsRunning(true)
+ return mAnimator as AnimatorSet
+ }
+
/** Starts the dream content and dream overlay exit animations. */
fun wakeUp(doneCallback: Runnable, executor: DelayableExecutor) {
cancelAnimations()
@@ -182,18 +254,6 @@ constructor(
}
}
- /**
- * Ends the dream content and dream overlay animations, if they're currently running.
- * @see [AnimatorSet.end]
- */
- fun endAnimations() {
- mAnimator =
- mAnimator?.let {
- it.end()
- null
- }
- }
-
private fun blurAnimator(
view: View,
fromBlurRadius: Float,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 50cfb6a905c9..4b478cdca9f9 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -23,6 +23,7 @@ import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
import static com.android.systemui.dreams.complication.ComplicationLayoutParams.POSITION_BOTTOM;
import static com.android.systemui.dreams.complication.ComplicationLayoutParams.POSITION_TOP;
+import android.animation.Animator;
import android.content.res.Resources;
import android.os.Handler;
import android.util.MathUtils;
@@ -31,6 +32,7 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
+import com.android.dream.lowlight.LowLightTransitionCoordinator;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Main;
@@ -54,11 +56,14 @@ import javax.inject.Named;
* View controller for {@link DreamOverlayContainerView}.
*/
@DreamOverlayComponent.DreamOverlayScope
-public class DreamOverlayContainerViewController extends ViewController<DreamOverlayContainerView> {
+public class DreamOverlayContainerViewController extends
+ ViewController<DreamOverlayContainerView> implements
+ LowLightTransitionCoordinator.LowLightEnterListener {
private final DreamOverlayStatusBarViewController mStatusBarViewController;
private final BlurUtils mBlurUtils;
private final DreamOverlayAnimationsController mDreamOverlayAnimationsController;
private final DreamOverlayStateController mStateController;
+ private final LowLightTransitionCoordinator mLowLightTransitionCoordinator;
private final ComplicationHostViewController mComplicationHostViewController;
@@ -143,19 +148,18 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
};
/**
- * If true, overlay entry animations should be skipped once.
- *
- * This is turned on when exiting low light and should be turned off once the entry animations
- * are skipped once.
+ * If {@code true}, the dream has just transitioned from the low light dream back to the user
+ * dream and we should play an entry animation where the overlay slides in downwards from the
+ * top instead of the typicla slide in upwards from the bottom.
*/
- private boolean mSkipEntryAnimations;
+ private boolean mExitingLowLight;
private final DreamOverlayStateController.Callback
mDreamOverlayStateCallback =
new DreamOverlayStateController.Callback() {
@Override
public void onExitLowLight() {
- mSkipEntryAnimations = true;
+ mExitingLowLight = true;
}
};
@@ -165,6 +169,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
ComplicationHostViewController complicationHostViewController,
@Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView,
DreamOverlayStatusBarViewController statusBarViewController,
+ LowLightTransitionCoordinator lowLightTransitionCoordinator,
BlurUtils blurUtils,
@Main Handler handler,
@Main Resources resources,
@@ -182,6 +187,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
mBlurUtils = blurUtils;
mDreamOverlayAnimationsController = animationsController;
mStateController = stateController;
+ mLowLightTransitionCoordinator = lowLightTransitionCoordinator;
mBouncerlessScrimController = bouncerlessScrimController;
mBouncerlessScrimController.addCallback(mBouncerlessExpansionCallback);
@@ -208,6 +214,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
mStatusBarViewController.init();
mComplicationHostViewController.init();
mDreamOverlayAnimationsController.init(mView);
+ mLowLightTransitionCoordinator.setLowLightEnterListener(this);
}
@Override
@@ -219,14 +226,10 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
// Start dream entry animations. Skip animations for low light clock.
if (!mStateController.isLowLightActive()) {
- mDreamOverlayAnimationsController.startEntryAnimations();
-
- if (mSkipEntryAnimations) {
- // If we're transitioning from the low light dream back to the user dream, skip the
- // overlay animations and show immediately.
- mDreamOverlayAnimationsController.endAnimations();
- mSkipEntryAnimations = false;
- }
+ // If this is transitioning from the low light dream to the user dream, the overlay
+ // should translate in downwards instead of upwards.
+ mDreamOverlayAnimationsController.startEntryAnimations(mExitingLowLight);
+ mExitingLowLight = false;
}
}
@@ -310,4 +313,12 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
mDreamOverlayAnimationsController.wakeUp(onAnimationEnd, callbackExecutor);
}
+
+ @Override
+ public Animator onBeforeEnterLowLight() {
+ // Return the animator so that the transition coordinator waits for the overlay exit
+ // animations to finish before entering low light, as otherwise the default DreamActivity
+ // animation plays immediately and there's no time for this animation to play.
+ return mDreamOverlayAnimationsController.startExitAnimations();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 9660aaeeceb2..854323f51555 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -16,6 +16,8 @@
package com.android.systemui.dreams;
+import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_WINDOW_TITLE;
+
import android.content.ComponentName;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
@@ -70,6 +72,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
private final ComponentName mLowLightDreamComponent;
private final UiEventLogger mUiEventLogger;
private final WindowManager mWindowManager;
+ private final String mWindowTitle;
// A reference to the {@link Window} used to hold the dream overlay.
private Window mWindow;
@@ -134,7 +137,8 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
UiEventLogger uiEventLogger,
@Nullable @Named(LowLightDreamModule.LOW_LIGHT_DREAM_COMPONENT)
ComponentName lowLightDreamComponent,
- DreamOverlayCallbackController dreamOverlayCallbackController) {
+ DreamOverlayCallbackController dreamOverlayCallbackController,
+ @Named(DREAM_OVERLAY_WINDOW_TITLE) String windowTitle) {
mContext = context;
mExecutor = executor;
mWindowManager = windowManager;
@@ -144,6 +148,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
mStateController = stateController;
mUiEventLogger = uiEventLogger;
mDreamOverlayCallbackController = dreamOverlayCallbackController;
+ mWindowTitle = windowTitle;
final ViewModelStore viewModelStore = new ViewModelStore();
final Complication.Host host =
@@ -251,7 +256,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
private boolean addOverlayWindowLocked(WindowManager.LayoutParams layoutParams) {
mWindow = new PhoneWindow(mContext);
// Default to SystemUI name for TalkBack.
- mWindow.setTitle("");
+ mWindow.setTitle(mWindowTitle);
mWindow.setAttributes(layoutParams);
mWindow.setWindowManager(null, layoutParams.token, "DreamOverlay", true);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java
index a2e11b21ea59..24e90f066622 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java
@@ -22,14 +22,18 @@ import static com.android.systemui.dreams.complication.dagger.ComplicationModule
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Debug;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.util.Log;
import android.view.View;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.lifecycle.LifecycleOwner;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.util.ViewController;
+import com.android.systemui.util.settings.SecureSettings;
import java.util.Collection;
import java.util.HashMap;
@@ -54,6 +58,8 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay
private final LifecycleOwner mLifecycleOwner;
private final ComplicationCollectionViewModel mComplicationCollectionViewModel;
private final HashMap<ComplicationId, Complication.ViewHolder> mComplications = new HashMap<>();
+ @VisibleForTesting
+ boolean mIsAnimationEnabled;
// Whether dream entry animations are finished.
private boolean mEntryAnimationsFinished = false;
@@ -64,7 +70,8 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay
ComplicationLayoutEngine layoutEngine,
DreamOverlayStateController dreamOverlayStateController,
LifecycleOwner lifecycleOwner,
- @Named(SCOPED_COMPLICATIONS_MODEL) ComplicationCollectionViewModel viewModel) {
+ @Named(SCOPED_COMPLICATIONS_MODEL) ComplicationCollectionViewModel viewModel,
+ SecureSettings secureSettings) {
super(view);
mLayoutEngine = layoutEngine;
mLifecycleOwner = lifecycleOwner;
@@ -78,6 +85,10 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay
mDreamOverlayStateController.areEntryAnimationsFinished();
}
});
+
+ // Whether animations are enabled.
+ mIsAnimationEnabled = secureSettings.getFloatForUser(
+ Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f, UserHandle.USER_CURRENT) != 0.0f;
}
@Override
@@ -148,7 +159,7 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay
// Complications to be added before dream entry animations are finished are set
// to invisible and are animated in.
- if (!mEntryAnimationsFinished) {
+ if (!mEntryAnimationsFinished && mIsAnimationEnabled) {
view.setVisibility(View.INVISIBLE);
}
mComplications.put(id, viewHolder);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java
index e39073bb6711..ff1f31245570 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java
@@ -28,6 +28,8 @@ import android.widget.FrameLayout;
import com.android.systemui.CoreStartable;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.smartspace.DreamSmartspaceController;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
import com.android.systemui.shared.condition.Monitor;
import com.android.systemui.util.condition.ConditionalCoreStartable;
@@ -68,6 +70,7 @@ public class SmartSpaceComplication implements Complication {
private final DreamSmartspaceController mSmartSpaceController;
private final DreamOverlayStateController mDreamOverlayStateController;
private final SmartSpaceComplication mComplication;
+ private final FeatureFlags mFeatureFlags;
private final BcSmartspaceDataPlugin.SmartspaceTargetListener mSmartspaceListener =
new BcSmartspaceDataPlugin.SmartspaceTargetListener() {
@@ -85,15 +88,21 @@ public class SmartSpaceComplication implements Complication {
DreamOverlayStateController dreamOverlayStateController,
SmartSpaceComplication smartSpaceComplication,
DreamSmartspaceController smartSpaceController,
- @Named(DREAM_PRETEXT_MONITOR) Monitor monitor) {
+ @Named(DREAM_PRETEXT_MONITOR) Monitor monitor,
+ FeatureFlags featureFlags) {
super(monitor);
mDreamOverlayStateController = dreamOverlayStateController;
mComplication = smartSpaceComplication;
mSmartSpaceController = smartSpaceController;
+ mFeatureFlags = featureFlags;
}
@Override
public void onStart() {
+ if (mFeatureFlags.isEnabled(Flags.HIDE_SMARTSPACE_ON_DREAM_OVERLAY)) {
+ return;
+ }
+
mDreamOverlayStateController.addCallback(new DreamOverlayStateController.Callback() {
@Override
public void onStateChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
index 13563dfd03f0..93a57543ec05 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
@@ -23,6 +23,7 @@ import android.content.res.Resources;
import com.android.dream.lowlight.dagger.LowLightDreamModule;
import com.android.settingslib.dream.DreamBackend;
+import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.DreamOverlayNotificationCountProvider;
@@ -63,6 +64,8 @@ public interface DreamModule {
String DREAM_SUPPORTED = "dream_supported";
String DREAM_PRETEXT_CONDITIONS = "dream_pretext_conditions";
String DREAM_PRETEXT_MONITOR = "dream_prtext_monitor";
+ String DREAM_OVERLAY_WINDOW_TITLE = "dream_overlay_window_title";
+
/**
* Provides the dream component
@@ -136,4 +139,11 @@ public interface DreamModule {
@Named(DREAM_PRETEXT_CONDITIONS) Set<Condition> pretextConditions) {
return new Monitor(executor, pretextConditions);
}
+
+ /** */
+ @Provides
+ @Named(DREAM_OVERLAY_WINDOW_TITLE)
+ static String providesDreamOverlayWindowTitle(@Main Resources resources) {
+ return resources.getString(R.string.app_label);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
index 73c2289ad6bd..a7b3bbcbc37b 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
@@ -254,7 +254,10 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
mCurrentScrimController = mScrimManager.getCurrentController();
session.registerCallback(() -> {
- mVelocityTracker.recycle();
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
mScrimManager.removeCallback(mScrimManagerCallback);
mCapture = null;
mNotificationShadeWindowController.setForcePluginOpen(false, this);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerScrimController.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerScrimController.java
index f5bbba780b27..776b7bd080d0 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerScrimController.java
@@ -34,7 +34,7 @@ public class BouncerScrimController implements ScrimController {
@Override
public void show() {
- mStatusBarKeyguardViewManager.showBouncer(false);
+ mStatusBarKeyguardViewManager.showPrimaryBouncer(false);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 52debfeed77f..7e41d5ee644d 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -74,8 +74,12 @@ object Flags {
val NOTIFICATION_MEMORY_MONITOR_ENABLED =
releasedFlag(112, "notification_memory_monitor_enabled")
+ /**
+ * This flag is server-controlled and should stay as [unreleasedFlag] since we never want to
+ * enable it on release builds.
+ */
val NOTIFICATION_MEMORY_LOGGING_ENABLED =
- unreleasedFlag(119, "notification_memory_logging_enabled", teamfood = true)
+ unreleasedFlag(119, "notification_memory_logging_enabled")
// TODO(b/254512731): Tracking Bug
@JvmField val NOTIFICATION_DISMISSAL_FADE = releasedFlag(113, "notification_dismissal_fade")
@@ -109,6 +113,10 @@ object Flags {
@JvmField
val NOTIFICATION_ANIMATE_BIG_PICTURE = unreleasedFlag(120, "notification_animate_big_picture")
+ @JvmField
+ val ANIMATED_NOTIFICATION_SHADE_INSETS =
+ unreleasedFlag(270682168, "animated_notification_shade_insets", teamfood = true)
+
// 200 - keyguard/lockscreen
// ** Flag retired **
// public static final BooleanFlag KEYGUARD_LAYOUT =
@@ -157,12 +165,6 @@ object Flags {
val CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES =
unreleasedFlag(216, "customizable_lock_screen_quick_affordances", teamfood = true)
- /** Shows chipbar UI whenever the device is unlocked by ActiveUnlock (watch). */
- // TODO(b/256513609): Tracking Bug
- @JvmField
- val ACTIVE_UNLOCK_CHIPBAR =
- resourceBooleanFlag(217, R.bool.flag_active_unlock_chipbar, "active_unlock_chipbar")
-
/**
* Migrates control of the LightRevealScrim's reveal effect and amount from legacy code to the
* new KeyguardTransitionRepository.
@@ -189,10 +191,6 @@ object Flags {
@JvmField
val REVAMPED_WALLPAPER_UI = unreleasedFlag(222, "revamped_wallpaper_ui", teamfood = true)
- /** A different path for unocclusion transitions back to keyguard */
- // TODO(b/262859270): Tracking Bug
- @JvmField val UNOCCLUSION_TRANSITION = releasedFlag(223, "unocclusion_transition")
-
// flag for controlling auto pin confirmation and material u shapes in bouncer
@JvmField
val AUTO_PIN_CONFIRMATION =
@@ -235,6 +233,10 @@ object Flags {
val SMARTSPACE_DATE_WEATHER_DECOUPLED =
sysPropBooleanFlag(403, "persist.sysui.ss.dw_decoupled", default = false)
+ // TODO(b/270223352): Tracking Bug
+ @JvmField
+ val HIDE_SMARTSPACE_ON_DREAM_OVERLAY = unreleasedFlag(404, "hide_smartspace_on_dream_overlay")
+
// 500 - quick settings
val PEOPLE_TILE = resourceBooleanFlag(502, R.bool.flag_conversations, "people_tile")
@@ -247,6 +249,9 @@ object Flags {
"qs_user_detail_shortcut"
)
+ @JvmField
+ val QS_PIPELINE_NEW_HOST = unreleasedFlag(504, "qs_pipeline_new_host", teamfood = false)
+
// TODO(b/254512383): Tracking Bug
@JvmField
val FULL_SCREEN_USER_SWITCHER =
@@ -269,8 +274,7 @@ object Flags {
/** Enables new QS Edit Mode visual refresh */
// TODO(b/269787742): Tracking Bug
@JvmField
- val ENABLE_NEW_QS_EDIT_MODE =
- unreleasedFlag(510, "enable_new_qs_edit_mode", teamfood = false)
+ val ENABLE_NEW_QS_EDIT_MODE = unreleasedFlag(510, "enable_new_qs_edit_mode", teamfood = false)
// 600- status bar
@@ -356,7 +360,7 @@ object Flags {
val MEDIA_TTT_RECEIVER_SUCCESS_RIPPLE = releasedFlag(910, "media_ttt_receiver_success_ripple")
// TODO(b/263512203): Tracking Bug
- val MEDIA_EXPLICIT_INDICATOR = unreleasedFlag(911, "media_explicit_indicator", teamfood = true)
+ val MEDIA_EXPLICIT_INDICATOR = unreleasedFlag(911, "media_explicit_indicator")
// TODO(b/265813373): Tracking Bug
val MEDIA_TAP_TO_TRANSFER_DISMISS_GESTURE = releasedFlag(912, "media_ttt_dismiss_gesture")
@@ -374,15 +378,27 @@ object Flags {
// TODO(b/267166152) : Tracking Bug
val MEDIA_RETAIN_RECOMMENDATIONS = unreleasedFlag(916, "media_retain_recommendations")
+ // TODO(b/270437894): Tracking Bug
+ val MEDIA_REMOTE_RESUME = unreleasedFlag(917, "media_remote_resume")
+
// 1000 - dock
val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag(1000, "simulate_dock_through_charging")
// TODO(b/254512758): Tracking Bug
@JvmField val ROUNDED_BOX_RIPPLE = releasedFlag(1002, "rounded_box_ripple")
+ // TODO(b/270882464): Tracking Bug
+ val ENABLE_DOCK_SETUP_V2 = unreleasedFlag(1005, "enable_dock_setup_v2")
+
// TODO(b/265045965): Tracking Bug
val SHOW_LOWLIGHT_ON_DIRECT_BOOT = releasedFlag(1003, "show_lowlight_on_direct_boot")
+ @JvmField
+ // TODO(b/271428141): Tracking Bug
+ val ENABLE_LOW_LIGHT_CLOCK_UNDOCKED = unreleasedFlag(
+ 1004,
+ "enable_low_light_clock_undocked", teamfood = true)
+
// 1100 - windowing
@Keep
@JvmField
@@ -436,7 +452,9 @@ object Flags {
)
// TODO(b/256873975): Tracking Bug
- @JvmField @Keep val WM_BUBBLE_BAR = unreleasedFlag(1111, "wm_bubble_bar")
+ @JvmField
+ @Keep
+ val WM_BUBBLE_BAR = sysPropBooleanFlag(1111, "persist.wm.debug.bubble_bar", default = false)
// TODO(b/260271148): Tracking bug
@Keep
@@ -459,13 +477,13 @@ object Flags {
@Keep
@JvmField
val ENABLE_PIP_SIZE_LARGE_SCREEN =
- sysPropBooleanFlag(1114, "persist.wm.debug.enable_pip_size_large_screen", default = false)
+ sysPropBooleanFlag(1114, "persist.wm.debug.enable_pip_size_large_screen", default = true)
// TODO(b/265998256): Tracking bug
@Keep
@JvmField
val ENABLE_PIP_APP_ICON_OVERLAY =
- sysPropBooleanFlag(1115, "persist.wm.debug.enable_pip_app_icon_overlay", default = false)
+ sysPropBooleanFlag(1115, "persist.wm.debug.enable_pip_app_icon_overlay", default = true)
// 1200 - predictive back
@Keep
@@ -542,7 +560,7 @@ object Flags {
// 1500 - chooser aka sharesheet
// TODO(b/254512507): Tracking Bug
- val CHOOSER_UNBUNDLED = releasedFlag(1500, "chooser_unbundled")
+ val CHOOSER_UNBUNDLED = unreleasedFlag(1500, "chooser_unbundled")
// TODO(b/266983432) Tracking Bug
val SHARESHEET_CUSTOM_ACTIONS =
@@ -630,11 +648,6 @@ object Flags {
@JvmField
val OUTPUT_SWITCHER_DEVICE_STATUS = unreleasedFlag(2502, "output_switcher_device_status")
- // TODO(b/20911786): Tracking Bug
- @JvmField
- val OUTPUT_SWITCHER_SHOW_API_ENABLED =
- releasedFlag(2503, "output_switcher_show_api_enabled", teamfood = true)
-
// 2700 - unfold transitions
// TODO(b/265764985): Tracking Bug
@Keep
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index e80e71c7b599..03b45b512010 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -2054,6 +2054,10 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
|| Intent.ACTION_SCREEN_OFF.equals(action)) {
String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
if (!SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
+ // These broadcasts are usually received when locking the device, swiping up to
+ // home (which collapses the shade), etc. In those cases, we usually don't want
+ // to animate this dialog back into the view, so we disable the exit animations.
+ mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations();
mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISMISS, reason));
}
} else if (TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt
index b0f9c4edb073..d078688e5944 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt
@@ -21,6 +21,7 @@ import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyboard.backlight.ui.KeyboardBacklightDialogCoordinator
import javax.inject.Inject
/** A [CoreStartable] that launches components interested in physical keyboard interaction. */
@@ -28,11 +29,12 @@ import javax.inject.Inject
class PhysicalKeyboardCoreStartable
@Inject
constructor(
+ private val keyboardBacklightDialogCoordinator: KeyboardBacklightDialogCoordinator,
private val featureFlags: FeatureFlags,
) : CoreStartable {
override fun start() {
if (featureFlags.isEnabled(Flags.KEYBOARD_BACKLIGHT_INDICATOR)) {
- // TODO(b/268645743) start listening for keyboard backlight brightness
+ keyboardBacklightDialogCoordinator.startListening()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt
new file mode 100644
index 000000000000..65e70b319923
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.keyboard.backlight.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyboard.data.repository.KeyboardRepository
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+
+/** Allows listening to changes to keyboard backlight level */
+@SysUISingleton
+class KeyboardBacklightInteractor
+@Inject
+constructor(
+ private val keyboardRepository: KeyboardRepository,
+) {
+
+ /** Emits current backlight level as [BacklightModel] or null if keyboard is not connected */
+ val backlight: Flow<BacklightModel?> =
+ keyboardRepository.keyboardConnected.flatMapLatest { connected ->
+ if (connected) keyboardRepository.backlight else flowOf(null)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt
new file mode 100644
index 000000000000..85d0379a77db
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.keyboard.backlight.ui
+
+import android.content.Context
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyboard.backlight.ui.view.KeyboardBacklightDialog
+import com.android.systemui.keyboard.backlight.ui.viewmodel.BacklightDialogViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * Based on the state produced from [BacklightDialogViewModel] shows or hides keyboard backlight
+ * indicator
+ */
+@SysUISingleton
+class KeyboardBacklightDialogCoordinator
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ private val context: Context,
+ private val viewModel: BacklightDialogViewModel,
+) {
+
+ var dialog: KeyboardBacklightDialog? = null
+
+ fun startListening() {
+ applicationScope.launch {
+ viewModel.dialogContent.collect { dialogViewModel ->
+ if (dialogViewModel != null) {
+ if (dialog == null) {
+ dialog = KeyboardBacklightDialog(context, dialogViewModel)
+ // pass viewModel and show
+ }
+ } else {
+ dialog?.dismiss()
+ dialog = null
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
new file mode 100644
index 000000000000..b68a2a84b5d1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.keyboard.backlight.ui.view
+
+import android.app.Dialog
+import android.content.Context
+import android.os.Bundle
+import com.android.systemui.keyboard.backlight.ui.viewmodel.BacklightDialogContentViewModel
+
+class KeyboardBacklightDialog(context: Context, val viewModel: BacklightDialogContentViewModel) :
+ Dialog(context) {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ // TODO(b/268650355) Implement the dialog
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt
new file mode 100644
index 000000000000..3ef0ca39b8f3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.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.keyboard.backlight.ui.viewmodel
+
+data class BacklightDialogContentViewModel(val currentValue: Int, val maxValue: Int)
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt
new file mode 100644
index 000000000000..86abca5faaf3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.keyboard.backlight.ui.viewmodel
+
+import android.view.accessibility.AccessibilityManager
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyboard.backlight.domain.interactor.KeyboardBacklightInteractor
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
+import javax.inject.Inject
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.map
+
+/**
+ * Responsible for dialog visibility and content - emits [BacklightDialogContentViewModel] if dialog
+ * should be shown and hidden otherwise
+ */
+@SysUISingleton
+class BacklightDialogViewModel
+@Inject
+constructor(
+ interactor: KeyboardBacklightInteractor,
+ private val accessibilityManagerWrapper: AccessibilityManagerWrapper,
+) {
+
+ private val timeoutMillis: Long
+ get() =
+ accessibilityManagerWrapper
+ .getRecommendedTimeoutMillis(
+ DEFAULT_DIALOG_TIMEOUT_MILLIS,
+ AccessibilityManager.FLAG_CONTENT_ICONS
+ )
+ .toLong()
+
+ val dialogContent: Flow<BacklightDialogContentViewModel?> =
+ interactor.backlight
+ .filterNotNull()
+ .map { BacklightDialogContentViewModel(it.level, it.maxLevel) }
+ .timeout(timeoutMillis, emitAfterTimeout = null)
+
+ private fun <T> Flow<T>.timeout(timeoutMillis: Long, emitAfterTimeout: T): Flow<T> {
+ return flatMapLatest {
+ flow {
+ emit(it)
+ delay(timeoutMillis)
+ emit(emitAfterTimeout)
+ }
+ }
+ }
+
+ private companion object {
+ const val DEFAULT_DIALOG_TIMEOUT_MILLIS = 3000
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
index 70faf406d621..9449ece0933b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
@@ -23,7 +23,7 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.keyboard.data.model.BacklightModel
+import com.android.systemui.keyboard.shared.model.BacklightModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/BacklightModel.kt
index ea15a9f18584..4a32f79285e3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/BacklightModel.kt
@@ -15,7 +15,7 @@
*
*/
-package com.android.systemui.keyboard.data.model
+package com.android.systemui.keyboard.shared.model
/**
* Model for current state of keyboard backlight brightness. [level] indicates current level of
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c857f8945b71..2815df68ad0a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -126,8 +126,6 @@ import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.dagger.KeyguardModule;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -515,8 +513,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
private CentralSurfaces mCentralSurfaces;
- private boolean mUnocclusionTransitionFlagEnabled = false;
-
private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
new DeviceConfig.OnPropertiesChangedListener() {
@Override
@@ -968,16 +964,24 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
- if (!mUnocclusionTransitionFlagEnabled) {
- setOccluded(true /* isOccluded */, true /* animate */);
+ if (!handleOnAnimationStart(
+ transit, apps, wallpapers, nonApps, finishedCallback)) {
+ // Usually we rely on animation completion to synchronize occluded status,
+ // but there was no animation to play, so just update it now.
+ setOccluded(true /* isOccluded */, false /* animate */);
}
+ }
+
+ private boolean handleOnAnimationStart(int transit, RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
+ IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
if (apps == null || apps.length == 0 || apps[0] == null) {
if (DEBUG) {
Log.d(TAG, "No apps provided to the OccludeByDream runner; "
+ "skipping occluding animation.");
}
finishedCallback.onAnimationFinished();
- return;
+ return false;
}
final RemoteAnimationTarget primary = apps[0];
@@ -987,7 +991,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
Log.w(TAG, "The occluding app isn't Dream; "
+ "finishing up. Please check that the config is correct.");
finishedCallback.onAnimationFinished();
- return;
+ return false;
}
final SyncRtSurfaceTransactionApplier applier =
@@ -1021,7 +1025,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
@Override
public void onAnimationEnd(Animator animation) {
try {
- if (!mIsCancelled && mUnocclusionTransitionFlagEnabled) {
+ if (!mIsCancelled) {
// We're already on the main thread, don't queue this call
handleSetOccluded(true /* isOccluded */,
false /* animate */);
@@ -1036,6 +1040,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mOccludeByDreamAnimator.start();
});
+ return true;
}
};
@@ -1198,7 +1203,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
ScreenOnCoordinator screenOnCoordinator,
InteractionJankMonitor interactionJankMonitor,
DreamOverlayStateController dreamOverlayStateController,
- FeatureFlags featureFlags,
Lazy<ShadeController> shadeControllerLazy,
Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy,
Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
@@ -1257,7 +1261,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mDreamOpenAnimationDuration = (int) DREAMING_ANIMATION_DURATION_MS;
mDreamCloseAnimationDuration = (int) LOCKSCREEN_ANIMATION_DURATION_MS;
- mUnocclusionTransitionFlagEnabled = featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION);
}
public void userActivity() {
@@ -1929,20 +1932,24 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
// If the keyguard is already showing, see if we don't need to bother re-showing it. Check
// flags in both files to account for the hiding animation which results in a delay and
- // discrepancy between flags.
+ // discrepancy between flags. If we're in the middle of hiding, do not short circuit so that
+ // we explicitly re-set state.
if (mShowing && mKeyguardStateController.isShowing()) {
- if (mPM.isInteractive()) {
+ if (mPM.isInteractive() && !mHiding) {
// It's already showing, and we're not trying to show it while the screen is off.
// We can simply reset all of the views.
- if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
+ if (DEBUG) Log.d(TAG, "doKeyguard: not showing (instead, resetting) because it is "
+ + "already showing, we're interactive, and we were not previously hiding. "
+ + "It should be safe to short-circuit here.");
resetStateLocked();
return;
} else {
- // We are trying to show the keyguard while the screen is off - this results from
- // race conditions involving locking while unlocking. Don't short-circuit here and
- // ensure the keyguard is fully re-shown.
+ // We are trying to show the keyguard while the screen is off or while we were in
+ // the middle of hiding - this results from race conditions involving locking while
+ // unlocking. Don't short-circuit here and ensure the keyguard is fully re-shown.
Log.e(TAG,
- "doKeyguard: already showing, but re-showing since we're not interactive");
+ "doKeyguard: already showing, but re-showing because we're interactive or "
+ + "were in the middle of hiding.");
}
}
@@ -2436,11 +2443,19 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
if (DEBUG) Log.d(TAG, "handleShow");
}
- mHiding = false;
mKeyguardExitAnimationRunner = null;
mWakeAndUnlocking = false;
setPendingLock(false);
- setShowingLocked(true);
+
+ // Force if we we're showing in the middle of hiding, to ensure we end up in the correct
+ // state.
+ setShowingLocked(true, mHiding /* force */);
+ if (mHiding) {
+ Log.d(TAG, "Forcing setShowingLocked because mHiding=true, which means we're "
+ + "showing in the middle of hiding.");
+ }
+ mHiding = false;
+
mKeyguardViewControllerLazy.get().show(options);
resetKeyguardDonePendingLocked();
mHideAnimationRun = false;
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 98d3570106ce..47ef0fac17ab 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -39,7 +39,6 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -113,7 +112,6 @@ public class KeyguardModule {
ScreenOnCoordinator screenOnCoordinator,
InteractionJankMonitor interactionJankMonitor,
DreamOverlayStateController dreamOverlayStateController,
- FeatureFlags featureFlags,
Lazy<ShadeController> shadeController,
Lazy<NotificationShadeWindowController> notificationShadeWindowController,
Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
@@ -144,7 +142,6 @@ public class KeyguardModule {
screenOnCoordinator,
interactionJankMonitor,
dreamOverlayStateController,
- featureFlags,
shadeController,
notificationShadeWindowController,
activityLaunchAnimator,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt
index be73f851fa82..ef0c9a175141 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt
@@ -134,7 +134,9 @@ constructor(
.flowOn(backgroundDispatcher)
.distinctUntilChanged()
.onEach { settingsValue = it }
- ) { callbackFlowValue, _ -> callbackFlowValue }
+ ) { callbackFlowValue, _ ->
+ callbackFlowValue
+ }
override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState {
return if (controller.isZenAvailable) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt
index 006678546de8..356a8fb65883 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt
@@ -102,7 +102,8 @@ constructor(
// setup).
emit(Unit)
}
- ) { _, _ -> }
+ ) { _, _ ->
+ }
.flatMapLatest {
conflatedCallbackFlow {
// We want to instantiate a new SharedPreferences instance each time either the
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
index baadc66170cc..84abf57cacf2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
@@ -24,8 +24,10 @@ import android.hardware.biometrics.BiometricManager
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback
import android.os.Looper
import android.os.UserHandle
+import android.util.Log
import com.android.internal.widget.LockPatternUtils
import com.android.systemui.Dumpable
+import com.android.systemui.R
import com.android.systemui.biometrics.AuthController
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
@@ -35,6 +37,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
+import com.android.systemui.keyguard.shared.model.DevicePosture
import com.android.systemui.user.data.repository.UserRepository
import java.io.PrintWriter
import javax.inject.Inject
@@ -47,8 +50,10 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transformLatest
@@ -82,6 +87,12 @@ interface BiometricSettingsRepository {
/** Whether fingerprint feature is enabled for the current user by the DevicePolicy */
val isFingerprintEnabledByDevicePolicy: StateFlow<Boolean>
+
+ /**
+ * Whether face authentication is supported for the current device posture. Face auth can be
+ * restricted to specific postures using [R.integer.config_face_auth_supported_posture]
+ */
+ val isFaceAuthSupportedInCurrentPosture: Flow<Boolean>
}
@SysUISingleton
@@ -98,11 +109,27 @@ constructor(
@Background backgroundDispatcher: CoroutineDispatcher,
biometricManager: BiometricManager?,
@Main looper: Looper,
+ devicePostureRepository: DevicePostureRepository,
dumpManager: DumpManager,
) : BiometricSettingsRepository, Dumpable {
+ override val isFaceAuthSupportedInCurrentPosture: Flow<Boolean>
+
init {
dumpManager.registerDumpable(this)
+ val configFaceAuthSupportedPosture =
+ DevicePosture.toPosture(
+ context.resources.getInteger(R.integer.config_face_auth_supported_posture)
+ )
+ isFaceAuthSupportedInCurrentPosture =
+ if (configFaceAuthSupportedPosture == DevicePosture.UNKNOWN) {
+ flowOf(true)
+ } else {
+ devicePostureRepository.currentDevicePosture.map {
+ it == configFaceAuthSupportedPosture
+ }
+ }
+ .onEach { Log.d(TAG, "isFaceAuthSupportedInCurrentPosture value changed to: $it") }
}
override fun dump(pw: PrintWriter, args: Array<String?>) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DevicePostureRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DevicePostureRepository.kt
new file mode 100644
index 000000000000..adb1e01d0d00
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DevicePostureRepository.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.data.repository
+
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.shared.model.DevicePosture
+import com.android.systemui.statusbar.policy.DevicePostureController
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/** Provide current device posture state. */
+interface DevicePostureRepository {
+ /** Provides the current device posture. */
+ val currentDevicePosture: Flow<DevicePosture>
+}
+
+@SysUISingleton
+class DevicePostureRepositoryImpl
+@Inject
+constructor(private val postureController: DevicePostureController) : DevicePostureRepository {
+ override val currentDevicePosture: Flow<DevicePosture>
+ get() = conflatedCallbackFlow {
+ val sendPostureUpdate = { posture: Int ->
+ val currentDevicePosture = DevicePosture.toPosture(posture)
+ trySendWithFailureLogging(
+ currentDevicePosture,
+ TAG,
+ "Error sending posture update to $currentDevicePosture"
+ )
+ }
+ val callback = DevicePostureController.Callback { sendPostureUpdate(it) }
+ postureController.addCallback(callback)
+ sendPostureUpdate(postureController.devicePosture)
+
+ awaitClose { postureController.removeCallback(callback) }
+ }
+
+ companion object {
+ const val TAG = "PostureRepositoryImpl"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
index 0e85347c24b0..86e5cd738120 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
@@ -53,6 +53,7 @@ interface KeyguardBouncerRepository {
val primaryBouncerScrimmed: StateFlow<Boolean>
/**
* Set how much of the notification panel is showing on the screen.
+ *
* ```
* 0f = panel fully hidden = bouncer fully showing
* 1f = panel fully showing = bouncer fully hidden
@@ -134,6 +135,7 @@ constructor(
override val primaryBouncerScrimmed = _primaryBouncerScrimmed.asStateFlow()
/**
* Set how much of the notification panel is showing on the screen.
+ *
* ```
* 0f = panel fully hidden = bouncer fully showing
* 1f = panel fully showing = bouncer fully hidden
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index a3b3d0fd0681..76f20d25b0ec 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -80,6 +80,9 @@ interface KeyguardRepository {
*/
val isKeyguardShowing: Flow<Boolean>
+ /** Is the keyguard in a unlocked state? */
+ val isKeyguardUnlocked: Flow<Boolean>
+
/** Is an activity showing over the keyguard? */
val isKeyguardOccluded: Flow<Boolean>
@@ -278,6 +281,31 @@ constructor(
}
.distinctUntilChanged()
+ override val isKeyguardUnlocked: Flow<Boolean> =
+ conflatedCallbackFlow {
+ val callback =
+ object : KeyguardStateController.Callback {
+ override fun onUnlockedChanged() {
+ trySendWithFailureLogging(
+ keyguardStateController.isUnlocked,
+ TAG,
+ "updated isKeyguardUnlocked"
+ )
+ }
+ }
+
+ keyguardStateController.addCallback(callback)
+ // Adding the callback does not send an initial update.
+ trySendWithFailureLogging(
+ keyguardStateController.isUnlocked,
+ TAG,
+ "initial isKeyguardUnlocked"
+ )
+
+ awaitClose { keyguardStateController.removeCallback(callback) }
+ }
+ .distinctUntilChanged()
+
override val isKeyguardGoingAway: Flow<Boolean> = conflatedCallbackFlow {
val callback =
object : KeyguardStateController.Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
index 4a262f580749..f27f89995dbd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
@@ -31,6 +31,8 @@ interface KeyguardRepositoryModule {
@Binds
fun lightRevealScrimRepository(impl: LightRevealScrimRepositoryImpl): LightRevealScrimRepository
+ @Binds fun devicePostureRepository(impl: DevicePostureRepositoryImpl): DevicePostureRepository
+
@Binds
fun biometricSettingsRepository(
impl: BiometricSettingsRepositoryImpl
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index 0c4bca616e12..100bc596103d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -68,8 +68,11 @@ interface KeyguardTransitionRepository {
/**
* Begin a transition from one state to another. Transitions are interruptible, and will issue a
* [TransitionStep] with state = [TransitionState.CANCELED] before beginning the next one.
+ *
+ * When canceled, there are two options: to continue from the current position of the prior
+ * transition, or to reset the position. When [resetIfCanceled] == true, it will do the latter.
*/
- fun startTransition(info: TransitionInfo): UUID?
+ fun startTransition(info: TransitionInfo, resetIfCanceled: Boolean = false): UUID?
/**
* Allows manual control of a transition. When calling [startTransition], the consumer must pass
@@ -130,7 +133,10 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
)
}
- override fun startTransition(info: TransitionInfo): UUID? {
+ override fun startTransition(
+ info: TransitionInfo,
+ resetIfCanceled: Boolean,
+ ): UUID? {
if (lastStep.from == info.from && lastStep.to == info.to) {
Log.i(TAG, "Duplicate call to start the transition, rejecting: $info")
return null
@@ -138,7 +144,11 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
val startingValue =
if (lastStep.transitionState != TransitionState.FINISHED) {
Log.i(TAG, "Transition still active: $lastStep, canceling")
- lastStep.value
+ if (resetIfCanceled) {
+ 0f
+ } else {
+ lastStep.value
+ }
} else {
0f
}
@@ -227,10 +237,7 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
}
private fun trace(step: TransitionStep, isManual: Boolean) {
- if (
- step.transitionState != TransitionState.STARTED &&
- step.transitionState != TransitionState.FINISHED
- ) {
+ if (step.transitionState == TransitionState.RUNNING) {
return
}
val traceName =
@@ -243,7 +250,10 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
val traceCookie = traceName.hashCode()
if (step.transitionState == TransitionState.STARTED) {
Trace.beginAsyncSection(traceName, traceCookie)
- } else if (step.transitionState == TransitionState.FINISHED) {
+ } else if (
+ step.transitionState == TransitionState.FINISHED ||
+ step.transitionState == TransitionState.CANCELED
+ ) {
Trace.endAsyncSection(traceName, traceCookie)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
index dfe10381720c..eae40d61cdb6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
@@ -24,6 +24,7 @@ import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.LegacyAlternateBouncer
+import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -33,6 +34,7 @@ import kotlinx.coroutines.flow.Flow
class AlternateBouncerInteractor
@Inject
constructor(
+ private val keyguardStateController: KeyguardStateController,
private val bouncerRepository: KeyguardBouncerRepository,
private val biometricSettingsRepository: BiometricSettingsRepository,
private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
@@ -48,6 +50,7 @@ constructor(
/**
* Sets the correct bouncer states to show the alternate bouncer if it can show.
+ *
* @return whether alternateBouncer is visible
*/
fun show(): Boolean {
@@ -72,6 +75,7 @@ constructor(
* Sets the correct bouncer states to hide the bouncer. Should only be called through
* StatusBarKeyguardViewManager until ScrimController is refactored to use
* alternateBouncerInteractor.
+ *
* @return true if the alternate bouncer was newly hidden, else false.
*/
fun hide(): Boolean {
@@ -102,7 +106,8 @@ constructor(
biometricSettingsRepository.isFingerprintEnrolled.value &&
biometricSettingsRepository.isStrongBiometricAllowed.value &&
biometricSettingsRepository.isFingerprintEnabledByDevicePolicy.value &&
- !deviceEntryFingerprintAuthRepository.isLockedOut.value
+ !deviceEntryFingerprintAuthRepository.isLockedOut.value &&
+ !keyguardStateController.isUnlocked
} else {
legacyAlternateBouncer != null &&
keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(true)
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 310f44da6e66..e6568f20bc20 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
@@ -71,8 +71,7 @@ constructor(
isPrimaryBouncerShowing,
lastStartedTransitionStep,
wakefulnessState,
- isAodAvailable
- ) ->
+ isAodAvailable) ->
if (
!isAlternateBouncerShowing &&
!isPrimaryBouncerShowing &&
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 8715d1f55069..3beac0b1322e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -34,7 +34,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@@ -57,14 +56,7 @@ constructor(
private fun listenForDreamingToLockscreen() {
scope.launch {
- // Dependending on the dream, either dream state or occluded change will change first,
- // so listen for both
- combine(keyguardInteractor.isAbleToDream, keyguardInteractor.isKeyguardOccluded) {
- isAbleToDream,
- isKeyguardOccluded ->
- isAbleToDream && isKeyguardOccluded
- }
- .distinctUntilChanged()
+ keyguardInteractor.isAbleToDream
.sample(
combine(
keyguardInteractor.dozeTransitionModel,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index d01f48970c97..911861ddde47 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -130,55 +130,59 @@ constructor(
shadeRepository.shadeModel
.sample(
combine(
- keyguardTransitionInteractor.finishedKeyguardState,
+ keyguardTransitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.statusBarState,
- ::Pair
+ keyguardInteractor.isKeyguardUnlocked,
+ ::toTriple
),
- ::toTriple
+ ::toQuad
)
- .collect { (shadeModel, keyguardState, statusBarState) ->
+ .collect { (shadeModel, keyguardState, statusBarState, isKeyguardUnlocked) ->
val id = transitionId
if (id != null) {
- // An existing `id` means a transition is started, and calls to
- // `updateTransition` will control it until FINISHED or CANCELED
- var nextState =
- if (shadeModel.expansionAmount == 0f) {
- TransitionState.FINISHED
- } else if (shadeModel.expansionAmount == 1f) {
- TransitionState.CANCELED
- } else {
- TransitionState.RUNNING
- }
- keyguardTransitionRepository.updateTransition(
- id,
- 1f - shadeModel.expansionAmount,
- nextState,
- )
+ if (keyguardState.to == KeyguardState.PRIMARY_BOUNCER) {
+ // An existing `id` means a transition is started, and calls to
+ // `updateTransition` will control it until FINISHED or CANCELED
+ var nextState =
+ if (shadeModel.expansionAmount == 0f) {
+ TransitionState.FINISHED
+ } else if (shadeModel.expansionAmount == 1f) {
+ TransitionState.CANCELED
+ } else {
+ TransitionState.RUNNING
+ }
+ keyguardTransitionRepository.updateTransition(
+ id,
+ 1f - shadeModel.expansionAmount,
+ nextState,
+ )
- if (
- nextState == TransitionState.CANCELED ||
- nextState == TransitionState.FINISHED
- ) {
- transitionId = null
- }
+ if (
+ nextState == TransitionState.CANCELED ||
+ nextState == TransitionState.FINISHED
+ ) {
+ transitionId = null
+ }
- // If canceled, just put the state back
- if (nextState == TransitionState.CANCELED) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.PRIMARY_BOUNCER,
- to = KeyguardState.LOCKSCREEN,
- animator = getAnimator(0.milliseconds)
+ // If canceled, just put the state back
+ if (nextState == TransitionState.CANCELED) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = name,
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.LOCKSCREEN,
+ animator = getAnimator(0.milliseconds)
+ )
)
- )
+ }
}
} else {
// TODO (b/251849525): Remove statusbarstate check when that state is
// integrated into KeyguardTransitionRepository
if (
- keyguardState == KeyguardState.LOCKSCREEN &&
+ keyguardState.to == KeyguardState.LOCKSCREEN &&
shadeModel.isUserDragging &&
+ !isKeyguardUnlocked &&
statusBarState == KEYGUARD
) {
transitionId =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index b59b413d7a40..94961cbf4240 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -17,6 +17,9 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Password
+import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -26,6 +29,8 @@ import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@@ -37,7 +42,8 @@ constructor(
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor
+ private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ private val keyguardSecurityModel: KeyguardSecurityModel,
) : TransitionInteractor(FromPrimaryBouncerTransitionInteractor::class.simpleName!!) {
override fun start() {
@@ -93,31 +99,47 @@ constructor(
private fun listenForPrimaryBouncerToGone() {
scope.launch {
keyguardInteractor.isKeyguardGoingAway
- .sample(keyguardTransitionInteractor.finishedKeyguardState) { a, b -> Pair(a, b) }
- .collect { pair ->
- val (isKeyguardGoingAway, keyguardState) = pair
- if (isKeyguardGoingAway && keyguardState == KeyguardState.PRIMARY_BOUNCER) {
+ .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .collect { (isKeyguardGoingAway, lastStartedTransitionStep) ->
+ if (
+ isKeyguardGoingAway &&
+ lastStartedTransitionStep.to == KeyguardState.PRIMARY_BOUNCER
+ ) {
+ val securityMode =
+ keyguardSecurityModel.getSecurityMode(
+ KeyguardUpdateMonitor.getCurrentUser()
+ )
+ // IME for password requires a slightly faster animation
+ val duration =
+ if (securityMode == Password) {
+ TO_GONE_SHORT_DURATION
+ } else {
+ TO_GONE_DURATION
+ }
keyguardTransitionRepository.startTransition(
TransitionInfo(
ownerName = name,
from = KeyguardState.PRIMARY_BOUNCER,
to = KeyguardState.GONE,
- animator = getAnimator(),
- )
+ animator = getAnimator(duration),
+ ),
+ resetIfCanceled = true,
)
}
}
}
}
- private fun getAnimator(): ValueAnimator {
+ private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
return ValueAnimator().apply {
setInterpolator(Interpolators.LINEAR)
- setDuration(TRANSITION_DURATION_MS)
+ setDuration(duration.inWholeMilliseconds)
}
}
companion object {
- private const val TRANSITION_DURATION_MS = 300L
+ private val DEFAULT_DURATION = 300.milliseconds
+ val TO_GONE_DURATION = 250.milliseconds
+ val TO_GONE_SHORT_DURATION = 200.milliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index d25aff0add86..ec99049b42e3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -33,7 +33,9 @@ import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDoz
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessModel.Companion.isWakingOrStartingToWake
import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.delay
@@ -95,6 +97,9 @@ constructor(
awaitClose { commandQueue.removeCallback(callback) }
}
+ /** The device wake/sleep state */
+ val wakefulnessModel: Flow<WakefulnessModel> = repository.wakefulness
+
/**
* Dozing and dreaming have overlapping events. If the doze state remains in FINISH, it means
* that doze mode is not running and DREAMING is ok to commence.
@@ -109,6 +114,12 @@ constructor(
isDreaming && isDozeOff(dozeTransitionModel.to)
}
)
+ .sample(
+ wakefulnessModel,
+ { isAbleToDream, wakefulnessModel ->
+ isAbleToDream && isWakingOrStartingToWake(wakefulnessModel)
+ }
+ )
.flatMapLatest { isAbleToDream ->
flow {
delay(50)
@@ -119,6 +130,8 @@ constructor(
/** Whether the keyguard is showing or not. */
val isKeyguardShowing: Flow<Boolean> = repository.isKeyguardShowing
+ /** Whether the keyguard is unlocked or not. */
+ val isKeyguardUnlocked: Flow<Boolean> = repository.isKeyguardUnlocked
/** Whether the keyguard is occluded (covered by an activity). */
val isKeyguardOccluded: Flow<Boolean> = repository.isKeyguardOccluded
/** Whether the keyguard is going away. */
@@ -127,8 +140,6 @@ constructor(
val primaryBouncerShowing: Flow<Boolean> = bouncerRepository.primaryBouncerVisible
/** Whether the alternate bouncer is showing or not. */
val alternateBouncerShowing: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
- /** The device wake/sleep state */
- val wakefulnessModel: Flow<WakefulnessModel> = repository.wakefulness
/** Observable for the [StatusBarState] */
val statusBarState: Flow<StatusBarState> = repository.statusBarState
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index dfbe1c216847..568cc0f42639 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -119,7 +119,7 @@ constructor(
* Notifies that a quick affordance has been "triggered" (clicked) by the user.
*
* @param configKey The configuration key corresponding to the [KeyguardQuickAffordanceModel] of
- * the affordance that was clicked
+ * the affordance that was clicked
* @param expandable An optional [Expandable] for the activity- or dialog-launch animation
*/
fun onQuickAffordanceTriggered(
@@ -198,9 +198,9 @@ constructor(
*
* @param slotId The ID of the slot.
* @param affordanceId The ID of the affordance to remove; if `null`, removes all affordances
- * from the slot.
+ * from the slot.
* @return `true` if the affordance was successfully removed; `false` otherwise (for example, if
- * the affordance was not on the slot to begin with).
+ * the affordance was not on the slot to begin with).
*/
suspend fun unselect(slotId: String, affordanceId: String?): Boolean {
check(isUsingRepository)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index 51b02779a89f..e650b9fc0e47 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -61,7 +61,15 @@ constructor(
}
scope.launch {
- keyguardInteractor.isDreaming.collect { logger.log(TAG, VERBOSE, "isDreaming", it) }
+ keyguardInteractor.isAbleToDream.collect {
+ logger.log(TAG, VERBOSE, "isAbleToDream", it)
+ }
+ }
+
+ scope.launch {
+ keyguardInteractor.isKeyguardOccluded.collect {
+ logger.log(TAG, VERBOSE, "isOccluded", it)
+ }
}
scope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 1b7da5b65a03..3c0ec350c5c5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -78,6 +78,10 @@ constructor(
val occludedToLockscreenTransition: Flow<TransitionStep> =
repository.transition(OCCLUDED, LOCKSCREEN)
+ /** PRIMARY_BOUNCER->GONE transition information. */
+ val primaryBouncerToGoneTransition: Flow<TransitionStep> =
+ repository.transition(PRIMARY_BOUNCER, GONE)
+
/**
* AOD<->LOCKSCREEN transition information, mapped to dozeAmount range of AOD (1f) <->
* Lockscreen (0f).
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/DevicePosture.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/DevicePosture.kt
new file mode 100644
index 000000000000..fff7cfe1d6a3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/DevicePosture.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.shared.model
+
+import com.android.systemui.statusbar.policy.DevicePostureController
+
+/** Represents the possible posture states of the device. */
+enum class DevicePosture {
+ UNKNOWN,
+ CLOSED,
+ HALF_OPENED,
+ OPENED,
+ FLIPPED;
+
+ companion object {
+ fun toPosture(@DevicePostureController.DevicePostureInt posture: Int): DevicePosture {
+ return when (posture) {
+ DevicePostureController.DEVICE_POSTURE_CLOSED -> CLOSED
+ DevicePostureController.DEVICE_POSTURE_HALF_OPENED -> HALF_OPENED
+ DevicePostureController.DEVICE_POSTURE_OPENED -> OPENED
+ DevicePostureController.DEVICE_POSTURE_FLIPPED -> FLIPPED
+ DevicePostureController.DEVICE_POSTURE_UNKNOWN -> UNKNOWN
+ else -> UNKNOWN
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
index ca1e27c9d19c..38b9d508f81c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
@@ -47,6 +47,7 @@ class KeyguardTransitionAnimationFlow(
duration: Duration,
onStep: (Float) -> Float,
startTime: Duration = 0.milliseconds,
+ onStart: (() -> Unit)? = null,
onCancel: (() -> Float)? = null,
onFinish: (() -> Float)? = null,
interpolator: Interpolator = LINEAR,
@@ -73,6 +74,7 @@ class KeyguardTransitionAnimationFlow(
// the ViewModels of the last update
STARTED -> {
isComplete = false
+ onStart?.invoke()
max(0f, min(1f, value))
}
// Always send a final value of 1. Because of rounding, [value] may never be
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index ab009f4a6a66..2a9060f6db47 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -342,7 +342,13 @@ object KeyguardBottomAreaViewBinder {
if (viewModel.isClickable) {
if (viewModel.useLongPress) {
view.setOnTouchListener(
- OnTouchListener(view, viewModel, messageDisplayer, vibratorHelper)
+ OnTouchListener(
+ view,
+ viewModel,
+ messageDisplayer,
+ vibratorHelper,
+ falsingManager,
+ )
)
} else {
view.setOnClickListener(OnClickListener(viewModel, checkNotNull(falsingManager)))
@@ -371,6 +377,7 @@ object KeyguardBottomAreaViewBinder {
private val viewModel: KeyguardQuickAffordanceViewModel,
private val messageDisplayer: (Int) -> Unit,
private val vibratorHelper: VibratorHelper?,
+ private val falsingManager: FalsingManager?,
) : View.OnTouchListener {
private val longPressDurationMs = ViewConfiguration.getLongPressTimeout().toLong()
@@ -395,7 +402,14 @@ object KeyguardBottomAreaViewBinder {
.scaleY(PRESSED_SCALE)
.setDuration(longPressDurationMs)
.withEndAction {
- dispatchClick(viewModel.configKey)
+ if (
+ falsingManager
+ ?.isFalseLongTap(
+ FalsingManager.MODERATE_PENALTY
+ ) == false
+ ) {
+ dispatchClick(viewModel.configKey)
+ }
cancel()
}
}
@@ -421,7 +435,8 @@ object KeyguardBottomAreaViewBinder {
// the pointer performs a click.
if (
viewModel.configKey != null &&
- distanceMoved(event) <= ViewConfiguration.getTouchSlop()
+ distanceMoved(event) <= ViewConfiguration.getTouchSlop() &&
+ falsingManager?.isFalseTap(FalsingManager.NO_PENALTY) == false
) {
dispatchClick(viewModel.configKey)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
index 7db567b2a0e9..2337ffc35fa6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
@@ -31,6 +31,7 @@ import com.android.settingslib.Utils
import com.android.systemui.keyguard.data.BouncerViewDelegate
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.ActivityStarter
import kotlinx.coroutines.awaitCancellation
@@ -44,6 +45,7 @@ object KeyguardBouncerViewBinder {
fun bind(
view: ViewGroup,
viewModel: KeyguardBouncerViewModel,
+ primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
componentFactory: KeyguardBouncerComponent.Factory
) {
// Builds the KeyguardSecurityContainerController from bouncer view group.
@@ -145,6 +147,12 @@ object KeyguardBouncerViewBinder {
}
launch {
+ primaryBouncerToGoneTransitionViewModel.bouncerAlpha.collect { alpha ->
+ securityContainerController.setAlpha(alpha)
+ }
+ }
+
+ launch {
viewModel.bouncerExpansionAmount
.filter { it == EXPANSION_VISIBLE }
.collect {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt
index ef3f242a39a9..86717537efd3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt
@@ -34,7 +34,7 @@ object KeyguardLongPressViewBinder {
* @param viewModel The view-model that models the UI state.
* @param onSingleTap A callback to invoke when the system decides that there was a single tap.
* @param falsingManager [FalsingManager] for making sure the long-press didn't just happen in
- * the user's pocket.
+ * the user's pocket.
*/
@JvmStatic
fun bind(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
index 1e3b60c27d84..ab9e6a4ce045 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
@@ -135,7 +135,7 @@ constructor(
*
* @param initiallySelectedSlotId The ID of the initial slot to render as the selected one.
* @param shouldHighlightSelectedAffordance Whether the selected quick affordance should be
- * highlighted (while all others are dimmed to make the selected one stand out).
+ * highlighted (while all others are dimmed to make the selected one stand out).
*/
fun enablePreviewMode(
initiallySelectedSlotId: String?,
@@ -187,6 +187,7 @@ constructor(
previewMode.isInPreviewMode &&
previewMode.shouldHighlightSelectedAffordance &&
!isSelected,
+ forceInactive = previewMode.isInPreviewMode
)
}
.distinctUntilChanged()
@@ -198,6 +199,7 @@ constructor(
isClickable: Boolean,
isSelected: Boolean,
isDimmed: Boolean,
+ forceInactive: Boolean,
): KeyguardQuickAffordanceViewModel {
return when (this) {
is KeyguardQuickAffordanceModel.Visible ->
@@ -213,7 +215,7 @@ constructor(
)
},
isClickable = isClickable,
- isActivated = activationState is ActivationState.Active,
+ isActivated = !forceInactive && activationState is ActivationState.Active,
isSelected = isSelected,
useLongPress = quickAffordanceInteractor.useLongPress,
isDimmed = isDimmed,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
new file mode 100644
index 000000000000..92038e24edf3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
@@ -0,0 +1,69 @@
+/*
+ * 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 com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Breaks down PRIMARY_BOUNCER->GONE transition into discrete steps for corresponding views to
+ * consume.
+ */
+@SysUISingleton
+class PrimaryBouncerToGoneTransitionViewModel
+@Inject
+constructor(
+ private val interactor: KeyguardTransitionInteractor,
+ private val statusBarStateController: SysuiStatusBarStateController,
+) {
+ private val transitionAnimation =
+ KeyguardTransitionAnimationFlow(
+ transitionDuration = TO_GONE_DURATION,
+ transitionFlow = interactor.primaryBouncerToGoneTransition,
+ )
+
+ private var leaveShadeOpen: Boolean = false
+
+ /** Bouncer container alpha */
+ val bouncerAlpha: Flow<Float> =
+ transitionAnimation.createFlow(
+ duration = 200.milliseconds,
+ onStep = { 1f - it },
+ )
+
+ /** Scrim behind alpha */
+ val scrimBehindAlpha: Flow<Float> =
+ transitionAnimation.createFlow(
+ duration = TO_GONE_DURATION,
+ interpolator = EMPHASIZED_ACCELERATE,
+ onStart = { leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide() },
+ onStep = {
+ if (leaveShadeOpen) {
+ 1f
+ } else {
+ 1f - it
+ }
+ },
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
index d69ac7fe035d..34a67403fc84 100644
--- a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
+++ b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
@@ -47,13 +47,13 @@ import kotlinx.coroutines.launch
* fresh one.
*
* @param coroutineContext An optional [CoroutineContext] to replace the dispatcher [block] is
- * invoked on.
+ * invoked on.
* @param block The block of code that should be run when the view becomes attached. It can end up
- * being invoked multiple times if the view is reattached after being detached.
+ * being invoked multiple times if the view is reattached after being detached.
* @return A [DisposableHandle] to invoke when the caller of the function destroys its [View] and is
- * no longer interested in the [block] being run the next time its attached. Calling this is an
- * optional optimization as the logic will be properly cleaned up and destroyed each time the view
- * is detached. Using this is not *thread-safe* and should only be used on the main thread.
+ * no longer interested in the [block] being run the next time its attached. Calling this is an
+ * optional optimization as the logic will be properly cleaned up and destroyed each time the view
+ * is detached. Using this is not *thread-safe* and should only be used on the main thread.
*/
@MainThread
fun View.repeatWhenAttached(
@@ -125,7 +125,6 @@ private fun createLifecycleOwnerAndRun(
* The implementation requires the caller to call [onCreate] and [onDestroy] when the view is
* attached to or detached from a view hierarchy. After [onCreate] and before [onDestroy] is called,
* the implementation monitors window state in the following way
- *
* * If the window is not visible, we are in the [Lifecycle.State.CREATED] state
* * If the window is visible but not focused, we are in the [Lifecycle.State.STARTED] state
* * If the window is visible and focused, we are in the [Lifecycle.State.RESUMED] state
diff --git a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
index f7349a2a7ae6..647e3a15ba2f 100644
--- a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
@@ -16,7 +16,6 @@ private const val TAG = "KeyguardFaceAuthManagerLog"
* Helper class for logging for [com.android.keyguard.faceauth.KeyguardFaceAuthManager]
*
* To enable logcat echoing for an entire buffer:
- *
* ```
* adb shell settings put global systemui/buffer/KeyguardFaceAuthManagerLog <logLevel>
*
diff --git a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
index 5acaa46c25d6..edc278d1ae4f 100644
--- a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
@@ -33,7 +33,6 @@ private const val TAG = "ScreenDecorationsLog"
* Helper class for logging for [com.android.systemui.ScreenDecorations]
*
* To enable logcat echoing for an entire buffer:
- *
* ```
* adb shell settings put global systemui/buffer/ScreenDecorationsLog <logLevel>
*
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/DeviceStateAutoRotationLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/DeviceStateAutoRotationLog.java
new file mode 100644
index 000000000000..beb725e61e4a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/DeviceStateAutoRotationLog.java
@@ -0,0 +1,30 @@
+/*
+ * 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.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface DeviceStateAutoRotationLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 817de7976352..98b6d70317b8 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -62,6 +62,15 @@ public class LogModule {
return factory.create("NotifLog", maxSize, false /* systrace */);
}
+ /** Provides a logging buffer for all logs related to notifications on the lockscreen. */
+ @Provides
+ @SysUISingleton
+ @NotificationLockscreenLog
+ public static LogBuffer provideNotificationLockScreenLogBuffer(
+ LogBufferFactory factory) {
+ return factory.create("NotifLockscreenLog", 50, false /* systrace */);
+ }
+
/** Provides a logging buffer for logs related to heads up presentation of notifications. */
@Provides
@SysUISingleton
@@ -361,6 +370,16 @@ public class LogModule {
}
/**
+ * Provides a {@link LogBuffer} for Device State Auto-Rotation logs.
+ */
+ @Provides
+ @SysUISingleton
+ @DeviceStateAutoRotationLog
+ public static LogBuffer provideDeviceStateAutoRotationLogBuffer(LogBufferFactory factory) {
+ return factory.create("DeviceStateAutoRotationLog", 100);
+ }
+
+ /**
* Provides a {@link LogBuffer} for bluetooth-related logs.
*/
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLockscreenLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLockscreenLog.java
new file mode 100644
index 000000000000..a2d381ec90f0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLockscreenLog.java
@@ -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.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.plugins.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/** A {@link LogBuffer} for notification & lockscreen related messages. */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface NotificationLockscreenLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
index 1712dab8aff9..29f273a5ed41 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
@@ -29,7 +29,6 @@ import kotlinx.coroutines.flow.Flow
*
* Some parts of System UI maintain a lot of pieces of state at once.
* [com.android.systemui.plugins.log.LogBuffer] allows us to easily log change events:
- *
* - 10-10 10:10:10.456: state2 updated to newVal2
* - 10-10 10:11:00.000: stateN updated to StateN(val1=true, val2=1)
* - 10-10 10:11:02.123: stateN updated to StateN(val1=true, val2=2)
@@ -37,7 +36,6 @@ import kotlinx.coroutines.flow.Flow
* - 10-10 10:11:06.000: stateN updated to StateN(val1=false, val2=3)
*
* However, it can sometimes be more useful to view the state changes in table format:
- *
* - timestamp--------- | state1- | state2- | ... | stateN.val1 | stateN.val2
* - -------------------------------------------------------------------------
* - 10-10 10:10:10.123 | val1--- | val2--- | ... | false------ | 0-----------
@@ -56,23 +54,18 @@ import kotlinx.coroutines.flow.Flow
* individual fields.
*
* How it works:
- *
* 1) Create an instance of this buffer via [TableLogBufferFactory].
- *
* 2) For any states being logged, implement [Diffable]. Implementing [Diffable] allows the state to
- * only log the fields that have *changed* since the previous update, instead of always logging all
- * fields.
- *
+ * only log the fields that have *changed* since the previous update, instead of always logging
+ * all fields.
* 3) Each time a change in a state happens, call [logDiffs]. If your state is emitted using a
- * [Flow], you should use the [logDiffsForTable] extension function to automatically log diffs any
- * time your flow emits a new value.
+ * [Flow], you should use the [logDiffsForTable] extension function to automatically log diffs
+ * any time your flow emits a new value.
*
* When a dump occurs, there will be two dumps:
- *
* 1) The change events under the dumpable name "$name-changes".
- *
* 2) This class will coalesce all the diffs into a table format and log them under the dumpable
- * name "$name-table".
+ * name "$name-table".
*
* @param maxSize the maximum size of the buffer. Must be > 0.
*/
@@ -99,11 +92,10 @@ class TableLogBuffer(
* The [newVal] object's method [Diffable.logDiffs] will be used to fetch the diffs.
*
* @param columnPrefix a prefix that will be applied to every column name that gets logged. This
- * ensures that all the columns related to the same state object will be grouped together in the
- * table.
- *
+ * ensures that all the columns related to the same state object will be grouped together in
+ * the table.
* @throws IllegalArgumentException if [columnPrefix] or column name contain "|". "|" is used as
- * the separator token for parsing, so it can't be present in any part of the column name.
+ * the separator token for parsing, so it can't be present in any part of the column name.
*/
@Synchronized
fun <T : Diffable<T>> logDiffs(columnPrefix: String, prevVal: T, newVal: T) {
@@ -117,7 +109,7 @@ class TableLogBuffer(
* Logs change(s) to the buffer using [rowInitializer].
*
* @param rowInitializer a function that will be called immediately to store relevant data on
- * the row.
+ * the row.
*/
@Synchronized
fun logChange(columnPrefix: String, rowInitializer: (TableRowLogger) -> Unit) {
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
index 7ccc43ce62c2..06668d33408d 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
@@ -38,7 +38,6 @@ constructor(
*
* @param name a unique table name
* @param maxSize the buffer max size. See [adjustMaxSize]
- *
* @return a new [TableLogBuffer] registered with [DumpManager]
*/
fun create(
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt
index a057c9f22be3..2509f21242cd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt
@@ -187,6 +187,7 @@ constructor(
/**
* Handle request to change the current position in the media track.
+ *
* @param position Place to seek to in the track.
*/
@AnyThread
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaData.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaData.kt
index 0b57175defe7..ae03f27b32cd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaData.kt
@@ -52,6 +52,7 @@ data class SmartspaceMediaData(
* Indicates if all the data is valid.
*
* TODO(b/230333302): Make MediaControlPanel more flexible so that we can display fewer than
+ *
* ```
* [NUM_REQUIRED_RECOMMENDATIONS].
* ```
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt
index 97717a64ce26..207df6bc4422 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt
@@ -329,9 +329,8 @@ constructor(
* Return the time since last active for the most-recent media.
*
* @param sortedEntries userEntries sorted from the earliest to the most-recent.
- *
* @return The duration in milliseconds from the most-recent media's last active timestamp to
- * the present. MAX_VALUE will be returned if there is no media.
+ * the present. MAX_VALUE will be returned if there is no media.
*/
private fun timeSinceActiveForMostRecentMedia(
sortedEntries: SortedMap<String, MediaData>
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
index eb6893f0f141..6023bc250b1b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
@@ -525,8 +525,8 @@ class MediaDataManager(
* through the internal listener pipeline.
*
* @param immediately indicates should apply the UI changes immediately, otherwise wait until
- * the next refresh-round before UI becomes visible. Should only be true if the update is
- * initiated by user's interaction.
+ * the next refresh-round before UI becomes visible. Should only be true if the update is
+ * initiated by user's interaction.
*/
private fun notifySmartspaceMediaDataRemoved(key: String, immediately: Boolean) {
internalListeners.forEach { it.onSmartspaceMediaDataRemoved(key, immediately) }
@@ -535,6 +535,7 @@ class MediaDataManager(
/**
* Called whenever the player has been paused or stopped for a while, or swiped from QQS. This
* will make the player not active anymore, hiding it from QQS and Keyguard.
+ *
* @see MediaData.active
*/
internal fun setTimedOut(key: String, timedOut: Boolean, forceUpdate: Boolean = false) {
@@ -1023,6 +1024,7 @@ class MediaDataManager(
* @param packageName Package name for the media app
* @param controller MediaController for the current session
* @return a Pair consisting of a list of media actions, and a list of ints representing which
+ *
* ```
* of those actions should be shown in the compact player
* ```
@@ -1126,6 +1128,7 @@ class MediaDataManager(
* [PlaybackState.ACTION_SKIP_TO_NEXT]
* @return
* ```
+ *
* A [MediaAction] with correct values set, or null if the state doesn't support it
*/
private fun getStandardAction(
@@ -1226,6 +1229,7 @@ class MediaDataManager(
}
/**
* Load a bitmap from a URI
+ *
* @param uri the uri to load
* @return bitmap, or null if couldn't be loaded
*/
@@ -1339,10 +1343,13 @@ class MediaDataManager(
fun onNotificationRemoved(key: String) {
Assert.isMainThread()
val removed = mediaEntries.remove(key) ?: return
-
+ val isEligibleForResume =
+ removed.isLocalSession() ||
+ (mediaFlags.isRemoteResumeAllowed() &&
+ removed.playbackLocation != MediaData.PLAYBACK_CAST_REMOTE)
if (keyguardUpdateMonitor.isUserInLockdown(removed.userId)) {
logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
- } else if (useMediaResumption && removed.resumeAction != null && removed.isLocalSession()) {
+ } else if (useMediaResumption && removed.resumeAction != null && isEligibleForResume) {
convertToResumePlayer(key, removed)
} else if (mediaFlags.isRetainingPlayersEnabled()) {
handlePossibleRemoval(key, removed, notificationRemoved = true)
@@ -1516,15 +1523,13 @@ class MediaDataManager(
* notification key) or vice versa.
*
* @param immediately indicates should apply the UI changes immediately, otherwise wait
- * until the next refresh-round before UI becomes visible. True by default to take in place
- * immediately.
- *
+ * until the next refresh-round before UI becomes visible. True by default to take in
+ * place immediately.
* @param receivedSmartspaceCardLatency is the latency between headphone connects and sysUI
- * displays Smartspace media targets. Will be 0 if the data is not activated by Smartspace
- * signal.
- *
+ * displays Smartspace media targets. Will be 0 if the data is not activated by Smartspace
+ * signal.
* @param isSsReactivated indicates resume media card is reactivated by Smartspace
- * recommendation signal
+ * recommendation signal
*/
fun onMediaDataLoaded(
key: String,
@@ -1539,8 +1544,8 @@ class MediaDataManager(
* Called whenever there's new Smartspace media data loaded.
*
* @param shouldPrioritize indicates the sorting priority of the Smartspace card. If true,
- * it will be prioritized as the first card. Otherwise, it will show up as the last card as
- * default.
+ * it will be prioritized as the first card. Otherwise, it will show up as the last card
+ * as default.
*/
fun onSmartspaceMediaDataLoaded(
key: String,
@@ -1555,8 +1560,8 @@ class MediaDataManager(
* Called whenever a previously existing Smartspace media data was removed.
*
* @param immediately indicates should apply the UI changes immediately, otherwise wait
- * until the next refresh-round before UI becomes visible. True by default to take in place
- * immediately.
+ * until the next refresh-round before UI becomes visible. True by default to take in
+ * place immediately.
*/
fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean = true) {}
}
@@ -1565,7 +1570,7 @@ class MediaDataManager(
* Converts the pass-in SmartspaceTarget to SmartspaceMediaData
*
* @return An empty SmartspaceMediaData with the valid target Id is returned if the
- * SmartspaceTarget's data is invalid.
+ * SmartspaceTarget's data is invalid.
*/
private fun toSmartspaceMediaData(target: SmartspaceTarget): SmartspaceMediaData {
var dismissIntent: Intent? = null
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt
index 6a512be091e1..120704c0582a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt
@@ -408,9 +408,9 @@ constructor(
* [LocalMediaManager.DeviceCallback.onAboutToConnectDeviceAdded] for more information.
*
* @property fullMediaDevice a full-fledged [MediaDevice] object representing the device. If
- * non-null, prefer using [fullMediaDevice] over [backupMediaDeviceData].
+ * non-null, prefer using [fullMediaDevice] over [backupMediaDeviceData].
* @property backupMediaDeviceData a backup [MediaDeviceData] object containing the minimum
- * information required to display the device. Only use if [fullMediaDevice] is null.
+ * information required to display the device. Only use if [fullMediaDevice] is null.
*/
private data class AboutToConnectDevice(
val fullMediaDevice: MediaDevice? = null,
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt
index 878962dc60b4..a1d9214cb215 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt
@@ -60,6 +60,7 @@ constructor(
/**
* Callback representing that a media object is now expired:
+ *
* @param key Media control unique identifier
* @param timedOut True when expired for {@code PAUSED_MEDIA_TIMEOUT} for active media,
* ```
@@ -70,6 +71,7 @@ constructor(
/**
* Callback representing that a media object [PlaybackState] has changed.
+ *
* @param key Media control unique identifier
* @param state The new [PlaybackState]
*/
@@ -77,6 +79,7 @@ constructor(
/**
* Callback representing that the [MediaSession] for an active control has been destroyed
+ *
* @param key Media control unique identifier
*/
lateinit var sessionCallback: (String) -> Unit
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
index 2d10b823f784..b0389b50cd7d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
@@ -37,6 +37,7 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.media.controls.models.player.MediaData
import com.android.systemui.media.controls.pipeline.MediaDataManager
import com.android.systemui.media.controls.pipeline.RESUME_MEDIA_TIMEOUT
+import com.android.systemui.media.controls.util.MediaFlags
import com.android.systemui.settings.UserTracker
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.Utils
@@ -63,7 +64,8 @@ constructor(
private val tunerService: TunerService,
private val mediaBrowserFactory: ResumeMediaBrowserFactory,
dumpManager: DumpManager,
- private val systemClock: SystemClock
+ private val systemClock: SystemClock,
+ private val mediaFlags: MediaFlags,
) : MediaDataManager.Listener, Dumpable {
private var useMediaResumption: Boolean = Utils.useMediaResumption(context)
@@ -231,8 +233,14 @@ constructor(
mediaBrowser = null
}
// If we don't have a resume action, check if we haven't already
- if (data.resumeAction == null && !data.hasCheckedForResume && data.isLocalSession()) {
+ val isEligibleForResume =
+ data.isLocalSession() ||
+ (mediaFlags.isRemoteResumeAllowed() &&
+ data.playbackLocation != MediaData.PLAYBACK_CAST_REMOTE)
+ if (data.resumeAction == null && !data.hasCheckedForResume && isEligibleForResume) {
// TODO also check for a media button receiver intended for restarting (b/154127084)
+ // Set null action to prevent additional attempts to connect
+ mediaDataManager.setResumeAction(key, null)
Log.d(TAG, "Checking for service component for " + data.packageName)
val pm = context.packageManager
val serviceIntent = Intent(MediaBrowserService.SERVICE_INTERFACE)
@@ -243,9 +251,6 @@ constructor(
backgroundExecutor.execute {
tryUpdateResumptionList(key, inf!!.get(0).componentInfo.componentName)
}
- } else {
- // No service found
- mediaDataManager.setResumeAction(key, null)
}
}
}
@@ -257,8 +262,6 @@ constructor(
*/
private fun tryUpdateResumptionList(key: String, componentName: ComponentName) {
Log.d(TAG, "Testing if we can connect to $componentName")
- // Set null action to prevent additional attempts to connect
- mediaDataManager.setResumeAction(key, null)
mediaBrowser =
mediaBrowserFactory.create(
object : ResumeMediaBrowser.Callback() {
@@ -291,6 +294,7 @@ constructor(
/**
* Add the component to the saved list of media browser services, checking for duplicates and
* removing older components that exceed the maximum limit
+ *
* @param componentName
*/
private fun updateResumptionList(componentName: ComponentName) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java
index 3493b2453fd6..d460b5b5d782 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java
@@ -85,16 +85,13 @@ public class ResumeMediaBrowser {
* ResumeMediaBrowser#disconnect will be called automatically with this function.
*/
public void findRecentMedia() {
- disconnect();
Bundle rootHints = new Bundle();
rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true);
- mMediaBrowser = mBrowserFactory.create(
+ MediaBrowser browser = mBrowserFactory.create(
mComponentName,
mConnectionCallback,
rootHints);
- updateMediaController();
- mLogger.logConnection(mComponentName, "findRecentMedia");
- mMediaBrowser.connect();
+ connectBrowser(browser, "findRecentMedia");
}
private final MediaBrowser.SubscriptionCallback mSubscriptionCallback =
@@ -202,6 +199,21 @@ public class ResumeMediaBrowser {
};
/**
+ * Connect using a new media browser. Disconnects the existing browser first, if it exists.
+ * @param browser media browser to connect
+ * @param reason Reason to log for connection
+ */
+ private void connectBrowser(MediaBrowser browser, String reason) {
+ mLogger.logConnection(mComponentName, reason);
+ disconnect();
+ mMediaBrowser = browser;
+ if (browser != null) {
+ browser.connect();
+ }
+ updateMediaController();
+ }
+
+ /**
* Disconnect the media browser. This should be done after callbacks have completed to
* disconnect from the media browser service.
*/
@@ -222,10 +234,9 @@ public class ResumeMediaBrowser {
* getting a media update from the app
*/
public void restart() {
- disconnect();
Bundle rootHints = new Bundle();
rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true);
- mMediaBrowser = mBrowserFactory.create(mComponentName,
+ MediaBrowser browser = mBrowserFactory.create(mComponentName,
new MediaBrowser.ConnectionCallback() {
@Override
public void onConnected() {
@@ -265,9 +276,7 @@ public class ResumeMediaBrowser {
disconnect();
}
}, rootHints);
- updateMediaController();
- mLogger.logConnection(mComponentName, "restart");
- mMediaBrowser.connect();
+ connectBrowser(browser, "restart");
}
@VisibleForTesting
@@ -305,16 +314,13 @@ public class ResumeMediaBrowser {
* ResumeMediaBrowser#disconnect should be called after this to ensure the connection is closed.
*/
public void testConnection() {
- disconnect();
Bundle rootHints = new Bundle();
rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true);
- mMediaBrowser = mBrowserFactory.create(
+ MediaBrowser browser = mBrowserFactory.create(
mComponentName,
mConnectionCallback,
rootHints);
- updateMediaController();
- mLogger.logConnection(mComponentName, "testConnection");
- mMediaBrowser.connect();
+ connectBrowser(browser, "testConnection");
}
/** Updates mMediaController based on our current browser values. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt
index 335ce1d3d694..095cf09a6c2c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt
@@ -52,10 +52,12 @@ class ResumeMediaBrowserLogger @Inject constructor(@MediaBrowserLog private val
* event.
*
* @param isBrowserConnected true if there's a currently connected
+ *
* ```
* [android.media.browse.MediaBrowser] and false otherwise.
* @param componentName
* ```
+ *
* the component name for the [ResumeMediaBrowser] that triggered this log.
*/
fun logSessionDestroyed(isBrowserConnected: Boolean, componentName: ComponentName) =
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/AnimationBindHandler.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/AnimationBindHandler.kt
index d2793bca867b..f5cc04331f94 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/AnimationBindHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/AnimationBindHandler.kt
@@ -24,10 +24,12 @@ import android.graphics.drawable.Drawable
* and conflicts due to media notifications arriving at any time during an animation. It does this
* in two parts.
* - Exit animations fired as a result of user input are tracked. When these are running, any
+ *
* ```
* bind actions are delayed until the animation completes (and then fired in sequence).
* ```
* - Continuous animations are tracked using their rebind id. Later calls using the same
+ *
* ```
* rebind id will be totally ignored to prevent the continuous animation from restarting.
* ```
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
index 4827a16d229d..2b42604e7160 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
@@ -201,7 +201,9 @@ internal constructor(
animatingColorTransitionFactory(
loadDefaultColor(R.attr.textColorSecondary),
::textSecondaryFromScheme
- ) { textSecondary -> mediaViewHolder.artistText.setTextColor(textSecondary) }
+ ) { textSecondary ->
+ mediaViewHolder.artistText.setTextColor(textSecondary)
+ }
val textTertiary =
animatingColorTransitionFactory(
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
index 9f86cd88788b..3669493f4e41 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
@@ -159,6 +159,7 @@ class IlluminationDrawable : Drawable() {
/**
* Cross fade background.
+ *
* @see setTintList
* @see backgroundColor
*/
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
index 6cf051ad7668..67d3be4a3ad2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
@@ -197,7 +197,6 @@ constructor(
private val configListener =
object : ConfigurationController.ConfigurationListener {
- var lastOrientation = -1
override fun onDensityOrFontScaleChanged() {
// System font changes should only happen when UMO is offscreen or a flicker may
@@ -214,13 +213,6 @@ constructor(
override fun onConfigChanged(newConfig: Configuration?) {
if (newConfig == null) return
isRtl = newConfig.layoutDirection == View.LAYOUT_DIRECTION_RTL
- val newOrientation = newConfig.orientation
- if (lastOrientation != newOrientation) {
- // The players actually depend on the orientation possibly, so we have to
- // recreate them (at least on large screen devices)
- lastOrientation = newOrientation
- updatePlayers(recreateMedia = true)
- }
}
override fun onUiModeChanged() {
@@ -853,10 +845,12 @@ constructor(
* @param startLocation the start location of our state or -1 if this is directly set
* @param endLocation the ending location of our state.
* @param progress the progress of the transition between startLocation and endlocation. If
+ *
* ```
* this is not a guided transformation, this will be 1.0f
* @param immediately
* ```
+ *
* should this state be applied immediately, canceling all animations?
*/
fun setCurrentState(
@@ -1100,17 +1094,17 @@ constructor(
*
* @param eventId UI event id (e.g. 800 for SMARTSPACE_CARD_SEEN)
* @param instanceId id to uniquely identify a card, e.g. each headphone generates a new
- * instanceId
+ * instanceId
* @param uid uid for the application that media comes from
* @param surfaces list of display surfaces the media card is on (e.g. lockscreen, shade) when
- * the event happened
+ * the event happened
* @param interactedSubcardRank the rank for interacted media item for recommendation card, -1
- * for tapping on card but not on any media item, 0 for first media item, 1 for second, etc.
+ * for tapping on card but not on any media item, 0 for first media item, 1 for second, etc.
* @param interactedSubcardCardinality how many media items were shown to the user when there is
- * user interaction
+ * user interaction
* @param rank the rank for media card in the media carousel, starting from 0
* @param receivedLatencyMillis latency in milliseconds for card received events. E.g. latency
- * between headphone connection to sysUI displays media recommendation card
+ * between headphone connection to sysUI displays media recommendation card
* @param isSwipeToDismiss whether is to log swipe-to-dismiss event
*/
fun logSmartspaceCardReported(
@@ -1371,6 +1365,7 @@ internal object MediaPlayerData {
/**
* Removes media player given the key.
+ *
* @param isDismissed determines whether the media player is removed from the carousel.
*/
fun removeMediaPlayer(key: String, isDismissed: Boolean = false) =
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index 4ab93daef70c..4ddff530e658 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -31,12 +31,15 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
+import android.graphics.Bitmap;
import android.graphics.BlendMode;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.drawable.Animatable;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
@@ -62,7 +65,6 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
-import androidx.appcompat.content.res.AppCompatResources;
import androidx.constraintlayout.widget.ConstraintSet;
import com.android.internal.annotations.VisibleForTesting;
@@ -145,6 +147,12 @@ public class MediaControlPanel {
private static final int SMARTSPACE_CARD_CLICK_EVENT = 760;
protected static final int SMARTSPACE_CARD_DISMISS_EVENT = 761;
+ private static final float REC_MEDIA_COVER_SCALE_FACTOR = 1.25f;
+ private static final float MEDIA_SCRIM_START_ALPHA = 0.25f;
+ private static final float MEDIA_REC_SCRIM_START_ALPHA = 0.15f;
+ private static final float MEDIA_PLAYER_SCRIM_END_ALPHA = 0.9f;
+ private static final float MEDIA_REC_SCRIM_END_ALPHA = 1.0f;
+
private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS);
// Buttons to show in small player when using semantic actions
@@ -776,7 +784,7 @@ public class MediaControlPanel {
WallpaperColors wallpaperColors = getWallpaperColor(artworkIcon);
if (wallpaperColors != null) {
mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT);
- artwork = addGradientToIcon(artworkIcon, mutableColorScheme, width, height);
+ artwork = addGradientToPlayerAlbum(artworkIcon, mutableColorScheme, width, height);
isArtworkBound = true;
} else {
// If there's no artwork, use colors from the app icon
@@ -866,8 +874,9 @@ public class MediaControlPanel {
Trace.beginAsyncSection(traceName, traceCookie);
// Capture width & height from views in foreground for artwork scaling in background
- int width = mRecommendationViewHolder.getMediaCoverContainers().get(0).getMeasuredWidth();
- int height = mRecommendationViewHolder.getMediaCoverContainers().get(0).getMeasuredHeight();
+ int width = mContext.getResources().getDimensionPixelSize(R.dimen.qs_media_rec_album_width);
+ int height = mContext.getResources().getDimensionPixelSize(
+ R.dimen.qs_media_rec_album_height_expanded);
mBackgroundExecutor.execute(() -> {
// Album art
@@ -877,7 +886,8 @@ public class MediaControlPanel {
WallpaperColors wallpaperColors = getWallpaperColor(artworkIcon);
if (wallpaperColors != null) {
mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT);
- artwork = addGradientToIcon(artworkIcon, mutableColorScheme, width, height);
+ artwork = addGradientToRecommendationAlbum(artworkIcon, mutableColorScheme, width,
+ height);
} else {
artwork = new ColorDrawable(Color.TRANSPARENT);
}
@@ -886,6 +896,11 @@ public class MediaControlPanel {
// Bind the artwork drawable to media cover.
ImageView mediaCover =
mRecommendationViewHolder.getMediaCoverItems().get(itemIndex);
+ // Rescale media cover
+ Matrix coverMatrix = new Matrix(mediaCover.getImageMatrix());
+ coverMatrix.postScale(REC_MEDIA_COVER_SCALE_FACTOR, REC_MEDIA_COVER_SCALE_FACTOR,
+ 0.5f * width, 0.5f * height);
+ mediaCover.setImageMatrix(coverMatrix);
mediaCover.setImageDrawable(artwork);
// Set up the app icon.
@@ -907,40 +922,62 @@ public class MediaControlPanel {
// This method should be called from a background thread. WallpaperColors.fromBitmap takes a
// good amount of time. We do that work on the background executor to avoid stalling animations
// on the UI Thread.
- private WallpaperColors getWallpaperColor(Icon artworkIcon) {
+ @VisibleForTesting
+ protected WallpaperColors getWallpaperColor(Icon artworkIcon) {
if (artworkIcon != null) {
if (artworkIcon.getType() == Icon.TYPE_BITMAP
|| artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) {
// Avoids extra processing if this is already a valid bitmap
- return WallpaperColors
- .fromBitmap(artworkIcon.getBitmap());
+ Bitmap artworkBitmap = artworkIcon.getBitmap();
+ if (artworkBitmap.isRecycled()) {
+ Log.d(TAG, "Cannot load wallpaper color from a recycled bitmap");
+ return null;
+ }
+ return WallpaperColors.fromBitmap(artworkBitmap);
} else {
Drawable artworkDrawable = artworkIcon.loadDrawable(mContext);
if (artworkDrawable != null) {
- return WallpaperColors
- .fromDrawable(artworkIcon.loadDrawable(mContext));
+ return WallpaperColors.fromDrawable(artworkDrawable);
}
}
}
return null;
}
- private LayerDrawable addGradientToIcon(
- Icon artworkIcon,
- ColorScheme mutableColorScheme,
- int width,
- int height
- ) {
+ @VisibleForTesting
+ protected LayerDrawable addGradientToPlayerAlbum(Icon artworkIcon,
+ ColorScheme mutableColorScheme, int width, int height) {
Drawable albumArt = getScaledBackground(artworkIcon, width, height);
- GradientDrawable gradient = (GradientDrawable) AppCompatResources
- .getDrawable(mContext, R.drawable.qs_media_scrim);
+ GradientDrawable gradient = (GradientDrawable) mContext.getDrawable(
+ R.drawable.qs_media_scrim).mutate();
+ return setupGradientColorOnDrawable(albumArt, gradient, mutableColorScheme,
+ MEDIA_SCRIM_START_ALPHA, MEDIA_PLAYER_SCRIM_END_ALPHA);
+ }
+
+ @VisibleForTesting
+ protected LayerDrawable addGradientToRecommendationAlbum(Icon artworkIcon,
+ ColorScheme mutableColorScheme, int width, int height) {
+ // First try scaling rec card using bitmap drawable.
+ // If returns null, set drawable bounds.
+ Drawable albumArt = getScaledRecommendationCover(artworkIcon, width, height);
+ if (albumArt == null) {
+ albumArt = getScaledBackground(artworkIcon, width, height);
+ }
+ GradientDrawable gradient = (GradientDrawable) mContext.getDrawable(
+ R.drawable.qs_media_rec_scrim).mutate();
+ return setupGradientColorOnDrawable(albumArt, gradient, mutableColorScheme,
+ MEDIA_REC_SCRIM_START_ALPHA, MEDIA_REC_SCRIM_END_ALPHA);
+ }
+
+ private LayerDrawable setupGradientColorOnDrawable(Drawable albumArt, GradientDrawable gradient,
+ ColorScheme mutableColorScheme, float startAlpha, float endAlpha) {
gradient.setColors(new int[] {
ColorUtilKt.getColorWithAlpha(
MediaColorSchemesKt.backgroundStartFromScheme(mutableColorScheme),
- 0.25f),
+ startAlpha),
ColorUtilKt.getColorWithAlpha(
MediaColorSchemesKt.backgroundEndFromScheme(mutableColorScheme),
- 0.9f),
+ endAlpha),
});
return new LayerDrawable(new Drawable[] { albumArt, gradient });
}
@@ -1586,6 +1623,29 @@ public class MediaControlPanel {
}
/**
+ * Scale artwork to fill the background of media covers in recommendation card.
+ */
+ @UiThread
+ private Drawable getScaledRecommendationCover(Icon artworkIcon, int width, int height) {
+ if (width == 0 || height == 0) {
+ return null;
+ }
+ if (artworkIcon != null) {
+ Bitmap bitmap;
+ if (artworkIcon.getType() == Icon.TYPE_BITMAP
+ || artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) {
+ Bitmap artworkBitmap = artworkIcon.getBitmap();
+ if (artworkBitmap != null) {
+ bitmap = Bitmap.createScaledBitmap(artworkIcon.getBitmap(), width,
+ height, false);
+ return new BitmapDrawable(mContext.getResources(), bitmap);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
* Get the current media controller
*
* @return the controller
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
index 66f12d6242b0..7fc7bdb872c9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
@@ -28,7 +28,6 @@ import android.net.Uri
import android.os.Handler
import android.os.UserHandle
import android.provider.Settings
-import android.util.Log
import android.util.MathUtils
import android.view.View
import android.view.ViewGroup
@@ -418,8 +417,8 @@ constructor(
* Calculate the alpha of the view when given a cross-fade progress.
*
* @param crossFadeProgress The current cross fade progress. 0.5f means it's just switching
- * between the start and the end location and the content is fully faded, while 0.75f means that
- * we're halfway faded in again in the target state.
+ * between the start and the end location and the content is fully faded, while 0.75f means
+ * that we're halfway faded in again in the target state.
*/
private fun calculateAlphaFromCrossFade(crossFadeProgress: Float): Float {
if (crossFadeProgress <= 0.5f) {
@@ -629,6 +628,7 @@ constructor(
*
* @param forceNoAnimation optional parameter telling the system not to animate
* @param forceStateUpdate optional parameter telling the system to update transition state
+ *
* ```
* even if location did not change
* ```
@@ -944,7 +944,7 @@ constructor(
/**
* @return the current transformation progress if we're in a guided transformation and -1
- * otherwise
+ * otherwise
*/
private fun getTransformationProgress(): Float {
if (skipQqsOnExpansion) {
@@ -1055,17 +1055,6 @@ constructor(
// This will either do a full layout pass and remeasure, or it will bypass
// that and directly set the mediaFrame's bounds within the premeasured host.
targetHost.addView(mediaFrame)
-
- if (mediaFrame.childCount > 0) {
- val child = mediaFrame.getChildAt(0)
- if (mediaFrame.height < child.height) {
- Log.wtf(
- TAG,
- "mediaFrame height is too small for child: " +
- "${mediaFrame.height} vs ${child.height}"
- )
- }
- }
}
if (isCrossFadeAnimatorRunning) {
// When cross-fading with an animation, we only notify the media carousel of the
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt
index 455b7de3dc0c..be570b4a1119 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt
@@ -126,6 +126,7 @@ constructor(
* remeasurings later on.
*
* @param location the location this host name has. Used to identify the host during
+ *
* ```
* transitions.
* ```
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
index b9b0459ad615..b4724ddebb9a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
@@ -154,9 +154,11 @@ constructor(
return transitionLayout?.translationY ?: 0.0f
}
- /** A callback for RTL config changes */
+ /** A callback for config changes */
private val configurationListener =
object : ConfigurationController.ConfigurationListener {
+ var lastOrientation = -1
+
override fun onConfigChanged(newConfig: Configuration?) {
// Because the TransitionLayout is not always attached (and calculates/caches layout
// results regardless of attach state), we have to force the layoutDirection of the
@@ -169,6 +171,13 @@ constructor(
transitionLayout?.layoutDirection = layoutDirection
refreshState()
}
+ val newOrientation = newConfig.orientation
+ if (lastOrientation != newOrientation) {
+ // Layout dimensions are possibly changing, so we need to update them. (at
+ // least on large screen devices)
+ lastOrientation = newOrientation
+ loadLayoutForType(type)
+ }
}
}
}
@@ -195,13 +204,14 @@ constructor(
* The expanded constraint set used to render a expanded player. If it is modified, make sure to
* call [refreshState]
*/
- val collapsedLayout = ConstraintSet()
-
+ var collapsedLayout = ConstraintSet()
+ @VisibleForTesting set
/**
* The expanded constraint set used to render a collapsed player. If it is modified, make sure
* to call [refreshState]
*/
- val expandedLayout = ConstraintSet()
+ var expandedLayout = ConstraintSet()
+ @VisibleForTesting set
/** Whether the guts are visible for the associated player. */
var isGutsVisible = false
@@ -348,14 +358,17 @@ constructor(
* bottom of UMO reach the bottom of this group It will change to alpha 1.0 when the visible
* bottom of UMO reach the top of the group below e.g.Album title, artist title and play-pause
* button will change alpha together.
+ *
* ```
* And their alpha becomes 1.0 when the visible bottom of UMO reach the top of controls,
* including progress bar, next button, previous button
* ```
+ *
* widgetGroupIds: a group of widgets have same state during UMO is squished,
* ```
* e.g. Album title, artist title and play-pause button
* ```
+ *
* groupEndPosition: the height of UMO, when the height reaches this value,
* ```
* widgets in this group should have 1.0 as alpha
@@ -363,6 +376,7 @@ constructor(
* visible when the height of UMO reaches the top of controls group
* (progress bar, previous button and next button)
* ```
+ *
* squishedViewState: hold the widgetState of each widget, which will be modified
* squishFraction: the squishFraction of UMO
*/
@@ -479,7 +493,7 @@ constructor(
*/
fun attach(transitionLayout: TransitionLayout, type: TYPE) =
traceSection("MediaViewController#attach") {
- updateMediaViewControllerType(type)
+ loadLayoutForType(type)
logger.logMediaLocation("attach $type", currentStartLocation, currentEndLocation)
this.transitionLayout = transitionLayout
layoutController.attach(transitionLayout)
@@ -637,7 +651,7 @@ constructor(
return result
}
- private fun updateMediaViewControllerType(type: TYPE) {
+ private fun loadLayoutForType(type: TYPE) {
this.type = type
// These XML resources contain ConstraintSets that will apply to this player type's layout
@@ -665,7 +679,7 @@ constructor(
*
* @param location Target
* @param locationWhenHidden Location that will be used when the target is not
- * [MediaHost.visible]
+ * [MediaHost.visible]
* @return State require for executing a transition, and also the respective [MediaHost].
*/
private fun obtainViewStateForLocation(@MediaLocation location: Int): TransitionViewState? {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
index c3fa76ec9433..9bc66f6c98d0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
@@ -61,4 +61,7 @@ class MediaFlags @Inject constructor(private val featureFlags: FeatureFlags) {
/** If true, do not automatically dismiss the recommendation card */
fun isPersistentSsCardEnabled() = featureFlags.isEnabled(Flags.MEDIA_RETAIN_RECOMMENDATIONS)
+
+ /** Check whether we allow remote media to generate resume controls */
+ fun isRemoteResumeAllowed() = featureFlags.isEnabled(Flags.MEDIA_REMOTE_RESUME)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java
index e35575bfc184..b5b1f0ffe23d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java
@@ -23,8 +23,6 @@ import android.util.Log;
import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.statusbar.CommandQueue;
import javax.inject.Inject;
@@ -37,26 +35,19 @@ public class MediaOutputSwitcherDialogUI implements CoreStartable, CommandQueue.
private final CommandQueue mCommandQueue;
private final MediaOutputDialogFactory mMediaOutputDialogFactory;
- private final FeatureFlags mFeatureFlags;
@Inject
public MediaOutputSwitcherDialogUI(
Context context,
CommandQueue commandQueue,
- MediaOutputDialogFactory mediaOutputDialogFactory,
- FeatureFlags featureFlags) {
+ MediaOutputDialogFactory mediaOutputDialogFactory) {
mCommandQueue = commandQueue;
mMediaOutputDialogFactory = mediaOutputDialogFactory;
- mFeatureFlags = featureFlags;
}
@Override
public void start() {
- if (mFeatureFlags.isEnabled(Flags.OUTPUT_SWITCHER_SHOW_API_ENABLED)) {
- mCommandQueue.addCallback(this);
- } else {
- Log.w(TAG, "Show media output switcher is not enabled.");
- }
+ mCommandQueue.addCallback(this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
index 720c44a0904b..ee93c3788243 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
@@ -43,7 +43,7 @@ class MediaTttUtils {
*
* @param appPackageName the package name of the app playing the media.
* @param onPackageNotFoundException a function run if a
- * [PackageManager.NameNotFoundException] occurs.
+ * [PackageManager.NameNotFoundException] occurs.
* @param isReceiver indicates whether the icon is displayed in a receiver view.
*/
fun getIconInfoFromPackageName(
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt
index 7a77c476aa11..01398cf81314 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt
@@ -70,6 +70,8 @@ constructor(
RECENT_IGNORE_UNAVAILABLE,
userTracker.userId,
backgroundExecutor
- ) { tasks -> continuation.resume(tasks) }
+ ) { tasks ->
+ continuation.resume(tasks)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt
index 6ab0da6fe3b3..75a0c6836c45 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt
@@ -33,8 +33,8 @@ import javax.inject.Inject
* launched, creating a new shortcut for [CreateNoteTaskShortcutActivity], and will finish.
*
* @see <a
- * href="https://developer.android.com/develop/ui/views/launch/shortcuts/creating-shortcuts#custom-pinned">Creating
- * a custom shortcut activity</a>
+ * href="https://developer.android.com/develop/ui/views/launch/shortcuts/creating-shortcuts#custom-pinned">Creating
+ * a custom shortcut activity</a>
*/
internal class CreateNoteTaskShortcutActivity @Inject constructor() : ComponentActivity() {
diff --git a/packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt b/packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt
index 62c99da5ed81..fb09c55dc544 100644
--- a/packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt
@@ -26,8 +26,7 @@ import dagger.multibindings.StringKey
@Module
interface QRCodeScannerModule {
- /**
- */
+ /** */
@Binds
@IntoMap
@StringKey(QRCodeScannerTile.TILE_SPEC)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt
index be93550158c6..c70cce9fec26 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt
@@ -183,7 +183,7 @@ class AutoAddTracker @VisibleForTesting constructor(
}
fun getRestoredTilePosition(tile: String): Int =
- restoredTiles?.get(tile)?.index ?: QSTileHost.POSITION_AT_END
+ restoredTiles?.get(tile)?.index ?: QSHost.POSITION_AT_END
/**
* Returns `true` if the tile has been auto-added before
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 979884cb5497..a7aac5a4824d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -135,7 +135,7 @@ public class QSAnimator implements QSHost.Callback, PagedTileLayout.PageListener
private int mNumQuickTiles;
private int mLastQQSTileHeight;
private float mLastPosition;
- private final QSTileHost mHost;
+ private final QSHost mHost;
private final Executor mExecutor;
private boolean mShowCollapsedOnKeyguard;
private int mQQSTop;
@@ -146,7 +146,7 @@ public class QSAnimator implements QSHost.Callback, PagedTileLayout.PageListener
@Inject
public QSAnimator(QS qs, QuickQSPanel quickPanel, QuickStatusBarHeader quickStatusBarHeader,
QSPanelController qsPanelController,
- QuickQSPanelController quickQSPanelController, QSTileHost qsTileHost,
+ QuickQSPanelController quickQSPanelController, QSHost qsTileHost,
@Main Executor executor, TunerService tunerService,
QSExpansionPathInterpolator qsExpansionPathInterpolator) {
mQs = qs;
@@ -485,7 +485,7 @@ public class QSAnimator implements QSHost.Callback, PagedTileLayout.PageListener
if (specs.isEmpty()) {
// specs should not be empty in a valid secondary page, as we scrolled to it.
// We may crash later on because there's a null animator.
- specs = mQsPanelController.getHost().mTileSpecs;
+ specs = mHost.getSpecs();
Log.e(TAG, "Trying to create animators for empty page " + page + ". Tiles: " + specs);
// return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
index 1da30ade951b..a71e6ddb6abd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
@@ -14,15 +14,48 @@
package com.android.systemui.qs;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.res.Resources;
+import android.os.Build;
+import android.provider.Settings;
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.plugins.qs.QSTileView;
+import com.android.systemui.util.leak.GarbageMonitor;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
public interface QSHost {
+ String TILES_SETTING = Settings.Secure.QS_TILES;
+ int POSITION_AT_END = -1;
+
+ /**
+ * Returns the default QS tiles for the context.
+ * @param context the context to obtain the resources from
+ * @return a list of specs of the default tiles
+ */
+ static List<String> getDefaultSpecs(Context context) {
+ final ArrayList<String> tiles = new ArrayList();
+
+ final Resources res = context.getResources();
+ final String defaultTileList = res.getString(R.string.quick_settings_tiles_default);
+
+ tiles.addAll(Arrays.asList(defaultTileList.split(",")));
+ if (Build.IS_DEBUGGABLE
+ && GarbageMonitor.ADD_MEMORY_TILE_TO_DEFAULT_ON_DEBUGGABLE_BUILDS) {
+ tiles.add(GarbageMonitor.MemoryTile.TILE_SPEC);
+ }
+ return tiles;
+ }
+
void warn(String message, Throwable t);
void collapsePanels();
void forceCollapsePanels();
@@ -37,6 +70,44 @@ public interface QSHost {
void removeTile(String tileSpec);
void removeTiles(Collection<String> specs);
+ List<String> getSpecs();
+ /**
+ * Create a view for a tile, iterating over all possible {@link QSFactory}.
+ *
+ * @see QSFactory#createTileView
+ */
+ QSTileView createTileView(Context themedContext, QSTile tile, boolean collapsedView);
+ /** Create a {@link QSTile} of a {@code tileSpec} type. */
+ QSTile createTile(String tileSpec);
+
+ /**
+ * Add a tile to the end
+ *
+ * @param spec string matching a pre-defined tilespec
+ */
+ void addTile(String spec);
+
+ /**
+ * Add a tile into the requested spot, or at the end if the position is greater than the number
+ * of tiles.
+ * @param spec string matching a pre-defined tilespec
+ * @param requestPosition -1 for end, 0 for beginning, or X for insertion at position X
+ */
+ void addTile(String spec, int requestPosition);
+ void addTile(ComponentName tile);
+
+ /**
+ * Adds a custom tile to the set of current tiles.
+ * @param tile the component name of the {@link android.service.quicksettings.TileService}
+ * @param end if true, the tile will be added at the end. If false, at the beginning.
+ */
+ void addTile(ComponentName tile, boolean end);
+ void removeTileByUser(ComponentName tile);
+ void changeTilesByUser(List<String> previousTiles, List<String> newTiles);
+
+ boolean isTileAdded(ComponentName componentName, int userId);
+ void setTileAdded(ComponentName componentName, int userId, boolean added);
+
int indexOf(String tileSpec);
InstanceId getNewInstanceId();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index a4f0bdf94f56..b476521f1975 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -79,7 +79,6 @@ public class QSPanel extends LinearLayout implements Tunable {
protected boolean mExpanded;
protected boolean mListening;
- @Nullable protected QSTileHost mHost;
private final List<OnConfigurationChangedListener> mOnConfigurationChangedListeners =
new ArrayList<>();
@@ -359,11 +358,6 @@ public class QSPanel extends LinearLayout implements Tunable {
}
}
- @Nullable
- public QSTileHost getHost() {
- return mHost;
- }
-
public void updateResources() {
updatePadding();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index b36d0fa9ff51..83b373d5e626 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -71,7 +71,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
@Inject
QSPanelController(QSPanel view, TunerService tunerService,
- QSTileHost qstileHost, QSCustomizerController qsCustomizerController,
+ QSHost qsHost, QSCustomizerController qsCustomizerController,
@Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,
@Named(QS_PANEL) MediaHost mediaHost,
QSTileRevealController.Factory qsTileRevealControllerFactory,
@@ -80,7 +80,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
BrightnessSliderController.Factory brightnessSliderFactory,
FalsingManager falsingManager,
StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
- super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost,
+ super(view, qsHost, qsCustomizerController, usingMediaPlayer, mediaHost,
metricsLogger, uiEventLogger, qsLogger, dumpManager);
mTunerService = tunerService;
mQsCustomizerController = qsCustomizerController;
@@ -172,12 +172,6 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
mBrightnessMirrorHandler.setController(brightnessMirrorController);
}
- /** Get the QSTileHost this panel uses. */
- public QSTileHost getHost() {
- return mHost;
- }
-
-
/** Update appearance of QSPanel. */
public void updateResources() {
mView.updateResources();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index bbdf6cc70541..2668d2e36731 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -64,7 +64,7 @@ import kotlin.jvm.functions.Function1;
public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewController<T>
implements Dumpable{
private static final String TAG = "QSPanelControllerBase";
- protected final QSTileHost mHost;
+ protected final QSHost mHost;
private final QSCustomizerController mQsCustomizerController;
private final boolean mUsingMediaPlayer;
protected final MediaHost mMediaHost;
@@ -128,7 +128,7 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
protected QSPanelControllerBase(
T view,
- QSTileHost host,
+ QSHost host,
QSCustomizerController qsCustomizerController,
@Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,
MediaHost mediaHost,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 98af9dfe7f37..0ead97976ad9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -18,7 +18,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
-import android.os.Build;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings.Secure;
@@ -56,17 +55,14 @@ import com.android.systemui.settings.UserFileManager;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.CentralSurfaces;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
-import com.android.systemui.util.leak.GarbageMonitor;
import com.android.systemui.util.settings.SecureSettings;
import org.jetbrains.annotations.NotNull;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
@@ -94,16 +90,13 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final int MAX_QS_INSTANCE_ID = 1 << 20;
- public static final int POSITION_AT_END = -1;
- public static final String TILES_SETTING = Secure.QS_TILES;
-
// Shared prefs that hold tile lifecycle info.
@VisibleForTesting
static final String TILES = "tiles_prefs";
private final Context mContext;
private final LinkedHashMap<String, QSTile> mTiles = new LinkedHashMap<>();
- protected final ArrayList<String> mTileSpecs = new ArrayList<>();
+ private final ArrayList<String> mTileSpecs = new ArrayList<>();
private final TunerService mTunerService;
private final PluginManager mPluginManager;
private final DumpManager mDumpManager;
@@ -117,7 +110,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
private final List<Callback> mCallbacks = new ArrayList<>();
@Nullable
private AutoTileManager mAutoTiles;
- private final StatusBarIconController mIconController;
private final ArrayList<QSFactory> mQsFactories = new ArrayList<>();
private int mCurrentUser;
private final Optional<CentralSurfaces> mCentralSurfacesOptional;
@@ -135,7 +127,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
@Inject
public QSTileHost(Context context,
- StatusBarIconController iconController,
QSFactory defaultFactory,
@Main Executor mainExecutor,
PluginManager pluginManager,
@@ -152,7 +143,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
TileLifecycleManager.Factory tileLifecycleManagerFactory,
UserFileManager userFileManager
) {
- mIconController = iconController;
mContext = context;
mUserContext = context;
mTunerService = tunerService;
@@ -186,10 +176,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
});
}
- public StatusBarIconController getIconController() {
- return mIconController;
- }
-
@Override
public InstanceId getNewInstanceId() {
return mInstanceIdSequence.newInstanceId();
@@ -438,12 +424,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
addTile(spec, POSITION_AT_END);
}
- /**
- * Add a tile into the requested spot, or at the end if the position is greater than the number
- * of tiles.
- * @param spec string matching a pre-defined tilespec
- * @param requestPosition -1 for end, 0 for beginning, or X for insertion at position X
- */
+ @Override
public void addTile(String spec, int requestPosition) {
mMainExecutor.execute(() ->
changeTileSpecs(tileSpecs -> {
@@ -483,15 +464,12 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
}
}
+ @Override
public void addTile(ComponentName tile) {
addTile(tile, /* end */ false);
}
- /**
- * Adds a custom tile to the set of current tiles.
- * @param tile the component name of the {@link android.service.quicksettings.TileService}
- * @param end if true, the tile will be added at the end. If false, at the beginning.
- */
+ @Override
public void addTile(ComponentName tile, boolean end) {
String spec = CustomTile.toSpec(tile);
addTile(spec, end ? POSITION_AT_END : 0);
@@ -501,6 +479,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
* This will call through {@link #changeTilesByUser}. It should only be used when a tile is
* removed by a <b>user action</b> like {@code adb}.
*/
+ @Override
public void removeTileByUser(ComponentName tile) {
mMainExecutor.execute(() -> {
List<String> newSpecs = new ArrayList<>(mTileSpecs);
@@ -519,6 +498,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
* that are removed.
*/
@MainThread
+ @Override
public void changeTilesByUser(List<String> previousTiles, List<String> newTiles) {
final List<String> copy = new ArrayList<>(previousTiles);
final int NP = copy.size();
@@ -542,8 +522,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
saveTilesToSettings(newTiles);
}
- /** Create a {@link QSTile} of a {@code tileSpec} type. */
@Nullable
+ @Override
public QSTile createTile(String tileSpec) {
for (int i = 0; i < mQsFactories.size(); i++) {
QSTile t = mQsFactories.get(i).createTile(tileSpec);
@@ -554,11 +534,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
return null;
}
- /**
- * Create a view for a tile, iterating over all possible {@link QSFactory}.
- *
- * @see QSFactory#createTileView
- */
+ @Override
public QSTileView createTileView(Context themedContext, QSTile tile, boolean collapsedView) {
for (int i = 0; i < mQsFactories.size(); i++) {
QSTileView view = mQsFactories.get(i)
@@ -578,6 +554,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
* tile.
* @param userId the user to check
*/
+ @Override
public boolean isTileAdded(ComponentName componentName, int userId) {
return mUserFileManager
.getSharedPreferences(TILES, 0, userId)
@@ -593,6 +570,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
* @param userId the user for this tile
* @param added {@code true} if the tile is being added, {@code false} otherwise
*/
+ @Override
public void setTileAdded(ComponentName componentName, int userId, boolean added) {
mUserFileManager.getSharedPreferences(TILES, 0, userId)
.edit()
@@ -600,6 +578,11 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
.apply();
}
+ @Override
+ public List<String> getSpecs() {
+ return mTileSpecs;
+ }
+
protected static List<String> loadTileSpecs(Context context, String tileList) {
final Resources res = context.getResources();
@@ -617,7 +600,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
if (tile.isEmpty()) continue;
if (tile.equals("default")) {
if (!addedDefault) {
- List<String> defaultSpecs = getDefaultSpecs(context);
+ List<String> defaultSpecs = QSHost.getDefaultSpecs(context);
for (String spec : defaultSpecs) {
if (!addedSpecs.contains(spec)) {
tiles.add(spec);
@@ -650,25 +633,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
return tiles;
}
- /**
- * Returns the default QS tiles for the context.
- * @param context the context to obtain the resources from
- * @return a list of specs of the default tiles
- */
- public static List<String> getDefaultSpecs(Context context) {
- final ArrayList<String> tiles = new ArrayList<String>();
-
- final Resources res = context.getResources();
- final String defaultTileList = res.getString(R.string.quick_settings_tiles_default);
-
- tiles.addAll(Arrays.asList(defaultTileList.split(",")));
- if (Build.IS_DEBUGGABLE
- && GarbageMonitor.ADD_MEMORY_TILE_TO_DEFAULT_ON_DEBUGGABLE_BUILDS) {
- tiles.add(GarbageMonitor.MemoryTile.TILE_SPEC);
- }
- return tiles;
- }
-
@Override
public void dump(PrintWriter pw, String[] args) {
pw.println("QSTileHost:");
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 6aabe3b1ced1..2d543139a1b4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -48,7 +48,7 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel>
private final Provider<Boolean> mUsingCollapsedLandscapeMediaProvider;
@Inject
- QuickQSPanelController(QuickQSPanel view, QSTileHost qsTileHost,
+ QuickQSPanelController(QuickQSPanel view, QSHost qsHost,
QSCustomizerController qsCustomizerController,
@Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,
@Named(QUICK_QS_PANEL) MediaHost mediaHost,
@@ -57,7 +57,7 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel>
MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
DumpManager dumpManager
) {
- super(view, qsTileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
+ super(view, qsHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
uiEventLogger, qsLogger, dumpManager);
mUsingCollapsedLandscapeMediaProvider = usingCollapsedLandscapeMediaProvider;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
index 97390112c3ed..a319fb8d8756 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
@@ -40,7 +40,7 @@ import com.android.systemui.plugins.qs.QSContainerController;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSEditEvent;
import com.android.systemui.qs.QSFragment;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -57,7 +57,7 @@ import javax.inject.Inject;
@QSScope
public class QSCustomizerController extends ViewController<QSCustomizer> {
private final TileQueryHelper mTileQueryHelper;
- private final QSTileHost mQsTileHost;
+ private final QSHost mQsHost;
private final TileAdapter mTileAdapter;
private final ScreenLifecycle mScreenLifecycle;
private final KeyguardStateController mKeyguardStateController;
@@ -104,12 +104,12 @@ public class QSCustomizerController extends ViewController<QSCustomizer> {
@Inject
protected QSCustomizerController(QSCustomizer view, TileQueryHelper tileQueryHelper,
- QSTileHost qsTileHost, TileAdapter tileAdapter, ScreenLifecycle screenLifecycle,
+ QSHost qsHost, TileAdapter tileAdapter, ScreenLifecycle screenLifecycle,
KeyguardStateController keyguardStateController, LightBarController lightBarController,
ConfigurationController configurationController, UiEventLogger uiEventLogger) {
super(view);
mTileQueryHelper = tileQueryHelper;
- mQsTileHost = qsTileHost;
+ mQsHost = qsHost;
mTileAdapter = tileAdapter;
mScreenLifecycle = screenLifecycle;
mKeyguardStateController = keyguardStateController;
@@ -175,7 +175,7 @@ public class QSCustomizerController extends ViewController<QSCustomizer> {
private void reset() {
- mTileAdapter.resetTileSpecs(QSTileHost.getDefaultSpecs(getContext()));
+ mTileAdapter.resetTileSpecs(QSHost.getDefaultSpecs(getContext()));
}
public boolean isCustomizing() {
@@ -192,7 +192,7 @@ public class QSCustomizerController extends ViewController<QSCustomizer> {
mView.show(x, y, mTileAdapter);
mUiEventLogger.log(QSEditEvent.QS_EDIT_OPEN);
}
- mTileQueryHelper.queryTiles(mQsTileHost);
+ mTileQueryHelper.queryTiles(mQsHost);
mKeyguardStateController.addCallback(mKeyguardCallback);
mView.updateNavColors(mLightBarController);
}
@@ -258,13 +258,13 @@ public class QSCustomizerController extends ViewController<QSCustomizer> {
private void save() {
if (mTileQueryHelper.isFinished()) {
- mTileAdapter.saveSpecs(mQsTileHost);
+ mTileAdapter.saveSpecs(mQsHost);
}
}
private void setTileSpecs() {
List<String> specs = new ArrayList<>();
- for (QSTile tile : mQsTileHost.getTiles()) {
+ for (QSTile tile : mQsHost.getTiles()) {
specs.add(tile.getTileSpec());
}
mTileAdapter.setTileSpecs(specs);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index d84b12c714bd..6a05684a74e8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -45,7 +45,7 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.qs.QSEditEvent;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.customize.TileAdapter.Holder;
import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
@@ -91,7 +91,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
private ItemDecoration mDecoration;
private final MarginTileDecoration mMarginDecoration;
private final int mMinNumTiles;
- private final QSTileHost mHost;
+ private final QSHost mHost;
private int mEditIndex;
private int mTileDividerIndex;
private int mFocusIndex;
@@ -117,7 +117,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
@Inject
public TileAdapter(
@QSThemedContext Context context,
- QSTileHost qsHost,
+ QSHost qsHost,
UiEventLogger uiEventLogger) {
mContext = context;
mHost = qsHost;
@@ -176,7 +176,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
mMarginDecoration.setHalfMargin(halfMargin);
}
- public void saveSpecs(QSTileHost host) {
+ public void saveSpecs(QSHost host) {
List<String> newSpecs = new ArrayList<>();
clearAccessibilityState();
for (int i = 1; i < mTiles.size() && mTiles.get(i) != null; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 32a7916da70f..d9f448493591 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -38,7 +38,7 @@ import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.State;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon;
@@ -85,7 +85,7 @@ public class TileQueryHelper {
mListener = listener;
}
- public void queryTiles(QSTileHost host) {
+ public void queryTiles(QSHost host) {
mTiles.clear();
mSpecs.clear();
mFinished = false;
@@ -97,7 +97,7 @@ public class TileQueryHelper {
return mFinished;
}
- private void addCurrentAndStockTiles(QSTileHost host) {
+ private void addCurrentAndStockTiles(QSHost host) {
String stock = mContext.getString(R.string.quick_settings_tiles_stock);
String current = Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.QS_TILES);
@@ -153,14 +153,14 @@ public class TileQueryHelper {
private class TileCollector implements QSTile.Callback {
private final List<TilePair> mQSTileList = new ArrayList<>();
- private final QSTileHost mQSTileHost;
+ private final QSHost mQSHost;
- TileCollector(List<QSTile> tilesToAdd, QSTileHost host) {
+ TileCollector(List<QSTile> tilesToAdd, QSHost host) {
for (QSTile tile: tilesToAdd) {
TilePair pair = new TilePair(tile);
mQSTileList.add(pair);
}
- mQSTileHost = host;
+ mQSHost = host;
if (tilesToAdd.isEmpty()) {
mBgExecutor.execute(this::finished);
}
@@ -168,7 +168,7 @@ public class TileQueryHelper {
private void finished() {
notifyTilesChanged(false);
- addPackageTiles(mQSTileHost);
+ addPackageTiles(mQSHost);
}
private void startListening() {
@@ -207,7 +207,7 @@ public class TileQueryHelper {
}
}
- private void addPackageTiles(final QSTileHost host) {
+ private void addPackageTiles(final QSHost host) {
mBgExecutor.execute(() -> {
Collection<QSTile> params = host.getTiles();
PackageManager pm = mContext.getPackageManager();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index 27ae1710467b..431d6e847207 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -67,7 +67,7 @@ public interface QSModule {
static AutoTileManager provideAutoTileManager(
Context context,
AutoAddTracker.Builder autoAddTrackerBuilder,
- QSTileHost host,
+ QSHost host,
@Background Handler handler,
SecureSettings secureSettings,
HotspotController hotspotController,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 7c2536dac56e..d4854e1a7daf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -328,7 +328,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
if (listening) {
updateDefaultTileAndIcon();
refreshState();
- if (!mServiceManager.isActiveTile()) {
+ if (!mServiceManager.isActiveTile() || !isTileReady()) {
mServiceManager.setBindRequested(true);
mService.onStartListening();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index e86bd7a30490..9f93e4926532 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -76,7 +76,8 @@ public class TileServiceManager {
this(tileServices, handler, userTracker, new TileLifecycleManager(handler,
tileServices.getContext(), tileServices,
new PackageManagerAdapter(tileServices.getContext()), broadcastDispatcher,
- new Intent().setComponent(component), userTracker.getUserHandle()));
+ new Intent(TileService.ACTION_QS_TILE).setComponent(component),
+ userTracker.getUserHandle()));
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt
index 237b66e79ee5..d9e5580fc14c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt
@@ -25,13 +25,13 @@ import android.os.RemoteException
import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.internal.statusbar.IAddTileResultCallback
+import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.qs.QSTileHost
+import com.android.systemui.qs.QSHost
+import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.phone.SystemUIDialog
-import com.android.systemui.R
-import com.android.systemui.statusbar.CommandQueue
import java.io.PrintWriter
import java.util.concurrent.atomic.AtomicBoolean
import java.util.function.Consumer
@@ -40,14 +40,14 @@ import javax.inject.Inject
private const val TAG = "TileServiceRequestController"
/**
- * Controller to interface between [TileRequestDialog] and [QSTileHost].
+ * Controller to interface between [TileRequestDialog] and [QSHost].
*/
class TileServiceRequestController constructor(
- private val qsTileHost: QSTileHost,
+ private val qsHost: QSHost,
private val commandQueue: CommandQueue,
private val commandRegistry: CommandRegistry,
private val eventLogger: TileRequestDialogEventLogger,
- private val dialogCreator: () -> TileRequestDialog = { TileRequestDialog(qsTileHost.context) }
+ private val dialogCreator: () -> TileRequestDialog = { TileRequestDialog(qsHost.context) }
) {
companion object {
@@ -93,7 +93,7 @@ class TileServiceRequestController constructor(
}
private fun addTile(componentName: ComponentName) {
- qsTileHost.addTile(componentName, true)
+ qsHost.addTile(componentName, true)
}
@VisibleForTesting
@@ -158,7 +158,7 @@ class TileServiceRequestController constructor(
private fun isTileAlreadyAdded(componentName: ComponentName): Boolean {
val spec = CustomTile.toSpec(componentName)
- return qsTileHost.indexOf(spec) != -1
+ return qsHost.indexOf(spec) != -1
}
inner class TileServiceRequestCommand : Command {
@@ -194,13 +194,13 @@ class TileServiceRequestController constructor(
private val commandQueue: CommandQueue,
private val commandRegistry: CommandRegistry
) {
- fun create(qsTileHost: QSTileHost): TileServiceRequestController {
+ fun create(qsHost: QSHost): TileServiceRequestController {
return TileServiceRequestController(
- qsTileHost,
+ qsHost,
commandQueue,
commandRegistry,
TileRequestDialogEventLogger()
)
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index 84a18d8dd365..adc71657e680 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -39,7 +39,7 @@ import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -68,22 +68,24 @@ public class TileServices extends IQSService.Stub {
private final Context mContext;
private final Handler mMainHandler;
private final Provider<Handler> mHandlerProvider;
- private final QSTileHost mHost;
+ private final QSHost mHost;
private final KeyguardStateController mKeyguardStateController;
private final BroadcastDispatcher mBroadcastDispatcher;
private final CommandQueue mCommandQueue;
private final UserTracker mUserTracker;
+ private final StatusBarIconController mStatusBarIconController;
private int mMaxBound = DEFAULT_MAX_BOUND;
@Inject
public TileServices(
- QSTileHost host,
+ QSHost host,
@Main Provider<Handler> handlerProvider,
BroadcastDispatcher broadcastDispatcher,
UserTracker userTracker,
KeyguardStateController keyguardStateController,
- CommandQueue commandQueue) {
+ CommandQueue commandQueue,
+ StatusBarIconController statusBarIconController) {
mHost = host;
mKeyguardStateController = keyguardStateController;
mContext = mHost.getContext();
@@ -92,6 +94,7 @@ public class TileServices extends IQSService.Stub {
mMainHandler = mHandlerProvider.get();
mUserTracker = userTracker;
mCommandQueue = commandQueue;
+ mStatusBarIconController = statusBarIconController;
mCommandQueue.addCallback(mRequestListeningCallback);
}
@@ -99,7 +102,7 @@ public class TileServices extends IQSService.Stub {
return mContext;
}
- public QSTileHost getHost() {
+ public QSHost getHost() {
return mHost;
}
@@ -131,8 +134,7 @@ public class TileServices extends IQSService.Stub {
mTiles.remove(tile.getComponent());
final String slot = tile.getComponent().getClassName();
// TileServices doesn't know how to add more than 1 icon per slot, so remove all
- mMainHandler.post(() -> mHost.getIconController()
- .removeAllIconsForExternalSlot(slot));
+ mMainHandler.post(() -> mStatusBarIconController.removeAllIconsForSlot(slot));
}
}
@@ -309,7 +311,7 @@ public class TileServices extends IQSService.Stub {
mMainHandler.post(new Runnable() {
@Override
public void run() {
- StatusBarIconController iconController = mHost.getIconController();
+ StatusBarIconController iconController = mStatusBarIconController;
iconController.setIcon(componentName.getClassName(), statusIcon);
iconController.setExternalIcon(componentName.getClassName());
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt
index 03bb7a0f45da..8387c1dd60a5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt
@@ -71,8 +71,8 @@ interface FooterActionsInteractor {
/**
* Show the device monitoring dialog, expanded from [expandable] if it's not null.
*
- * Important: [quickSettingsContext] *must* be the [Context] associated to the [Quick Settings
- * fragment][com.android.systemui.qs.QSFragment].
+ * Important: [quickSettingsContext] *must* be the [Context] associated to the
+ * [Quick Settings fragment][com.android.systemui.qs.QSFragment].
*/
fun showDeviceMonitoringDialog(quickSettingsContext: Context, expandable: Expandable?)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
index fbf32b3b99ea..f170ac1d9d4e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
@@ -196,9 +196,9 @@ class FooterActionsViewModel(
* Observe the device monitoring dialog requests and show the dialog accordingly. This function
* will suspend indefinitely and will need to be cancelled to stop observing.
*
- * Important: [quickSettingsContext] must be the [Context] associated to the [Quick Settings
- * fragment][com.android.systemui.qs.QSFragment], and the call to this function must be
- * cancelled when that fragment is destroyed.
+ * Important: [quickSettingsContext] must be the [Context] associated to the
+ * [Quick Settings fragment][com.android.systemui.qs.QSFragment], and the call to this function
+ * must be cancelled when that fragment is destroyed.
*/
suspend fun observeDeviceMonitoringDialogRequests(quickSettingsContext: Context) {
footerActionsInteractor.deviceMonitoringDialogRequests.collect {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 25ff308b46bb..019ca52107dd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -631,7 +631,9 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
final NavigationBarView navBarView =
mNavBarControllerLazy.get().getNavigationBarView(mContext.getDisplayId());
final NotificationPanelViewController panelController =
- mCentralSurfacesOptionalLazy.get().get().getNotificationPanelViewController();
+ mCentralSurfacesOptionalLazy.get()
+ .map(CentralSurfaces::getNotificationPanelViewController)
+ .orElse(null);
if (SysUiState.DEBUG) {
Log.d(TAG_OPS, "Updating sysui state flags: navBarFragment=" + navBarFragment
+ " navBarView=" + navBarView + " panelController=" + panelController);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
index dd21be971b36..30509e23d186 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
@@ -124,8 +124,9 @@ class ScreenRecordPermissionDialog(
/**
* Starts screen capture after some countdown
+ *
* @param captureTarget target to capture (could be e.g. a task) or null to record the whole
- * screen
+ * screen
*/
private fun requestScreenCapture(captureTarget: MediaProjectionCaptureTarget?) {
val userContext = userContextProvider.userContext
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
index 310baafbae1a..a8f99bef2423 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
@@ -70,7 +70,7 @@ object ActionIntentCreator {
/**
* @return an ACTION_EDIT intent for the given URI, directed to config_screenshotEditor if
- * available.
+ * available.
*/
fun createEditIntent(uri: Uri, context: Context): Intent {
val editIntent = Intent(Intent.ACTION_EDIT)
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java b/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
index ead3b7b1de53..0b4b7c691cfd 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
@@ -45,6 +45,7 @@ public class DraggableConstraintLayout extends ConstraintLayout
implements ViewTreeObserver.OnComputeInternalInsetsListener {
private static final float VELOCITY_DP_PER_MS = 1;
+ private static final int MAXIMUM_DISMISS_DISTANCE_DP = 400;
private final SwipeDismissHandler mSwipeDismissHandler;
private final GestureDetector mSwipeDetector;
@@ -347,14 +348,18 @@ public class DraggableConstraintLayout extends ConstraintLayout
} else {
finalX = -1 * getBackgroundRight();
}
- float distance = Math.abs(finalX - startX);
+ float distance = Math.min(Math.abs(finalX - startX),
+ FloatingWindowUtil.dpToPx(mDisplayMetrics, MAXIMUM_DISMISS_DISTANCE_DP));
+ // ensure that view dismisses in the right direction (right in LTR, left in RTL)
+ float distanceVector = Math.copySign(distance, finalX - startX);
anim.addUpdateListener(animation -> {
- float translation = MathUtils.lerp(startX, finalX, animation.getAnimatedFraction());
+ float translation = MathUtils.lerp(
+ startX, startX + distanceVector, animation.getAnimatedFraction());
mView.setTranslationX(translation);
mView.setAlpha(1 - animation.getAnimatedFraction());
});
- anim.setDuration((long) (distance / Math.abs(velocity)));
+ anim.setDuration((long) (Math.abs(distance / velocity)));
return anim;
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
index c8c133774766..7cfe2327f992 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
@@ -57,7 +57,8 @@ import java.util.concurrent.Executor;
import javax.inject.Inject;
-class ImageExporter {
+/** A class to help with exporting screenshot to storage. */
+public class ImageExporter {
private static final String TAG = LogConfig.logTag(ImageExporter.class);
static final Duration PENDING_ENTRY_TTL = Duration.ofHours(24);
@@ -90,7 +91,7 @@ class ImageExporter {
private final FeatureFlags mFlags;
@Inject
- ImageExporter(ContentResolver resolver, FeatureFlags flags) {
+ public ImageExporter(ContentResolver resolver, FeatureFlags flags) {
mResolver = resolver;
mFlags = flags;
}
@@ -148,7 +149,7 @@ class ImageExporter {
*
* @return a listenable future result
*/
- ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap,
+ public ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap,
UserHandle owner) {
return export(executor, requestId, bitmap, ZonedDateTime.now(), owner);
}
@@ -181,13 +182,14 @@ class ImageExporter {
);
}
- static class Result {
- Uri uri;
- UUID requestId;
- String fileName;
- long timestamp;
- CompressFormat format;
- boolean published;
+ /** The result returned by the task exporting screenshots to storage. */
+ public static class Result {
+ public Uri uri;
+ public UUID requestId;
+ public String fileName;
+ public long timestamp;
+ public CompressFormat format;
+ public boolean published;
@Override
public String toString() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 8721d71897f7..557e95c64443 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -419,6 +419,10 @@ public class ScreenshotController {
return;
}
+ mScreenBitmap = screenshot.getBitmap();
+ String oldPackageName = mPackageName;
+ mPackageName = screenshot.getPackageNameString();
+
if (!isUserSetupComplete(Process.myUserHandle())) {
Log.w(TAG, "User setup not complete, displaying toast only");
// User setup isn't complete, so we don't want to show any UI beyond a toast, as editing
@@ -433,10 +437,6 @@ public class ScreenshotController {
mScreenshotTakenInPortrait =
mContext.getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT;
- String oldPackageName = mPackageName;
- mPackageName = screenshot.getPackageNameString();
-
- mScreenBitmap = screenshot.getBitmap();
// Optimizations
mScreenBitmap.setHasAlpha(false);
mScreenBitmap.prepareToDraw();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
index fc94aed5336a..7a62bae5b5ae 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
@@ -93,13 +93,7 @@ public enum ScreenshotEvent implements UiEventLogger.UiEventEnum {
@UiEvent(doc = "User has discarded the result of a long screenshot")
SCREENSHOT_LONG_SCREENSHOT_EXIT(911),
@UiEvent(doc = "A screenshot has been taken and saved to work profile")
- SCREENSHOT_SAVED_TO_WORK_PROFILE(1240),
- @UiEvent(doc = "Notes application triggered the screenshot for notes")
- SCREENSHOT_FOR_NOTE_TRIGGERED(1308),
- @UiEvent(doc = "User accepted the screenshot to be sent to the notes app")
- SCREENSHOT_FOR_NOTE_ACCEPTED(1309),
- @UiEvent(doc = "User cancelled the screenshot for notes app flow")
- SCREENSHOT_FOR_NOTE_CANCELLED(1310);
+ SCREENSHOT_SAVED_TO_WORK_PROFILE(1240);
private final int mId;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/WorkProfileMessageController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/WorkProfileMessageController.kt
index 1b728b8aa9cc..236213cb023f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/WorkProfileMessageController.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/WorkProfileMessageController.kt
@@ -44,7 +44,7 @@ constructor(
/**
* @return a populated WorkProfileFirstRunData object if a work profile first run message should
- * be shown
+ * be shown
*/
fun onScreenshotTaken(userHandle: UserHandle?): WorkProfileFirstRunData? {
if (userHandle == null) return null
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
index 287e8101f86d..33a3125d1c68 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
@@ -19,6 +19,7 @@ package com.android.systemui.settings
import android.content.Context
import android.content.pm.UserInfo
import android.os.UserHandle
+import java.util.concurrent.CountDownLatch
import java.util.concurrent.Executor
/**
@@ -67,14 +68,25 @@ interface UserTracker : UserContentResolverProvider, UserContextProvider {
interface Callback {
/**
+ * Same as {@link onUserChanging(Int, Context, CountDownLatch)} but the latch will be
+ * auto-decremented after the completion of this method.
+ */
+ @JvmDefault
+ fun onUserChanging(newUser: Int, userContext: Context) {}
+
+ /**
* Notifies that the current user is being changed.
* Override this method to run things while the screen is frozen for the user switch.
* Please use {@link #onUserChanged} if the task doesn't need to push the unfreezing of the
* screen further. Please be aware that code executed in this callback will lengthen the
- * user switch duration.
+ * user switch duration. When overriding this method, countDown() MUST be called on the
+ * latch once execution is complete.
*/
@JvmDefault
- fun onUserChanging(newUser: Int, userContext: Context) {}
+ fun onUserChanging(newUser: Int, userContext: Context, latch: CountDownLatch) {
+ onUserChanging(newUser, userContext)
+ latch.countDown()
+ }
/**
* Notifies that the current user has changed.
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
index 9f551c6ebd34..867403689292 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -183,9 +183,22 @@ class UserTrackerImpl internal constructor(
Log.i(TAG, "Switching to user $newUserId")
setUserIdInternal(newUserId)
- notifySubscribers {
- onUserChanging(newUserId, userContext)
- }.await()
+
+ val list = synchronized(callbacks) {
+ callbacks.toList()
+ }
+ val latch = CountDownLatch(list.size)
+ list.forEach {
+ val callback = it.callback.get()
+ if (callback != null) {
+ it.executor.execute {
+ callback.onUserChanging(userId, userContext, latch)
+ }
+ } else {
+ latch.countDown()
+ }
+ }
+ latch.await()
}
@WorkerThread
@@ -225,25 +238,18 @@ class UserTrackerImpl internal constructor(
}
}
- private inline fun notifySubscribers(
- crossinline action: UserTracker.Callback.() -> Unit
- ): CountDownLatch {
+ private inline fun notifySubscribers(crossinline action: UserTracker.Callback.() -> Unit) {
val list = synchronized(callbacks) {
callbacks.toList()
}
- val latch = CountDownLatch(list.size)
list.forEach {
if (it.callback.get() != null) {
it.executor.execute {
it.callback.get()?.action()
- latch.countDown()
}
- } else {
- latch.countDown()
}
}
- return latch
}
override fun dump(pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 8f4433e41c4a..8323d1e6bae3 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -23,6 +23,7 @@ import static android.view.View.VISIBLE;
import static androidx.constraintlayout.widget.ConstraintSet.END;
import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE;
@@ -71,6 +72,7 @@ import android.os.VibrationEffect;
import android.provider.Settings;
import android.transition.ChangeBounds;
import android.transition.Transition;
+import android.transition.TransitionListenerAdapter;
import android.transition.TransitionManager;
import android.transition.TransitionSet;
import android.transition.TransitionValues;
@@ -98,6 +100,7 @@ import android.widget.FrameLayout;
import androidx.constraintlayout.widget.ConstraintSet;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.SystemBarUtils;
@@ -353,6 +356,7 @@ public final class NotificationPanelViewController implements Dumpable {
private final NotificationGutsManager mGutsManager;
private final AlternateBouncerInteractor mAlternateBouncerInteractor;
private final QuickSettingsController mQsController;
+ private final InteractionJankMonitor mInteractionJankMonitor;
private long mDownTime;
private boolean mTouchSlopExceededBeforeDown;
@@ -465,7 +469,7 @@ public final class NotificationPanelViewController implements Dumpable {
private int mPanelAlpha;
private Runnable mPanelAlphaEndAction;
private float mBottomAreaShadeAlpha;
- private final ValueAnimator mBottomAreaShadeAlphaAnimator;
+ final ValueAnimator mBottomAreaShadeAlphaAnimator;
private final AnimatableProperty mPanelAlphaAnimator = AnimatableProperty.from("panelAlpha",
NotificationPanelView::setPanelAlphaInternal,
NotificationPanelView::getCurrentPanelAlpha,
@@ -597,7 +601,6 @@ public final class NotificationPanelViewController implements Dumpable {
private int mLockscreenToDreamingTransitionTranslationY;
private int mGoneToDreamingTransitionTranslationY;
private int mLockscreenToOccludedTransitionTranslationY;
- private boolean mUnocclusionTransitionFlagEnabled = false;
private final Runnable mFlingCollapseRunnable = () -> fling(0, false /* expand */,
mNextCollapseSpeedUpFactor, false /* expandBecauseOfFalsing */);
@@ -643,6 +646,19 @@ public final class NotificationPanelViewController implements Dumpable {
step.getTransitionState() == TransitionState.RUNNING;
};
+ private final TransitionListenerAdapter mKeyguardStatusAlignmentTransitionListener =
+ new TransitionListenerAdapter() {
+ @Override
+ public void onTransitionCancel(Transition transition) {
+ mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION);
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ mInteractionJankMonitor.end(CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION);
+ }
+ };
+
@Inject
public NotificationPanelViewController(NotificationPanelView view,
@Main Handler handler,
@@ -707,6 +723,7 @@ public final class NotificationPanelViewController implements Dumpable {
NotificationStackSizeCalculator notificationStackSizeCalculator,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
ShadeTransitionController shadeTransitionController,
+ InteractionJankMonitor interactionJankMonitor,
SystemClock systemClock,
KeyguardBottomAreaViewModel keyguardBottomAreaViewModel,
KeyguardBottomAreaInteractor keyguardBottomAreaInteractor,
@@ -721,6 +738,7 @@ public final class NotificationPanelViewController implements Dumpable {
DumpManager dumpManager,
KeyguardLongPressViewModel keyguardLongPressViewModel,
KeyguardInteractor keyguardInteractor) {
+ mInteractionJankMonitor = interactionJankMonitor;
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
@Override
public void onKeyguardFadingAwayChanged() {
@@ -886,7 +904,6 @@ public final class NotificationPanelViewController implements Dumpable {
mNotificationPanelUnfoldAnimationController = unfoldComponent.map(
SysUIUnfoldComponent::getNotificationPanelUnfoldAnimationController);
- mUnocclusionTransitionFlagEnabled = featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION);
updateUserSwitcherFlags();
mKeyguardBottomAreaViewModel = keyguardBottomAreaViewModel;
mKeyguardBottomAreaInteractor = keyguardBottomAreaInteractor;
@@ -1045,62 +1062,50 @@ public final class NotificationPanelViewController implements Dumpable {
mNotificationPanelUnfoldAnimationController.ifPresent(controller ->
controller.setup(mNotificationContainerParent));
- if (mUnocclusionTransitionFlagEnabled) {
- // Dreaming->Lockscreen
- collectFlow(mView, mKeyguardTransitionInteractor.getDreamingToLockscreenTransition(),
- mDreamingToLockscreenTransition, mMainDispatcher);
- collectFlow(mView, mDreamingToLockscreenTransitionViewModel.getLockscreenAlpha(),
- setTransitionAlpha(mNotificationStackScrollLayoutController),
- mMainDispatcher);
- collectFlow(mView, mDreamingToLockscreenTransitionViewModel.lockscreenTranslationY(
- mDreamingToLockscreenTransitionTranslationY),
- setTransitionY(mNotificationStackScrollLayoutController),
- mMainDispatcher);
-
- // Occluded->Lockscreen
- collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(),
- mOccludedToLockscreenTransition, mMainDispatcher);
- collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(),
- setTransitionAlpha(mNotificationStackScrollLayoutController),
- mMainDispatcher);
- collectFlow(mView, mOccludedToLockscreenTransitionViewModel.lockscreenTranslationY(
- mOccludedToLockscreenTransitionTranslationY),
- setTransitionY(mNotificationStackScrollLayoutController),
- mMainDispatcher);
-
- // Lockscreen->Dreaming
- collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToDreamingTransition(),
- mLockscreenToDreamingTransition, mMainDispatcher);
- collectFlow(mView, mLockscreenToDreamingTransitionViewModel.getLockscreenAlpha(),
- setTransitionAlpha(mNotificationStackScrollLayoutController),
- mMainDispatcher);
- collectFlow(mView, mLockscreenToDreamingTransitionViewModel.lockscreenTranslationY(
- mLockscreenToDreamingTransitionTranslationY),
- setTransitionY(mNotificationStackScrollLayoutController),
- mMainDispatcher);
-
- // Gone->Dreaming
- collectFlow(mView, mKeyguardTransitionInteractor.getGoneToDreamingTransition(),
- mGoneToDreamingTransition, mMainDispatcher);
- collectFlow(mView, mGoneToDreamingTransitionViewModel.getLockscreenAlpha(),
- setTransitionAlpha(mNotificationStackScrollLayoutController),
- mMainDispatcher);
- collectFlow(mView, mGoneToDreamingTransitionViewModel.lockscreenTranslationY(
- mGoneToDreamingTransitionTranslationY),
- setTransitionY(mNotificationStackScrollLayoutController),
- mMainDispatcher);
-
- // Lockscreen->Occluded
- collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToOccludedTransition(),
- mLockscreenToOccludedTransition, mMainDispatcher);
- collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha(),
- setTransitionAlpha(mNotificationStackScrollLayoutController),
- mMainDispatcher);
- collectFlow(mView, mLockscreenToOccludedTransitionViewModel.lockscreenTranslationY(
- mLockscreenToOccludedTransitionTranslationY),
- setTransitionY(mNotificationStackScrollLayoutController),
- mMainDispatcher);
- }
+ // Dreaming->Lockscreen
+ collectFlow(mView, mKeyguardTransitionInteractor.getDreamingToLockscreenTransition(),
+ mDreamingToLockscreenTransition, mMainDispatcher);
+ collectFlow(mView, mDreamingToLockscreenTransitionViewModel.getLockscreenAlpha(),
+ setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+ collectFlow(mView, mDreamingToLockscreenTransitionViewModel.lockscreenTranslationY(
+ mDreamingToLockscreenTransitionTranslationY),
+ setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
+
+ // Occluded->Lockscreen
+ collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(),
+ mOccludedToLockscreenTransition, mMainDispatcher);
+ collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(),
+ setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+ collectFlow(mView, mOccludedToLockscreenTransitionViewModel.lockscreenTranslationY(
+ mOccludedToLockscreenTransitionTranslationY),
+ setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
+
+ // Lockscreen->Dreaming
+ collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToDreamingTransition(),
+ mLockscreenToDreamingTransition, mMainDispatcher);
+ collectFlow(mView, mLockscreenToDreamingTransitionViewModel.getLockscreenAlpha(),
+ setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+ collectFlow(mView, mLockscreenToDreamingTransitionViewModel.lockscreenTranslationY(
+ mLockscreenToDreamingTransitionTranslationY),
+ setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
+
+ // Gone->Dreaming
+ collectFlow(mView, mKeyguardTransitionInteractor.getGoneToDreamingTransition(),
+ mGoneToDreamingTransition, mMainDispatcher);
+ collectFlow(mView, mGoneToDreamingTransitionViewModel.getLockscreenAlpha(),
+ setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+ collectFlow(mView, mGoneToDreamingTransitionViewModel.lockscreenTranslationY(
+ mGoneToDreamingTransitionTranslationY),
+ setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
+
+ // Lockscreen->Occluded
+ collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToOccludedTransition(),
+ mLockscreenToOccludedTransition, mMainDispatcher);
+ collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha(),
+ setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+ collectFlow(mView, mLockscreenToOccludedTransitionViewModel.lockscreenTranslationY(
+ mLockscreenToOccludedTransitionTranslationY),
+ setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
}
@VisibleForTesting
@@ -1554,6 +1559,7 @@ public final class NotificationPanelViewController implements Dumpable {
int statusConstraint = shouldBeCentered ? PARENT_ID : R.id.qs_edge_guideline;
constraintSet.connect(R.id.keyguard_status_view, END, statusConstraint, END);
if (animate) {
+ mInteractionJankMonitor.begin(mView, CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION);
ChangeBounds transition = new ChangeBounds();
if (mSplitShadeEnabled) {
// Excluding media from the transition on split-shade, as it doesn't transition
@@ -1577,6 +1583,7 @@ public final class NotificationPanelViewController implements Dumpable {
// The clock container can sometimes be null. If it is, just fall back to the
// old animation rather than setting up the custom animations.
if (clockContainerView == null || clockContainerView.getChildCount() == 0) {
+ transition.addListener(mKeyguardStatusAlignmentTransitionListener);
TransitionManager.beginDelayedTransition(
mNotificationContainerParent, transition);
} else {
@@ -1595,10 +1602,11 @@ public final class NotificationPanelViewController implements Dumpable {
adapter.setDuration(KEYGUARD_STATUS_VIEW_CUSTOM_CLOCK_MOVE_DURATION);
adapter.addTarget(clockView);
set.addTransition(adapter);
-
+ set.addListener(mKeyguardStatusAlignmentTransitionListener);
TransitionManager.beginDelayedTransition(mNotificationContainerParent, set);
}
} else {
+ transition.addListener(mKeyguardStatusAlignmentTransitionListener);
TransitionManager.beginDelayedTransition(
mNotificationContainerParent, transition);
}
@@ -2480,9 +2488,6 @@ public final class NotificationPanelViewController implements Dumpable {
}
private void onExpandingFinished() {
- if (!mUnocclusionTransitionFlagEnabled) {
- mScrimController.onExpandingFinished();
- }
mNotificationStackScrollLayoutController.onExpansionStopped();
mHeadsUpManager.onExpandingFinished();
mConversationNotificationManager.onNotificationPanelExpandStateChanged(isFullyCollapsed());
@@ -4645,8 +4650,13 @@ public final class NotificationPanelViewController implements Dumpable {
gesture possible. */
int pointerIndex = event.findPointerIndex(mTrackingPointer);
if (pointerIndex < 0) {
- pointerIndex = 0;
- mTrackingPointer = event.getPointerId(pointerIndex);
+ if (mTrackingPointer < 0) {
+ pointerIndex = 0;
+ mTrackingPointer = event.getPointerId(pointerIndex);
+ } else {
+ mShadeLog.logMotionEvent(event, "Skipping intercept of multitouch pointer");
+ return false;
+ }
}
final float x = event.getX(pointerIndex);
final float y = event.getY(pointerIndex);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 60fa865b83bc..c130b3913b64 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -38,8 +38,6 @@ import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dock.DockManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
@@ -47,6 +45,7 @@ import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.binder.KeyguardBouncerViewBinder;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationInsetsController;
@@ -132,11 +131,11 @@ public class NotificationShadeWindowViewController {
NotificationInsetsController notificationInsetsController,
AmbientState ambientState,
PulsingGestureListener pulsingGestureListener,
- FeatureFlags featureFlags,
KeyguardBouncerViewModel keyguardBouncerViewModel,
KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory,
AlternateBouncerInteractor alternateBouncerInteractor,
- KeyguardTransitionInteractor keyguardTransitionInteractor
+ KeyguardTransitionInteractor keyguardTransitionInteractor,
+ PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel
) {
mLockscreenShadeTransitionController = transitionController;
mFalsingCollector = falsingCollector;
@@ -163,12 +162,11 @@ public class NotificationShadeWindowViewController {
KeyguardBouncerViewBinder.bind(
mView.findViewById(R.id.keyguard_bouncer_container),
keyguardBouncerViewModel,
+ primaryBouncerToGoneTransitionViewModel,
keyguardBouncerComponentFactory);
- if (featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION)) {
- collectFlow(mView, keyguardTransitionInteractor.getLockscreenToDreamingTransition(),
- mLockscreenToDreamingTransition);
- }
+ collectFlow(mView, keyguardTransitionInteractor.getLockscreenToDreamingTransition(),
+ mLockscreenToDreamingTransition);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
index a1767cc5888d..f4b1cc5f71be 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
@@ -107,7 +107,7 @@ class ShadeExpansionStateManager @Inject constructor() : ShadeStateEvents {
*
* @param fraction the fraction from the expansion in [0, 1]
* @param expanded whether the panel is currently expanded; this is independent from the
- * fraction as the panel also might be expanded if the fraction is 0.
+ * fraction as the panel also might be expanded if the fraction is 0.
* @param tracking whether we're currently tracking the user's gesture.
*/
fun onPanelExpansionChanged(
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
index 37773e952875..b79f32a6eae1 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -70,9 +70,9 @@ import javax.inject.Named
*
* [header] is a [MotionLayout] that has two transitions:
* * [HEADER_TRANSITION_ID]: [QQS_HEADER_CONSTRAINT] <-> [QS_HEADER_CONSTRAINT] for portrait
- * handheld device configuration.
+ * handheld device configuration.
* * [LARGE_SCREEN_HEADER_TRANSITION_ID]: [LARGE_SCREEN_HEADER_CONSTRAINT] for all other
- * configurations
+ * configurations
*/
@CentralSurfacesScope
class ShadeHeaderController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt
index 62c225ba0b4e..df8c6abfff97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt
@@ -148,7 +148,8 @@ constructor(
qsDragFraction: $qsTransitionFraction
qsSquishFraction: $qsSquishTransitionFraction
isTransitioningToFullShade: $isTransitioningToFullShade
- """.trimIndent()
+ """
+ .trimIndent()
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index f0d064b42d9c..9a9503c8cd9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -572,8 +572,7 @@ class LockscreenShadeTransitionController @Inject constructor(
entry.setGroupExpansionChanging(true)
userId = entry.sbn.userId
}
- var fullShadeNeedsBouncer = (!lockScreenUserManager.userAllowsPrivateNotificationsInPublic(
- lockScreenUserManager.getCurrentUserId()) ||
+ var fullShadeNeedsBouncer = (
!lockScreenUserManager.shouldShowLockscreenNotifications() ||
falsingCollector.shouldEnforceBouncer())
if (keyguardBypassController.bypassEnabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index f4cd985adbdb..51c5183ffee9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -213,7 +213,8 @@ public class NotificationLockscreenUserManagerImpl implements
DeviceProvisionedController deviceProvisionedController,
KeyguardStateController keyguardStateController,
SecureSettings secureSettings,
- DumpManager dumpManager) {
+ DumpManager dumpManager,
+ LockPatternUtils lockPatternUtils) {
mContext = context;
mMainHandler = mainHandler;
mDevicePolicyManager = devicePolicyManager;
@@ -225,7 +226,7 @@ public class NotificationLockscreenUserManagerImpl implements
mClickNotifier = clickNotifier;
mOverviewProxyServiceLazy = overviewProxyServiceLazy;
statusBarStateController.addCallback(this);
- mLockPatternUtils = new LockPatternUtils(context);
+ mLockPatternUtils = lockPatternUtils;
mKeyguardManager = keyguardManager;
mBroadcastDispatcher = broadcastDispatcher;
mDeviceProvisionedController = deviceProvisionedController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index c35c5c522798..77550038c94a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -93,6 +93,16 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
@IntDef({STATE_ICON, STATE_DOT, STATE_HIDDEN})
public @interface VisibleState { }
+ /** Returns a human-readable string of {@link VisibleState}. */
+ public static String getVisibleStateString(@VisibleState int state) {
+ switch(state) {
+ case STATE_ICON: return "ICON";
+ case STATE_DOT: return "DOT";
+ case STATE_HIDDEN: return "HIDDEN";
+ default: return "UNKNOWN";
+ }
+ }
+
private static final String TAG = "StatusBarIconView";
private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT
= new FloatProperty<StatusBarIconView>("iconAppearAmount") {
@@ -561,7 +571,8 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
@Override
public String toString() {
return "StatusBarIconView("
- + "slot='" + mSlot + " alpha=" + getAlpha() + " icon=" + mIcon
+ + "slot='" + mSlot + "' alpha=" + getAlpha() + " icon=" + mIcon
+ + " visibleState=" + getVisibleStateString(getVisibleState())
+ " iconColor=#" + Integer.toHexString(mIconColor)
+ " notification=" + mNotification + ')';
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt
index 42b874fd7156..7297ae689224 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt
@@ -74,7 +74,7 @@ constructor(
/**
* @return a context with the MCC/MNC [Configuration] values corresponding to this
- * subscriptionId
+ * subscriptionId
*/
fun getMobileContextForSub(subId: Int, context: Context): Context {
if (demoModeController.isInDemoMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt
index 64b7ac9ee0a1..5fa83ef5d454 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt
@@ -39,6 +39,7 @@ import javax.inject.Inject
* - Simple prioritization: Privacy > Battery > connectivity (encoded in [StatusEvent])
* - Only schedules a single event, and throws away lowest priority events
* ```
+ *
* There are 4 basic stages of animation at play here:
* ```
* 1. System chrome animation OUT
@@ -46,6 +47,7 @@ import javax.inject.Inject
* 3. Chip animation OUT; potentially into a dot
* 4. System chrome animation IN
* ```
+ *
* Thus we can keep all animations synchronized with two separate ValueAnimators, one for system
* chrome and the other for the chip. These can animate from 0,1 and listeners can parameterize
* their respective views based on the progress of the animator. Interpolation differences TBD
@@ -168,7 +170,7 @@ constructor(
* 3. Update the scheduler state so that clients know where we are
* 4. Maybe: provide scaffolding such as: dot location, margins, etc
* 5. Maybe: define a maximum animation length and enforce it. Probably only doable if we
- * collect all of the animators and run them together.
+ * collect all of the animators and run them together.
*/
private fun runChipAnimation() {
statusBarWindowController.setForceStatusBarVisible(true)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 29510d00a8d4..b0ad6a1ffbd8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -333,9 +333,9 @@ constructor(
}
val ssView = plugin.getView(parent)
+ configPlugin?.let { ssView.registerConfigProvider(it) }
ssView.setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
ssView.registerDataProvider(plugin)
- configPlugin?.let { ssView.registerConfigProvider(it) }
ssView.setIntentStarter(object : BcSmartspaceDataPlugin.IntentStarter {
override fun startIntent(view: View, intent: Intent, showOnLockscreen: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index 0a5e9867a17f..11582d7e3cc8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -29,7 +29,6 @@ import android.app.AppGlobals;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.app.SynchronousUserSwitchObserver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -52,7 +51,9 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.CoreStartable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.NotificationChannels;
@@ -73,6 +74,8 @@ public class InstantAppNotifier
private final Context mContext;
private final Handler mHandler = new Handler();
+ private final UserTracker mUserTracker;
+ private final Executor mMainExecutor;
private final Executor mUiBgExecutor;
private final ArraySet<Pair<String, Integer>> mCurrentNotifs = new ArraySet<>();
private final CommandQueue mCommandQueue;
@@ -82,10 +85,14 @@ public class InstantAppNotifier
public InstantAppNotifier(
Context context,
CommandQueue commandQueue,
+ UserTracker userTracker,
+ @Main Executor mainExecutor,
@UiBackground Executor uiBgExecutor,
KeyguardStateController keyguardStateController) {
mContext = context;
mCommandQueue = commandQueue;
+ mUserTracker = userTracker;
+ mMainExecutor = mainExecutor;
mUiBgExecutor = uiBgExecutor;
mKeyguardStateController = keyguardStateController;
}
@@ -93,11 +100,7 @@ public class InstantAppNotifier
@Override
public void start() {
// listen for user / profile change.
- try {
- ActivityManager.getService().registerUserSwitchObserver(mUserSwitchListener, TAG);
- } catch (RemoteException e) {
- // Ignore
- }
+ mUserTracker.addCallback(mUserSwitchListener, mMainExecutor);
mCommandQueue.addCallback(this);
mKeyguardStateController.addCallback(this);
@@ -129,13 +132,10 @@ public class InstantAppNotifier
updateForegroundInstantApps();
}
- private final SynchronousUserSwitchObserver mUserSwitchListener =
- new SynchronousUserSwitchObserver() {
- @Override
- public void onUserSwitching(int newUserId) throws RemoteException {}
-
+ private final UserTracker.Callback mUserSwitchListener =
+ new UserTracker.Callback() {
@Override
- public void onUserSwitchComplete(int newUserId) throws RemoteException {
+ public void onUserChanged(int newUser, Context userContext) {
mHandler.post(
() -> {
updateForegroundInstantApps();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 7e53d5431353..8874f59d6c17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification
import android.animation.ObjectAnimator
import android.util.FloatProperty
+import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
@@ -302,29 +303,29 @@ class NotificationWakeUpCoordinator @Inject constructor(
// the doze amount to 0f (not dozing) so that the notifications are no longer hidden.
// See: UnlockedScreenOffAnimationController.onFinishedWakingUp()
setDozeAmount(0f, 0f, source = "Override: Shade->Shade (lock cancelled by unlock)")
+ this.state = newState
+ return
}
if (overrideDozeAmountIfAnimatingScreenOff(mLinearDozeAmount)) {
+ this.state = newState
return
}
if (overrideDozeAmountIfBypass()) {
+ this.state = newState
return
}
maybeClearDozeAmountOverrideHidingNotifs()
- if (bypassController.bypassEnabled &&
- newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED &&
- (!statusBarStateController.isDozing || shouldAnimateVisibility())) {
- // We're leaving shade locked. Let's animate the notifications away
- setNotificationsVisible(visible = true, increaseSpeed = false, animate = false)
- setNotificationsVisible(visible = false, increaseSpeed = false, animate = true)
- }
-
this.state = newState
}
+ @VisibleForTesting
+ val statusBarState: Int
+ get() = state
+
override fun onPanelExpansionChanged(event: ShadeExpansionChangeEvent) {
val collapsedEnough = event.fraction <= 0.9f
if (collapsedEnough != this.collapsedEnoughToHide) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
index 44645315ca80..88d9ffcdcf3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
@@ -13,7 +13,7 @@
package com.android.systemui.statusbar.notification
-import com.android.systemui.log.dagger.NotificationLog
+import com.android.systemui.log.dagger.NotificationLockscreenLog
import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.plugins.log.LogLevel.DEBUG
import com.android.systemui.statusbar.StatusBarState
@@ -21,7 +21,12 @@ import javax.inject.Inject
class NotificationWakeUpCoordinatorLogger
@Inject
-constructor(@NotificationLog private val buffer: LogBuffer) {
+constructor(@NotificationLockscreenLog private val buffer: LogBuffer) {
+ private var lastSetDozeAmountLogWasFractional = false
+ private var lastSetDozeAmountLogState = -1
+ private var lastSetDozeAmountLogSource = "undefined"
+ private var lastOnDozeAmountChangedLogWasFractional = false
+
fun logSetDozeAmount(
linear: Float,
eased: Float,
@@ -29,6 +34,20 @@ constructor(@NotificationLog private val buffer: LogBuffer) {
state: Int,
changed: Boolean,
) {
+ // Avoid logging on every frame of the animation if important values are not changing
+ val isFractional = linear != 1f && linear != 0f
+ if (
+ lastSetDozeAmountLogWasFractional &&
+ isFractional &&
+ lastSetDozeAmountLogState == state &&
+ lastSetDozeAmountLogSource == source
+ ) {
+ return
+ }
+ lastSetDozeAmountLogWasFractional = isFractional
+ lastSetDozeAmountLogState = state
+ lastSetDozeAmountLogSource = source
+
buffer.log(
TAG,
DEBUG,
@@ -66,6 +85,10 @@ constructor(@NotificationLog private val buffer: LogBuffer) {
}
fun logOnDozeAmountChanged(linear: Float, eased: Float) {
+ // Avoid logging on every frame of the animation when values are fractional
+ val isFractional = linear != 1f && linear != 0f
+ if (lastOnDozeAmountChangedLogWasFractional && isFractional) return
+ lastOnDozeAmountChangedLogWasFractional = isFractional
buffer.log(
TAG,
DEBUG,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt
index a35617c88caf..6deef2e11828 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt
@@ -315,6 +315,7 @@ interface Roundable {
/**
* State object for a `Roundable` class.
+ *
* @param targetView Will handle the [AnimatableProperty]
* @param roundable Target of the radius animation
* @param maxRadius Max corner radius in pixels
@@ -436,7 +437,6 @@ interface SourceType {
* This is the most convenient way to define a new [SourceType].
*
* For example:
- *
* ```kotlin
* private val SECTION = SourceType.from("Section")
* ```
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 64c1a595483e..bbabde3f444e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -191,7 +191,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private int mMaxSmallHeightBeforeS;
private int mMaxSmallHeight;
private int mMaxSmallHeightLarge;
- private int mMaxSmallHeightMedia;
private int mMaxExpandedHeight;
private int mIncreasedPaddingBetweenElements;
private int mNotificationLaunchHeight;
@@ -1771,8 +1770,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
R.dimen.notification_min_height);
mMaxSmallHeightLarge = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_min_height_increased);
- mMaxSmallHeightMedia = NotificationUtils.getFontScaledHeight(mContext,
- R.dimen.notification_min_height_media);
mMaxExpandedHeight = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_max_height);
mMaxHeadsUpHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 39e4000c5d05..4522e41daf91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -443,6 +443,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
CancellationSignal cancellationSignal = new CancellationSignal();
cancellationSignal.setOnCancelListener(
() -> runningInflations.values().forEach(CancellationSignal::cancel));
+
return cancellationSignal;
}
@@ -783,6 +784,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
public static class AsyncInflationTask extends AsyncTask<Void, Void, InflationProgress>
implements InflationCallback, InflationTask {
+ private static final long IMG_PRELOAD_TIMEOUT_MS = 1000L;
private final NotificationEntry mEntry;
private final Context mContext;
private final boolean mInflateSynchronously;
@@ -876,7 +878,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
recoveredBuilder, mIsLowPriority, mUsesIncreasedHeight,
mUsesIncreasedHeadsUpHeight, packageContext);
InflatedSmartReplyState previousSmartReplyState = mRow.getExistingSmartReplyState();
- return inflateSmartReplyViews(
+ InflationProgress result = inflateSmartReplyViews(
inflationProgress,
mReInflateFlags,
mEntry,
@@ -884,6 +886,11 @@ public class NotificationContentInflater implements NotificationRowContentBinder
packageContext,
previousSmartReplyState,
mSmartRepliesInflater);
+
+ // wait for image resolver to finish preloading
+ mRow.getImageResolver().waitForPreloadedImages(IMG_PRELOAD_TIMEOUT_MS);
+
+ return result;
} catch (Exception e) {
mError = e;
return null;
@@ -918,6 +925,9 @@ public class NotificationContentInflater implements NotificationRowContentBinder
mCallback.handleInflationException(mRow.getEntry(),
new InflationException("Couldn't inflate contentViews" + e));
}
+
+ // Cancel any image loading tasks, not useful any more
+ mRow.getImageResolver().cancelRunningTasks();
}
@Override
@@ -944,6 +954,9 @@ public class NotificationContentInflater implements NotificationRowContentBinder
// Notify the resolver that the inflation task has finished,
// try to purge unnecessary cached entries.
mRow.getImageResolver().purgeCache();
+
+ // Cancel any image loading tasks that have not completed at this point
+ mRow.getImageResolver().cancelRunningTasks();
}
private static class RtlEnabledContext extends ContextWrapper {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
index 41eeada0fcda..fe0b3123eb25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
@@ -22,8 +22,11 @@ import android.os.AsyncTask;
import android.util.Log;
import java.util.Set;
+import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* A cache for inline images of image messages.
@@ -56,12 +59,13 @@ public class NotificationInlineImageCache implements NotificationInlineImageReso
}
@Override
- public Drawable get(Uri uri) {
+ public Drawable get(Uri uri, long timeoutMs) {
Drawable result = null;
try {
- result = mCache.get(uri).get();
- } catch (InterruptedException | ExecutionException ex) {
- Log.d(TAG, "get: Failed get image from " + uri);
+ result = mCache.get(uri).get(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException | ExecutionException
+ | TimeoutException | CancellationException ex) {
+ Log.d(TAG, "get: Failed get image from " + uri + " " + ex);
}
return result;
}
@@ -72,6 +76,15 @@ public class NotificationInlineImageCache implements NotificationInlineImageReso
mCache.entrySet().removeIf(entry -> !wantedSet.contains(entry.getKey()));
}
+ @Override
+ public void cancelRunningTasks() {
+ mCache.forEach((key, value) -> {
+ if (value.getStatus() != AsyncTask.Status.FINISHED) {
+ value.cancel(true);
+ }
+ });
+ }
+
private static class PreloadImageTask extends AsyncTask<Uri, Void, Drawable> {
private final NotificationInlineImageResolver mResolver;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
index b05e64ab1991..c620f448b3b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
@@ -23,6 +23,7 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
+import android.os.SystemClock;
import android.util.Log;
import com.android.internal.R;
@@ -45,6 +46,9 @@ import java.util.Set;
public class NotificationInlineImageResolver implements ImageResolver {
private static final String TAG = NotificationInlineImageResolver.class.getSimpleName();
+ // Timeout for loading images from ImageCache when calling from UI thread
+ private static final long MAX_UI_THREAD_TIMEOUT_MS = 100L;
+
private final Context mContext;
private final ImageCache mImageCache;
private Set<Uri> mWantedUriSet;
@@ -123,17 +127,25 @@ public class NotificationInlineImageResolver implements ImageResolver {
return null;
}
+ /**
+ * Loads an image from the Uri.
+ * This method is synchronous and is usually called from the Main thread.
+ * It will time-out after MAX_UI_THREAD_TIMEOUT_MS.
+ *
+ * @param uri Uri of the target image.
+ * @return drawable of the image, null if loading failed/timeout
+ */
@Override
public Drawable loadImage(Uri uri) {
- return hasCache() ? loadImageFromCache(uri) : resolveImage(uri);
+ return hasCache() ? loadImageFromCache(uri, MAX_UI_THREAD_TIMEOUT_MS) : resolveImage(uri);
}
- private Drawable loadImageFromCache(Uri uri) {
+ private Drawable loadImageFromCache(Uri uri, long timeoutMs) {
// if the uri isn't currently cached, try caching it first
if (!mImageCache.hasEntry(uri)) {
mImageCache.preload((uri));
}
- return mImageCache.get(uri);
+ return mImageCache.get(uri, timeoutMs);
}
/**
@@ -208,6 +220,30 @@ public class NotificationInlineImageResolver implements ImageResolver {
}
/**
+ * Wait for a maximum timeout for images to finish preloading
+ * @param timeoutMs total timeout time
+ */
+ void waitForPreloadedImages(long timeoutMs) {
+ if (!hasCache()) {
+ return;
+ }
+ Set<Uri> preloadedUris = getWantedUriSet();
+ if (preloadedUris != null) {
+ // Decrement remaining timeout after each image check
+ long endTimeMs = SystemClock.elapsedRealtime() + timeoutMs;
+ preloadedUris.forEach(
+ uri -> loadImageFromCache(uri, endTimeMs - SystemClock.elapsedRealtime()));
+ }
+ }
+
+ void cancelRunningTasks() {
+ if (!hasCache()) {
+ return;
+ }
+ mImageCache.cancelRunningTasks();
+ }
+
+ /**
* A interface for internal cache implementation of this resolver.
*/
interface ImageCache {
@@ -216,7 +252,7 @@ public class NotificationInlineImageResolver implements ImageResolver {
* @param uri The uri of the image.
* @return Drawable of the image.
*/
- Drawable get(Uri uri);
+ Drawable get(Uri uri, long timeoutMs);
/**
* Set the image resolver that actually resolves image from specified uri.
@@ -241,6 +277,11 @@ public class NotificationInlineImageResolver implements ImageResolver {
* Purge unnecessary entries in the cache.
*/
void purge();
+
+ /**
+ * Cancel all unfinished image loading tasks
+ */
+ void cancelRunningTasks();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index d2087ba6ca1c..977e1bb31049 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -67,6 +67,7 @@ import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
+import android.view.WindowInsetsAnimation;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AnimationUtils;
@@ -199,6 +200,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private final boolean mDebugRemoveAnimation;
private final boolean mSimplifiedAppearFraction;
private final boolean mUseRoundnessSourceTypes;
+ private boolean mAnimatedInsets;
private int mContentHeight;
private float mIntrinsicContentHeight;
@@ -207,7 +209,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private int mTopPadding;
private boolean mAnimateNextTopPaddingChange;
private int mBottomPadding;
- private int mBottomInset = 0;
+ @VisibleForTesting
+ int mBottomInset = 0;
private float mQsExpansionFraction;
private final int mSplitShadeMinContentHeight;
@@ -388,9 +391,33 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
}
};
+
private boolean mPulsing;
private boolean mScrollable;
private View mForcedScroll;
+ private boolean mIsInsetAnimationRunning;
+
+ private final WindowInsetsAnimation.Callback mInsetsCallback =
+ new WindowInsetsAnimation.Callback(
+ WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE) {
+
+ @Override
+ public void onPrepare(WindowInsetsAnimation animation) {
+ mIsInsetAnimationRunning = true;
+ }
+
+ @Override
+ public WindowInsets onProgress(WindowInsets windowInsets,
+ List<WindowInsetsAnimation> list) {
+ updateBottomInset(windowInsets);
+ return windowInsets;
+ }
+
+ @Override
+ public void onEnd(WindowInsetsAnimation animation) {
+ mIsInsetAnimationRunning = false;
+ }
+ };
/**
* @see #setHideAmount(float, float)
@@ -584,6 +611,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mDebugRemoveAnimation = featureFlags.isEnabled(Flags.NSSL_DEBUG_REMOVE_ANIMATION);
mSimplifiedAppearFraction = featureFlags.isEnabled(Flags.SIMPLIFIED_APPEAR_FRACTION);
mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
+ setAnimatedInsetsEnabled(featureFlags.isEnabled(Flags.ANIMATED_NOTIFICATION_SHADE_INSETS));
mSectionsManager = Dependency.get(NotificationSectionsManager.class);
mScreenOffAnimationController =
Dependency.get(ScreenOffAnimationController.class);
@@ -622,6 +650,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mGroupMembershipManager = Dependency.get(GroupMembershipManager.class);
mGroupExpansionManager = Dependency.get(GroupExpansionManager.class);
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+ if (mAnimatedInsets) {
+ setWindowInsetsAnimationCallback(mInsetsCallback);
+ }
}
/**
@@ -690,6 +721,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@VisibleForTesting
+ void setAnimatedInsetsEnabled(boolean enabled) {
+ mAnimatedInsets = enabled;
+ }
+
+ @VisibleForTesting
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateFooter() {
if (mFooterView == null) {
@@ -1781,7 +1817,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
return;
}
mForcedScroll = v;
- scrollTo(v);
+ if (mAnimatedInsets) {
+ updateForcedScroll();
+ } else {
+ scrollTo(v);
+ }
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -1813,26 +1853,46 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
+ ((!isExpanded() && isPinnedHeadsUp(v)) ? mHeadsUpInset : getTopPadding());
}
+ private void updateBottomInset(WindowInsets windowInsets) {
+ mBottomInset = windowInsets.getInsets(WindowInsets.Type.ime()).bottom;
+
+ if (mForcedScroll != null) {
+ updateForcedScroll();
+ }
+
+ int range = getScrollRange();
+ if (mOwnScrollY > range) {
+ setOwnScrollY(range);
+ }
+ }
+
@Override
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- mBottomInset = insets.getInsets(WindowInsets.Type.ime()).bottom;
+ if (!mAnimatedInsets) {
+ mBottomInset = insets.getInsets(WindowInsets.Type.ime()).bottom;
+ }
mWaterfallTopInset = 0;
final DisplayCutout cutout = insets.getDisplayCutout();
if (cutout != null) {
mWaterfallTopInset = cutout.getWaterfallInsets().top;
}
-
- int range = getScrollRange();
- if (mOwnScrollY > range) {
- // HACK: We're repeatedly getting staggered insets here while the IME is
- // animating away. To work around that we'll wait until things have settled.
- removeCallbacks(mReclamp);
- postDelayed(mReclamp, 50);
- } else if (mForcedScroll != null) {
- // The scroll was requested before we got the actual inset - in case we need
- // to scroll up some more do so now.
- scrollTo(mForcedScroll);
+ if (mAnimatedInsets && !mIsInsetAnimationRunning) {
+ // update bottom inset e.g. after rotation
+ updateBottomInset(insets);
+ }
+ if (!mAnimatedInsets) {
+ int range = getScrollRange();
+ if (mOwnScrollY > range) {
+ // HACK: We're repeatedly getting staggered insets here while the IME is
+ // animating away. To work around that we'll wait until things have settled.
+ removeCallbacks(mReclamp);
+ postDelayed(mReclamp, 50);
+ } else if (mForcedScroll != null) {
+ // The scroll was requested before we got the actual inset - in case we need
+ // to scroll up some more do so now.
+ scrollTo(mForcedScroll);
+ }
}
return insets;
}
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 42d122d6f9ac..14b0763580e9 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
@@ -209,7 +209,11 @@ public class NotificationStackScrollLayoutController {
public void onViewAttachedToWindow(View v) {
mConfigurationController.addCallback(mConfigurationListener);
mZenModeController.addCallback(mZenModeControllerCallback);
- mBarState = mStatusBarStateController.getState();
+ final int newBarState = mStatusBarStateController.getState();
+ if (newBarState != mBarState) {
+ mStateListener.onStateChanged(newBarState);
+ mStateListener.onStatePostChange();
+ }
mStatusBarStateController.addCallback(
mStateListener, SysuiStatusBarStateController.RANK_STACK_SCROLLER);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index aaf9300e7cc8..c6f56d482d43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -251,13 +251,13 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
|| (isFastNonDismissGesture && isAbleToShowMenu);
int menuSnapTarget = menuRow.getMenuSnapTarget();
boolean isNonFalseMenuRevealingGesture =
- !isFalseGesture() && isMenuRevealingGestureAwayFromMenu;
+ isMenuRevealingGestureAwayFromMenu && !isFalseGesture();
if ((isNonDismissGestureTowardsMenu || isNonFalseMenuRevealingGesture)
&& menuSnapTarget != 0) {
// Menu has not been snapped to previously and this is menu revealing gesture
snapOpen(animView, menuSnapTarget, velocity);
menuRow.onSnapOpen();
- } else if (isDismissGesture(ev) && !gestureTowardsMenu) {
+ } else if (isDismissGesture && !gestureTowardsMenu) {
dismiss(animView, velocity);
menuRow.onDismiss();
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt
index 548d1a135948..8b6d6a4f3170 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt
@@ -25,9 +25,10 @@ constructor(
/**
* This method looks for views that can be rounded (and implement [Roundable]) during a
* notification swipe.
+ *
* @return The [Roundable] targets above/below the [viewSwiped] (if available). The
- * [RoundableTargets.before] and [RoundableTargets.after] parameters can be `null` if there is
- * no above/below notification or the notification is not part of the same section.
+ * [RoundableTargets.before] and [RoundableTargets.after] parameters can be `null` if there is
+ * no above/below notification or the notification is not part of the same section.
*/
fun findRoundableTargets(
viewSwiped: ExpandableNotificationRow,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 576df7ac7add..f6d53b3bc9b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -31,7 +31,7 @@ import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.AutoAddTracker;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.ReduceBrightColorsController;
import com.android.systemui.qs.SettingObserver;
import com.android.systemui.qs.external.CustomTile;
@@ -75,7 +75,7 @@ public class AutoTileManager implements UserAwareController {
private final String mSafetySpec;
protected final Context mContext;
- protected final QSTileHost mHost;
+ protected final QSHost mHost;
protected final Handler mHandler;
protected final SecureSettings mSecureSettings;
protected final AutoAddTracker mAutoTracker;
@@ -92,7 +92,7 @@ public class AutoTileManager implements UserAwareController {
private final ArrayList<AutoAddSetting> mAutoAddSettingList = new ArrayList<>();
public AutoTileManager(Context context, AutoAddTracker.Builder autoAddTrackerBuilder,
- QSTileHost host,
+ QSHost host,
@Background Handler handler,
SecureSettings secureSettings,
HotspotController hotspotController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index db2c0a08c1d9..573347cb1aff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -383,10 +383,24 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
}
@Override
+ public void onBiometricDetected(int userId, BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) {
+ Trace.beginSection("BiometricUnlockController#onBiometricDetected");
+ if (mUpdateMonitor.isGoingToSleep()) {
+ Trace.endSection();
+ return;
+ }
+ startWakeAndUnlock(MODE_SHOW_BOUNCER);
+ }
+
+ @Override
public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
boolean isStrongBiometric) {
Trace.beginSection("BiometricUnlockController#onBiometricAuthenticated");
if (mUpdateMonitor.isGoingToSleep()) {
+ mLogger.deferringAuthenticationDueToSleep(userId,
+ biometricSourceType,
+ mPendingAuthenticated != null);
mPendingAuthenticated = new PendingAuthenticated(userId, biometricSourceType,
isStrongBiometric);
Trace.endSection();
@@ -802,6 +816,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
public void onFinishedGoingToSleep() {
Trace.beginSection("BiometricUnlockController#onFinishedGoingToSleep");
if (mPendingAuthenticated != null) {
+ mLogger.finishedGoingToSleepWithPendingAuth();
PendingAuthenticated pendingAuthenticated = mPendingAuthenticated;
// Post this to make sure it's executed after the device is fully locked.
mHandler.post(() -> onBiometricAuthenticated(pendingAuthenticated.userId,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 4d0ad405835a..311728fff6aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -372,8 +372,6 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn
void fadeKeyguardAfterLaunchTransition(Runnable beforeFading,
Runnable endRunnable, Runnable cancelRunnable);
- void animateKeyguardUnoccluding();
-
void startLaunchTransitionTimeout();
boolean hideKeyguardImpl(boolean forceStateChange);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index b8ab956b32d3..df850ae42712 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -53,6 +53,7 @@ import com.android.systemui.camera.CameraIntents;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.CameraLauncher;
@@ -106,6 +107,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba
private final SystemBarAttributesListener mSystemBarAttributesListener;
private final Lazy<CameraLauncher> mCameraLauncherLazy;
private final QuickSettingsController mQsController;
+ private final QSHost mQSHost;
private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES =
VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);
@@ -138,7 +140,8 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba
@DisplayId int displayId,
SystemBarAttributesListener systemBarAttributesListener,
Lazy<CameraLauncher> cameraLauncherLazy,
- UserTracker userTracker) {
+ UserTracker userTracker,
+ QSHost qsHost) {
mCentralSurfaces = centralSurfaces;
mQsController = quickSettingsController;
mContext = context;
@@ -164,6 +167,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba
mDisplayId = displayId;
mCameraLauncherLazy = cameraLauncherLazy;
mUserTracker = userTracker;
+ mQSHost = qsHost;
mVibrateOnOpening = resources.getBoolean(R.bool.config_vibrateOnIconAnimation);
mCameraLaunchGestureVibrationEffect = getCameraGestureVibrationEffect(
@@ -184,22 +188,17 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba
@Override
public void addQsTile(ComponentName tile) {
- QSPanelController qsPanelController = mCentralSurfaces.getQSPanelController();
- if (qsPanelController != null && qsPanelController.getHost() != null) {
- qsPanelController.getHost().addTile(tile);
- }
+ mQSHost.addTile(tile);
}
@Override
public void remQsTile(ComponentName tile) {
- QSPanelController qsPanelController = mCentralSurfaces.getQSPanelController();
- if (qsPanelController != null && qsPanelController.getHost() != null) {
- qsPanelController.getHost().removeTileByUser(tile);
- }
+ mQSHost.removeTileByUser(tile);
}
@Override
public void clickTile(ComponentName tile) {
+ // Can't inject this because it changes with the QS fragment
QSPanelController qsPanelController = mCentralSurfaces.getQSPanelController();
if (qsPanelController != null) {
qsPanelController.clickTile(tile);
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 378b74a62024..b5d51ce2b9ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -2211,10 +2211,10 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
pw.println("Current Status Bar state:");
pw.println(" mExpandedVisible=" + mShadeController.isExpandedVisible());
pw.println(" mDisplayMetrics=" + mDisplayMetrics);
- pw.println(" mStackScroller: " + CentralSurfaces.viewInfo(mStackScroller));
- pw.println(" mStackScroller: " + CentralSurfaces.viewInfo(mStackScroller)
- + " scroll " + mStackScroller.getScrollX()
+ pw.print(" mStackScroller: " + CentralSurfaces.viewInfo(mStackScroller));
+ pw.print(" scroll " + mStackScroller.getScrollX()
+ "," + mStackScroller.getScrollY());
+ pw.println(" translationX " + mStackScroller.getTranslationX());
}
pw.print(" mInteractingWindows="); pw.println(mInteractingWindows);
@@ -2984,16 +2984,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
}
/**
- * Plays the animation when an activity that was occluding Keyguard goes away.
- */
- @Override
- public void animateKeyguardUnoccluding() {
- mNotificationPanelViewController.setExpandedFraction(0f);
- mCommandQueueCallbacks.animateExpandNotificationsPanel();
- mScrimController.setUnocclusionAnimationRunning(true);
- }
-
- /**
* Starts the timeout when we try to start the affordances on Keyguard. We usually rely that
* Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen
* because the launched app crashed or something else went wrong.
@@ -3705,6 +3695,12 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
@Override
public void notifyBiometricAuthModeChanged() {
mDozeServiceHost.updateDozing();
+ if (mBiometricUnlockController.getMode()
+ == BiometricUnlockController.MODE_DISMISS_BOUNCER) {
+ // Don't update the scrim controller at this time, in favor of the transition repository
+ // updating the scrim
+ return;
+ }
updateScrimController();
}
@@ -3757,6 +3753,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
} 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();
} else if (mBouncerShowing && !unlocking) {
// Bouncer needs the front scrim when it's on top of an activity,
// tapping on a notification, editing QS or being dismissed by
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index c72eb054c62c..39b5b5a4cef8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -40,6 +40,7 @@ import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger;
import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView;
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
import com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView;
@@ -288,10 +289,14 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da
* @param mobileContext possibly mcc/mnc overridden mobile context
* @param subId the subscriptionId for this mobile view
*/
- public void addModernMobileView(Context mobileContext, int subId) {
+ public void addModernMobileView(
+ Context mobileContext,
+ MobileViewLogger mobileViewLogger,
+ int subId) {
Log.d(TAG, "addModernMobileView (subId=" + subId + ")");
ModernStatusBarMobileView view = ModernStatusBarMobileView.constructAndBind(
mobileContext,
+ mobileViewLogger,
"mobile",
mMobileIconsViewModel.viewModelForSub(subId, mLocation)
);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index b88531e59568..ae715b3f20c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -429,7 +429,6 @@ public class DozeParameters implements
}
dispatchAlwaysOnEvent();
- mScreenOffAnimationController.onAlwaysOnChanged(getAlwaysOn());
}
@Override
@@ -469,6 +468,7 @@ public class DozeParameters implements
for (Callback callback : mCallbacks) {
callback.onAlwaysOnChange();
}
+ mScreenOffAnimationController.onAlwaysOnChanged(getAlwaysOn());
}
private boolean getPostureSpecificBool(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 753032c2ee01..3268032becf8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -59,7 +59,7 @@ import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.fragment.StatusBarIconBlocklistKt;
-import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventAnimator;
+import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventDefaultAnimator;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -75,6 +75,8 @@ import java.util.concurrent.Executor;
import javax.inject.Inject;
+import kotlin.Unit;
+
/** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */
public class KeyguardStatusBarViewController extends ViewController<KeyguardStatusBarView> {
private static final String TAG = "KeyguardStatusBarViewController";
@@ -123,7 +125,8 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
public void onDensityOrFontScaleChanged() {
mView.loadDimens();
// The animator is dependent on resources for offsets
- mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, getResources());
+ mSystemEventAnimator =
+ getSystemEventAnimator(mSystemEventAnimator.isAnimationRunning());
}
@Override
@@ -248,7 +251,8 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
private int mStatusBarState;
private boolean mDozing;
private boolean mShowingKeyguardHeadsUp;
- private StatusBarSystemEventAnimator mSystemEventAnimator;
+ private StatusBarSystemEventDefaultAnimator mSystemEventAnimator;
+ private float mSystemEventAnimatorAlpha = 1;
/**
* The alpha value to be set on the View. If -1, this value is to be ignored.
@@ -324,7 +328,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
mView.setKeyguardUserAvatarEnabled(
!mStatusBarUserChipViewModel.getChipEnabled());
- mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, r);
+ mSystemEventAnimator = getSystemEventAnimator(/* isAnimationRunning */ false);
mDisableStateTracker = new DisableStateTracker(
/* mask1= */ DISABLE_SYSTEM_INFO,
@@ -480,6 +484,10 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
* (1.0f - mKeyguardHeadsUpShowingAmount);
}
+ if (mSystemEventAnimator.isAnimationRunning()) {
+ newAlpha = Math.min(newAlpha, mSystemEventAnimatorAlpha);
+ }
+
boolean hideForBypass =
mFirstBypassAttempt && mKeyguardUpdateMonitor.shouldListenForFace()
|| mDelayShowingKeyguardStatusBar;
@@ -488,7 +496,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
&& !mDozing
&& !hideForBypass
&& !mDisableStateTracker.isDisabled()
- ? View.VISIBLE : View.INVISIBLE;
+ ? View.VISIBLE : View.INVISIBLE;
updateViewState(newAlpha, newVisibility);
}
@@ -614,4 +622,15 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
updateBlockedIcons();
}
};
+
+ private StatusBarSystemEventDefaultAnimator getSystemEventAnimator(boolean isAnimationRunning) {
+ return new StatusBarSystemEventDefaultAnimator(getResources(), (alpha) -> {
+ mSystemEventAnimatorAlpha = alpha;
+ updateViewState();
+ return Unit.INSTANCE;
+ }, (translationX) -> {
+ mView.setTranslationX(translationX);
+ return Unit.INSTANCE;
+ }, isAnimationRunning);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 6c532a5c5fab..e6b76ad0e00c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -22,8 +22,6 @@ import android.annotation.Nullable;
import android.app.ActivityTaskManager;
import android.app.AlarmManager;
import android.app.AlarmManager.AlarmClockInfo;
-import android.app.IActivityManager;
-import android.app.SynchronousUserSwitchObserver;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -134,7 +132,6 @@ public class PhoneStatusBarPolicy
private final NextAlarmController mNextAlarmController;
private final AlarmManager mAlarmManager;
private final UserInfoController mUserInfoController;
- private final IActivityManager mIActivityManager;
private final UserManager mUserManager;
private final UserTracker mUserTracker;
private final DevicePolicyManager mDevicePolicyManager;
@@ -149,6 +146,7 @@ public class PhoneStatusBarPolicy
private final KeyguardStateController mKeyguardStateController;
private final LocationController mLocationController;
private final PrivacyItemController mPrivacyItemController;
+ private final Executor mMainExecutor;
private final Executor mUiBgExecutor;
private final SensorPrivacyController mSensorPrivacyController;
private final RecordingController mRecordingController;
@@ -168,16 +166,17 @@ public class PhoneStatusBarPolicy
@Inject
public PhoneStatusBarPolicy(StatusBarIconController iconController,
CommandQueue commandQueue, BroadcastDispatcher broadcastDispatcher,
- @UiBackground Executor uiBgExecutor, @Main Looper looper, @Main Resources resources,
- CastController castController, HotspotController hotspotController,
- BluetoothController bluetoothController, NextAlarmController nextAlarmController,
- UserInfoController userInfoController, RotationLockController rotationLockController,
- DataSaverController dataSaverController, ZenModeController zenModeController,
+ @Main Executor mainExecutor, @UiBackground Executor uiBgExecutor, @Main Looper looper,
+ @Main Resources resources, CastController castController,
+ HotspotController hotspotController, BluetoothController bluetoothController,
+ NextAlarmController nextAlarmController, UserInfoController userInfoController,
+ RotationLockController rotationLockController, DataSaverController dataSaverController,
+ ZenModeController zenModeController,
DeviceProvisionedController deviceProvisionedController,
KeyguardStateController keyguardStateController,
LocationController locationController,
- SensorPrivacyController sensorPrivacyController, IActivityManager iActivityManager,
- AlarmManager alarmManager, UserManager userManager, UserTracker userTracker,
+ SensorPrivacyController sensorPrivacyController, AlarmManager alarmManager,
+ UserManager userManager, UserTracker userTracker,
DevicePolicyManager devicePolicyManager, RecordingController recordingController,
@Nullable TelecomManager telecomManager, @DisplayId int displayId,
@Main SharedPreferences sharedPreferences, DateFormatUtil dateFormatUtil,
@@ -195,7 +194,6 @@ public class PhoneStatusBarPolicy
mNextAlarmController = nextAlarmController;
mAlarmManager = alarmManager;
mUserInfoController = userInfoController;
- mIActivityManager = iActivityManager;
mUserManager = userManager;
mUserTracker = userTracker;
mDevicePolicyManager = devicePolicyManager;
@@ -208,6 +206,7 @@ public class PhoneStatusBarPolicy
mPrivacyItemController = privacyItemController;
mSensorPrivacyController = sensorPrivacyController;
mRecordingController = recordingController;
+ mMainExecutor = mainExecutor;
mUiBgExecutor = uiBgExecutor;
mTelecomManager = telecomManager;
mRingerModeTracker = ringerModeTracker;
@@ -256,11 +255,7 @@ public class PhoneStatusBarPolicy
mRingerModeTracker.getRingerModeInternal().observeForever(observer);
// listen for user / profile change.
- try {
- mIActivityManager.registerUserSwitchObserver(mUserSwitchListener, TAG);
- } catch (RemoteException e) {
- // Ignore
- }
+ mUserTracker.addCallback(mUserSwitchListener, mMainExecutor);
// TTY status
updateTTY();
@@ -555,15 +550,15 @@ public class PhoneStatusBarPolicy
});
}
- private final SynchronousUserSwitchObserver mUserSwitchListener =
- new SynchronousUserSwitchObserver() {
+ private final UserTracker.Callback mUserSwitchListener =
+ new UserTracker.Callback() {
@Override
- public void onUserSwitching(int newUserId) throws RemoteException {
+ public void onUserChanging(int newUser, Context userContext) {
mHandler.post(() -> mUserInfoController.reloadUserInfo());
}
@Override
- public void onUserSwitchComplete(int newUserId) throws RemoteException {
+ public void onUserChanged(int newUser, Context userContext) {
mHandler.post(() -> {
updateAlarm();
updateManagedProfile();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 80093a3da325..8fd967594198 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
+
import static java.lang.Float.isNaN;
import android.animation.Animator;
@@ -53,9 +55,14 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
+import com.android.systemui.keyguard.shared.model.TransitionState;
+import com.android.systemui.keyguard.shared.model.TransitionStep;
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.stack.ViewState;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -71,6 +78,8 @@ import java.util.function.Consumer;
import javax.inject.Inject;
+import kotlinx.coroutines.CoroutineDispatcher;
+
/**
* Controls both the scrim behind the notifications and in front of the notifications (when a
* security method gets shown).
@@ -138,26 +147,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private boolean mTransitioningToFullShade;
/**
- * Is there currently an unocclusion animation running. Used to avoid bright flickers
- * of the notification scrim.
- */
- private boolean mUnOcclusionAnimationRunning;
-
- /**
* The percentage of the bouncer which is hidden. If 1, the bouncer is completely hidden. If
* 0, the bouncer is visible.
*/
@FloatRange(from = 0, to = 1)
private float mBouncerHiddenFraction = KeyguardBouncerConstants.EXPANSION_HIDDEN;
- /**
- * Set whether an unocclusion animation is currently running on the notification panel. Used
- * to avoid bright flickers of the notification scrim.
- */
- public void setUnocclusionAnimationRunning(boolean unocclusionAnimationRunning) {
- mUnOcclusionAnimationRunning = unocclusionAnimationRunning;
- }
-
@IntDef(prefix = {"VISIBILITY_"}, value = {
TRANSPARENT,
SEMI_TRANSPARENT,
@@ -211,6 +206,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private final ScreenOffAnimationController mScreenOffAnimationController;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private final SysuiStatusBarStateController mStatusBarStateController;
private GradientColors mColors;
private boolean mNeedsDrawableColorUpdate;
@@ -265,6 +261,20 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private boolean mWakeLockHeld;
private boolean mKeyguardOccluded;
+ private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ private CoroutineDispatcher mMainDispatcher;
+ private boolean mIsBouncerToGoneTransitionRunning = false;
+ private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
+ private final Consumer<Float> mScrimAlphaConsumer =
+ (Float alpha) -> {
+ mScrimInFront.setViewAlpha(mInFrontAlpha);
+ mNotificationsScrim.setViewAlpha(mNotificationsAlpha);
+ mBehindAlpha = alpha;
+ mScrimBehind.setViewAlpha(alpha);
+ };
+
+ Consumer<TransitionStep> mPrimaryBouncerToGoneTransition;
+
@Inject
public ScrimController(
LightBarController lightBarController,
@@ -279,13 +289,18 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
@Main Executor mainExecutor,
ScreenOffAnimationController screenOffAnimationController,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
- StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel,
+ KeyguardTransitionInteractor keyguardTransitionInteractor,
+ SysuiStatusBarStateController sysuiStatusBarStateController,
+ @Main CoroutineDispatcher mainDispatcher) {
mScrimStateListener = lightBarController::setScrimState;
mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
mKeyguardStateController = keyguardStateController;
mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen();
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mStatusBarStateController = sysuiStatusBarStateController;
mKeyguardVisibilityCallback = new KeyguardVisibilityCallback();
mHandler = handler;
mMainExecutor = mainExecutor;
@@ -318,6 +333,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
}
});
mColors = new GradientColors();
+ mPrimaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel;
+ mKeyguardTransitionInteractor = keyguardTransitionInteractor;
+ mMainDispatcher = mainDispatcher;
}
/**
@@ -357,6 +375,33 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
for (ScrimState state : ScrimState.values()) {
state.prepare(state);
}
+
+ // Directly control transition to UNLOCKED scrim state from PRIMARY_BOUNCER, and make sure
+ // to report back that keyguard has faded away. This fixes cases where the scrim state was
+ // rapidly switching on unlock, due to shifts in state in CentralSurfacesImpl
+ mPrimaryBouncerToGoneTransition =
+ (TransitionStep step) -> {
+ TransitionState state = step.getTransitionState();
+
+ mIsBouncerToGoneTransitionRunning = state == TransitionState.RUNNING;
+
+ if (state == TransitionState.STARTED) {
+ setExpansionAffectsAlpha(false);
+ transitionTo(ScrimState.UNLOCKED);
+ }
+
+ if (state == TransitionState.FINISHED || state == TransitionState.CANCELED) {
+ setExpansionAffectsAlpha(true);
+ if (mKeyguardStateController.isKeyguardFadingAway()) {
+ mStatusBarKeyguardViewManager.onKeyguardFadedAway();
+ }
+ }
+ };
+
+ collectFlow(behindScrim, mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition(),
+ mPrimaryBouncerToGoneTransition, mMainDispatcher);
+ collectFlow(behindScrim, mPrimaryBouncerToGoneTransitionViewModel.getScrimBehindAlpha(),
+ mScrimAlphaConsumer, mMainDispatcher);
}
/**
@@ -379,6 +424,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
}
public void transitionTo(ScrimState state, Callback callback) {
+ if (mIsBouncerToGoneTransitionRunning) {
+ Log.i(TAG, "Skipping transition to: " + state
+ + " while mIsBouncerToGoneTransitionRunning");
+ return;
+ }
if (state == mState) {
// Call the callback anyway, unless it's already enqueued
if (callback != null && mCallback != callback) {
@@ -532,10 +582,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
}
}
- public void onExpandingFinished() {
- setUnocclusionAnimationRunning(false);
- }
-
@VisibleForTesting
protected void onHideWallpaperTimeout() {
if (mState != ScrimState.AOD && mState != ScrimState.PULSING) {
@@ -875,13 +921,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
if (mKeyguardOccluded || hideNotificationScrim) {
mNotificationsAlpha = 0;
}
- if (mUnOcclusionAnimationRunning && mState == ScrimState.KEYGUARD) {
- // We're unoccluding the keyguard and don't want to have a bright flash.
- mNotificationsAlpha = ScrimState.KEYGUARD.getNotifAlpha();
- mNotificationsTint = ScrimState.KEYGUARD.getNotifTint();
- mBehindAlpha = ScrimState.KEYGUARD.getBehindAlpha();
- mBehindTint = ScrimState.KEYGUARD.getBehindTint();
- }
}
if (mState != ScrimState.UNLOCKED) {
mAnimatingPanelExpansionOnUnlock = false;
@@ -1061,7 +1100,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
mBehindAlpha = 1;
}
// Prevent notification scrim flicker when transitioning away from keyguard.
- if (mKeyguardStateController.isKeyguardGoingAway()) {
+ if (mKeyguardStateController.isKeyguardGoingAway()
+ && !mStatusBarStateController.leaveOpenOnKeyguardHide()) {
mNotificationsAlpha = 0;
}
@@ -1150,7 +1190,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
Trace.traceCounter(Trace.TRACE_TAG_APP, getScrimName(scrimView) + "_tint",
Color.alpha(tint));
scrimView.setTint(tint);
- scrimView.setViewAlpha(alpha);
+ if (!mIsBouncerToGoneTransitionRunning) {
+ scrimView.setViewAlpha(alpha);
+ }
} else {
scrim.setAlpha(alpha);
}
@@ -1498,6 +1540,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
}
public void setKeyguardOccluded(boolean keyguardOccluded) {
+ if (mKeyguardOccluded == keyguardOccluded) {
+ return;
+ }
mKeyguardOccluded = keyguardOccluded;
updateScrims();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 11863627218e..04cc8ce792d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -569,7 +569,10 @@ public interface StatusBarIconController {
mGroup.addView(view, index, onCreateLayoutParams());
if (mIsInDemoMode) {
- mDemoStatusIcons.addModernMobileView(mContext, subId);
+ mDemoStatusIcons.addModernMobileView(
+ mContext,
+ mMobileIconsViewModel.getLogger(),
+ subId);
}
return view;
@@ -601,6 +604,7 @@ public interface StatusBarIconController {
return ModernStatusBarMobileView
.constructAndBind(
mobileContext,
+ mMobileIconsViewModel.getLogger(),
slot,
mMobileIconsViewModel.viewModelForSub(subId, mLocation)
);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
index f6c0da8da8c0..833cb93f62e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
@@ -79,6 +79,18 @@ public class StatusBarIconHolder {
private @IconType int mType = TYPE_ICON;
private int mTag = 0;
+ /** Returns a human-readable string representing the given type. */
+ public static String getTypeString(@IconType int type) {
+ switch(type) {
+ case TYPE_ICON: return "ICON";
+ case TYPE_WIFI: return "WIFI_OLD";
+ case TYPE_MOBILE: return "MOBILE_OLD";
+ case TYPE_MOBILE_NEW: return "MOBILE_NEW";
+ case TYPE_WIFI_NEW: return "WIFI_NEW";
+ default: return "UNKNOWN";
+ }
+ }
+
private StatusBarIconHolder() {
}
@@ -230,4 +242,11 @@ public class StatusBarIconHolder {
public int getTag() {
return mTag;
}
+
+ @Override
+ public String toString() {
+ return "StatusBarIconHolder(type=" + getTypeString(mType)
+ + " tag=" + getTag()
+ + " visible=" + isVisible() + ")";
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
index 8800b05fadb7..565481a20d95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
@@ -27,6 +27,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.stream.Collectors;
/** A class holding the list of all the system icons that could be shown in the status bar. */
public class StatusBarIconList {
@@ -302,7 +303,7 @@ public class StatusBarIconList {
@Override
public String toString() {
- return String.format("(%s) %s", mName, subSlotsString());
+ return String.format("(%s) holder=%s %s", mName, mHolder, subSlotsString());
}
private String subSlotsString() {
@@ -310,7 +311,10 @@ public class StatusBarIconList {
return "";
}
- return "" + mSubSlots.size() + " subSlots";
+ return "| " + mSubSlots.size() + " subSlots: "
+ + mSubSlots.stream()
+ .map(StatusBarIconHolder::toString)
+ .collect(Collectors.joining("|"));
}
}
}
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 80b0262482ac..3c32131220d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -280,7 +280,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private boolean mLastScreenOffAnimationPlaying;
private float mQsExpansion;
final Set<KeyguardViewManagerCallback> mCallbacks = new HashSet<>();
- private boolean mIsUnoccludeTransitionFlagEnabled;
private boolean mIsModernAlternateBouncerEnabled;
private boolean mIsBackAnimationEnabled;
@@ -359,7 +358,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mPrimaryBouncerView = primaryBouncerView;
mFoldAodAnimationController = sysUIUnfoldComponent
.map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null);
- mIsUnoccludeTransitionFlagEnabled = featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION);
mIsModernAlternateBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER);
mAlternateBouncerInteractor = alternateBouncerInteractor;
mIsBackAnimationEnabled =
@@ -880,11 +878,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
// by a FLAG_DISMISS_KEYGUARD_ACTIVITY.
reset(isOccluding /* hideBouncerWhenShowing*/);
}
- if (!mIsUnoccludeTransitionFlagEnabled) {
- if (animate && !isOccluded && isShowing && !primaryBouncerIsShowing()) {
- mCentralSurfaces.animateKeyguardUnoccluding();
- }
- }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
index 79c0984d9bf7..d30d0e25bd8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
@@ -22,6 +22,7 @@ import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator.AlphaP
import com.android.systemui.statusbar.phone.PhoneStatusBarViewController.StatusBarViewsCenterProvider
import com.android.systemui.unfold.SysUIUnfoldScope
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.unfold.util.CurrentActivityTypeProvider
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
import javax.inject.Inject
import kotlin.math.max
@@ -29,9 +30,13 @@ import kotlin.math.max
@SysUIUnfoldScope
class StatusBarMoveFromCenterAnimationController @Inject constructor(
private val progressProvider: ScopedUnfoldTransitionProgressProvider,
+ private val currentActivityTypeProvider: CurrentActivityTypeProvider,
windowManager: WindowManager
) {
+ // Whether we're on home activity. Updated only when the animation starts.
+ private var isOnHomeActivity: Boolean? = null
+
private val transitionListener = TransitionListener()
private val moveFromCenterAnimator = UnfoldMoveFromCenterAnimator(
windowManager,
@@ -60,6 +65,10 @@ class StatusBarMoveFromCenterAnimationController @Inject constructor(
}
private inner class TransitionListener : TransitionProgressListener {
+ override fun onTransitionStarted() {
+ isOnHomeActivity = currentActivityTypeProvider.isHomeActivity
+ }
+
override fun onTransitionProgress(progress: Float) {
moveFromCenterAnimator.onTransitionProgress(progress)
}
@@ -68,11 +77,23 @@ class StatusBarMoveFromCenterAnimationController @Inject constructor(
// Reset translations when transition is stopped/cancelled
// (e.g. the transition could be cancelled mid-way when rotating the screen)
moveFromCenterAnimator.onTransitionProgress(1f)
+ isOnHomeActivity = null
}
}
- private class StatusBarIconsAlphaProvider : AlphaProvider {
+
+ /**
+ * In certain cases, an alpha is applied based on the progress.
+ *
+ * This mainly happens to hide the statusbar during the unfold animation while on apps, as the
+ * bounds of the app "collapse" to the center, but the statusbar doesn't.
+ * While on launcher, this alpha is not applied.
+ */
+ private inner class StatusBarIconsAlphaProvider : AlphaProvider {
override fun getAlpha(progress: Float): Float {
+ if (isOnHomeActivity == true) {
+ return 1.0f
+ }
return max(
0f,
(progress - ICONS_START_APPEARING_PROGRESS) / (1 - ICONS_START_APPEARING_PROGRESS)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
index c04ea36b3d8d..5903fa3d5bd1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
@@ -26,19 +26,39 @@ import com.android.systemui.statusbar.events.STATUS_BAR_X_MOVE_IN
import com.android.systemui.statusbar.events.STATUS_BAR_X_MOVE_OUT
import com.android.systemui.statusbar.events.SystemStatusAnimationCallback
import com.android.systemui.util.animation.AnimationUtil.Companion.frames
+import com.android.systemui.util.doOnCancel
+import com.android.systemui.util.doOnEnd
+
+/**
+ * An implementation of [StatusBarSystemEventDefaultAnimator], applying the onAlphaChanged and
+ * onTranslationXChanged callbacks directly to the provided animatedView.
+ */
+class StatusBarSystemEventAnimator @JvmOverloads constructor(
+ val animatedView: View,
+ resources: Resources,
+ isAnimationRunning: Boolean = false
+) : StatusBarSystemEventDefaultAnimator(
+ resources = resources,
+ onAlphaChanged = animatedView::setAlpha,
+ onTranslationXChanged = animatedView::setTranslationX,
+ isAnimationRunning = isAnimationRunning
+)
/**
* Tied directly to [SystemStatusAnimationScheduler]. Any StatusBar-like thing (keyguard, collapsed
- * status bar fragment), can just feed this an animatable view to get the default system status
- * animation.
+ * status bar fragment), can use this Animator to get the default system status animation. It simply
+ * needs to implement the onAlphaChanged and onTranslationXChanged callbacks.
*
* This animator relies on resources, and should be recreated whenever resources are updated. While
* this class could be used directly as the animation callback, it's probably best to forward calls
* to it so that it can be recreated at any moment without needing to remove/add callback.
*/
-class StatusBarSystemEventAnimator(
- val animatedView: View,
- resources: Resources
+
+open class StatusBarSystemEventDefaultAnimator @JvmOverloads constructor(
+ resources: Resources,
+ private val onAlphaChanged: (Float) -> Unit,
+ private val onTranslationXChanged: (Float) -> Unit,
+ var isAnimationRunning: Boolean = false
) : SystemStatusAnimationCallback {
private val translationXIn: Int = resources.getDimensionPixelSize(
R.dimen.ongoing_appops_chip_animation_in_status_bar_translation_x)
@@ -46,18 +66,19 @@ class StatusBarSystemEventAnimator(
R.dimen.ongoing_appops_chip_animation_out_status_bar_translation_x)
override fun onSystemEventAnimationBegin(): Animator {
+ isAnimationRunning = true
val moveOut = ValueAnimator.ofFloat(0f, 1f).apply {
duration = 23.frames
interpolator = STATUS_BAR_X_MOVE_OUT
addUpdateListener {
- animatedView.translationX = -(translationXIn * animatedValue as Float)
+ onTranslationXChanged(-(translationXIn * animatedValue as Float))
}
}
val alphaOut = ValueAnimator.ofFloat(1f, 0f).apply {
duration = 8.frames
interpolator = null
addUpdateListener {
- animatedView.alpha = animatedValue as Float
+ onAlphaChanged(animatedValue as Float)
}
}
@@ -67,13 +88,13 @@ class StatusBarSystemEventAnimator(
}
override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator {
- animatedView.translationX = translationXOut.toFloat()
+ onTranslationXChanged(translationXOut.toFloat())
val moveIn = ValueAnimator.ofFloat(1f, 0f).apply {
duration = 23.frames
startDelay = 7.frames
interpolator = STATUS_BAR_X_MOVE_IN
addUpdateListener {
- animatedView.translationX = translationXOut * animatedValue as Float
+ onTranslationXChanged(translationXOut * animatedValue as Float)
}
}
val alphaIn = ValueAnimator.ofFloat(0f, 1f).apply {
@@ -81,13 +102,14 @@ class StatusBarSystemEventAnimator(
startDelay = 11.frames
interpolator = null
addUpdateListener {
- animatedView.alpha = animatedValue as Float
+ onAlphaChanged(animatedValue as Float)
}
}
val animatorSet = AnimatorSet()
animatorSet.playTogether(moveIn, alphaIn)
-
+ animatorSet.doOnEnd { isAnimationRunning = false }
+ animatorSet.doOnCancel { isAnimationRunning = false }
return animatorSet
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/MobileViewLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/MobileViewLog.kt
new file mode 100644
index 000000000000..e594a8a5efd9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/MobileViewLog.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.statusbar.pipeline.dagger
+
+import javax.inject.Qualifier
+
+/** Logs for changes with the new mobile views. */
+@Qualifier
+@MustBeDocumented
+@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
+annotation class MobileViewLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index 44647515a6e5..adfea80715a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -148,5 +148,19 @@ abstract class StatusBarPipelineModule {
fun provideMobileInputLogBuffer(factory: LogBufferFactory): LogBuffer {
return factory.create("MobileInputLog", 100)
}
+
+ @Provides
+ @SysUISingleton
+ @MobileViewLog
+ fun provideMobileViewLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("MobileViewLog", 100)
+ }
+
+ @Provides
+ @SysUISingleton
+ @VerboseMobileViewLog
+ fun provideVerboseMobileViewLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("VerboseMobileViewLog", 100)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/VerboseMobileViewLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/VerboseMobileViewLog.kt
new file mode 100644
index 000000000000..b98789807dd3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/VerboseMobileViewLog.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.statusbar.pipeline.dagger
+
+import javax.inject.Qualifier
+
+/** Logs for **verbose** changes with the new mobile views. */
+@Qualifier
+@MustBeDocumented
+@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
+annotation class VerboseMobileViewLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
index 3cbd2b76c248..4156fc152602 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.shared
+package com.android.systemui.statusbar.pipeline.mobile.data
import android.net.Network
import android.net.NetworkCapabilities
@@ -51,8 +51,8 @@ constructor(
)
}
- fun logOnLost(network: Network) {
- LoggerHelper.logOnLost(buffer, TAG, network)
+ fun logOnLost(network: Network, isDefaultNetworkCallback: Boolean) {
+ LoggerHelper.logOnLost(buffer, TAG, network, isDefaultNetworkCallback)
}
fun logOnServiceStateChanged(serviceState: ServiceState, subId: Int) {
@@ -133,24 +133,6 @@ constructor(
)
}
- fun logUiAdapterSubIdsUpdated(subs: List<Int>) {
- buffer.log(
- TAG,
- LogLevel.INFO,
- { str1 = subs.toString() },
- { "Sub IDs in MobileUiAdapter updated internally: $str1" },
- )
- }
-
- fun logUiAdapterSubIdsSentToIconController(subs: List<Int>) {
- buffer.log(
- TAG,
- LogLevel.INFO,
- { str1 = subs.toString() },
- { "Sub IDs in MobileUiAdapter being sent to icon controller: $str1" },
- )
- }
-
fun logCarrierConfigChanged(subId: Int) {
buffer.log(
TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/DataConnectionState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/DataConnectionState.kt
index 85729c12cd4c..19f0242040fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/DataConnectionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/DataConnectionState.kt
@@ -24,9 +24,11 @@ import android.telephony.TelephonyManager.DATA_HANDOVER_IN_PROGRESS
import android.telephony.TelephonyManager.DATA_SUSPENDED
import android.telephony.TelephonyManager.DATA_UNKNOWN
import android.telephony.TelephonyManager.DataState
+import com.android.systemui.log.table.Diffable
+import com.android.systemui.log.table.TableRowLogger
/** Internal enum representation of the telephony data connection states */
-enum class DataConnectionState {
+enum class DataConnectionState : Diffable<DataConnectionState> {
Connected,
Connecting,
Disconnected,
@@ -34,7 +36,17 @@ enum class DataConnectionState {
Suspended,
HandoverInProgress,
Unknown,
- Invalid,
+ Invalid;
+
+ override fun logDiffs(prevVal: DataConnectionState, row: TableRowLogger) {
+ if (prevVal != this) {
+ row.logChange(COL_CONNECTION_STATE, name)
+ }
+ }
+
+ companion object {
+ private const val COL_CONNECTION_STATE = "connectionState"
+ }
}
fun @receiver:DataState Int.toDataConnectionType(): DataConnectionState =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt
deleted file mode 100644
index ed7f60b50bb9..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt
+++ /dev/null
@@ -1,176 +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.pipeline.mobile.data.model
-
-import android.annotation.IntRange
-import android.telephony.CellSignalStrength
-import android.telephony.TelephonyCallback.CarrierNetworkListener
-import android.telephony.TelephonyCallback.DataActivityListener
-import android.telephony.TelephonyCallback.DataConnectionStateListener
-import android.telephony.TelephonyCallback.DisplayInfoListener
-import android.telephony.TelephonyCallback.ServiceStateListener
-import android.telephony.TelephonyCallback.SignalStrengthsListener
-import android.telephony.TelephonyDisplayInfo
-import android.telephony.TelephonyManager
-import androidx.annotation.VisibleForTesting
-import com.android.systemui.log.table.Diffable
-import com.android.systemui.log.table.TableRowLogger
-import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Disconnected
-import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
-
-/**
- * Data class containing all of the relevant information for a particular line of service, known as
- * a Subscription in the telephony world. These models are the result of a single telephony listener
- * which has many callbacks which each modify some particular field on this object.
- *
- * The design goal here is to de-normalize fields from the system into our model fields below. So
- * any new field that needs to be tracked should be copied into this data class rather than
- * threading complex system objects through the pipeline.
- */
-data class MobileConnectionModel(
- /** Fields below are from [ServiceStateListener.onServiceStateChanged] */
- val isEmergencyOnly: Boolean = false,
- val isRoaming: Boolean = false,
- /**
- * See [android.telephony.ServiceState.getOperatorAlphaShort], this value is defined as the
- * current registered operator name in short alphanumeric format. In some cases this name might
- * be preferred over other methods of calculating the network name
- */
- val operatorAlphaShort: String? = null,
-
- /**
- * TODO (b/263167683): Clarify this field
- *
- * This check comes from [com.android.settingslib.Utils.isInService]. It is intended to be a
- * mapping from a ServiceState to a notion of connectivity. Notably, it will consider a
- * connection to be in-service if either the voice registration state is IN_SERVICE or the data
- * registration state is IN_SERVICE and NOT IWLAN.
- */
- val isInService: Boolean = false,
-
- /** Fields below from [SignalStrengthsListener.onSignalStrengthsChanged] */
- val isGsm: Boolean = false,
- @IntRange(from = 0, to = 4)
- val cdmaLevel: Int = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
- @IntRange(from = 0, to = 4)
- val primaryLevel: Int = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
-
- /** Fields below from [DataConnectionStateListener.onDataConnectionStateChanged] */
- val dataConnectionState: DataConnectionState = Disconnected,
-
- /**
- * Fields below from [DataActivityListener.onDataActivity]. See [TelephonyManager] for the
- * values
- */
- val dataActivityDirection: DataActivityModel =
- DataActivityModel(
- hasActivityIn = false,
- hasActivityOut = false,
- ),
-
- /** Fields below from [CarrierNetworkListener.onCarrierNetworkChange] */
- val carrierNetworkChangeActive: Boolean = false,
-
- /** Fields below from [DisplayInfoListener.onDisplayInfoChanged]. */
-
- /**
- * [resolvedNetworkType] is the [TelephonyDisplayInfo.getOverrideNetworkType] if it exists or
- * [TelephonyDisplayInfo.getNetworkType]. This is used to look up the proper network type icon
- */
- val resolvedNetworkType: ResolvedNetworkType = ResolvedNetworkType.UnknownNetworkType,
-) : Diffable<MobileConnectionModel> {
- override fun logDiffs(prevVal: MobileConnectionModel, row: TableRowLogger) {
- if (prevVal.dataConnectionState != dataConnectionState) {
- row.logChange(COL_CONNECTION_STATE, dataConnectionState.name)
- }
-
- if (prevVal.isEmergencyOnly != isEmergencyOnly) {
- row.logChange(COL_EMERGENCY, isEmergencyOnly)
- }
-
- if (prevVal.isRoaming != isRoaming) {
- row.logChange(COL_ROAMING, isRoaming)
- }
-
- if (prevVal.operatorAlphaShort != operatorAlphaShort) {
- row.logChange(COL_OPERATOR, operatorAlphaShort)
- }
-
- if (prevVal.isInService != isInService) {
- row.logChange(COL_IS_IN_SERVICE, isInService)
- }
-
- if (prevVal.isGsm != isGsm) {
- row.logChange(COL_IS_GSM, isGsm)
- }
-
- if (prevVal.cdmaLevel != cdmaLevel) {
- row.logChange(COL_CDMA_LEVEL, cdmaLevel)
- }
-
- if (prevVal.primaryLevel != primaryLevel) {
- row.logChange(COL_PRIMARY_LEVEL, primaryLevel)
- }
-
- if (prevVal.dataActivityDirection.hasActivityIn != dataActivityDirection.hasActivityIn) {
- row.logChange(COL_ACTIVITY_DIRECTION_IN, dataActivityDirection.hasActivityIn)
- }
-
- if (prevVal.dataActivityDirection.hasActivityOut != dataActivityDirection.hasActivityOut) {
- row.logChange(COL_ACTIVITY_DIRECTION_OUT, dataActivityDirection.hasActivityOut)
- }
-
- if (prevVal.carrierNetworkChangeActive != carrierNetworkChangeActive) {
- row.logChange(COL_CARRIER_NETWORK_CHANGE, carrierNetworkChangeActive)
- }
-
- if (prevVal.resolvedNetworkType != resolvedNetworkType) {
- row.logChange(COL_RESOLVED_NETWORK_TYPE, resolvedNetworkType.toString())
- }
- }
-
- override fun logFull(row: TableRowLogger) {
- row.logChange(COL_CONNECTION_STATE, dataConnectionState.name)
- row.logChange(COL_EMERGENCY, isEmergencyOnly)
- row.logChange(COL_ROAMING, isRoaming)
- row.logChange(COL_OPERATOR, operatorAlphaShort)
- row.logChange(COL_IS_IN_SERVICE, isInService)
- row.logChange(COL_IS_GSM, isGsm)
- row.logChange(COL_CDMA_LEVEL, cdmaLevel)
- row.logChange(COL_PRIMARY_LEVEL, primaryLevel)
- row.logChange(COL_ACTIVITY_DIRECTION_IN, dataActivityDirection.hasActivityIn)
- row.logChange(COL_ACTIVITY_DIRECTION_OUT, dataActivityDirection.hasActivityOut)
- row.logChange(COL_CARRIER_NETWORK_CHANGE, carrierNetworkChangeActive)
- row.logChange(COL_RESOLVED_NETWORK_TYPE, resolvedNetworkType.toString())
- }
-
- @VisibleForTesting
- companion object {
- const val COL_EMERGENCY = "EmergencyOnly"
- const val COL_ROAMING = "Roaming"
- const val COL_OPERATOR = "OperatorName"
- const val COL_IS_IN_SERVICE = "IsInService"
- const val COL_IS_GSM = "IsGsm"
- const val COL_CDMA_LEVEL = "CdmaLevel"
- const val COL_PRIMARY_LEVEL = "PrimaryLevel"
- const val COL_CONNECTION_STATE = "ConnectionState"
- const val COL_ACTIVITY_DIRECTION_IN = "DataActivity.In"
- const val COL_ACTIVITY_DIRECTION_OUT = "DataActivity.Out"
- const val COL_CARRIER_NETWORK_CHANGE = "CarrierNetworkChangeActive"
- const val COL_RESOLVED_NETWORK_TYPE = "NetworkType"
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt
index 5562e73f0478..cf7a313a4cb1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt
@@ -17,8 +17,12 @@
package com.android.systemui.statusbar.pipeline.mobile.data.model
import android.telephony.Annotation.NetworkType
+import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.log.table.Diffable
+import com.android.systemui.log.table.TableRowLogger
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
/**
@@ -26,11 +30,19 @@ import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
* on whether or not the display info contains an override type, we may have to call different
* methods on [MobileMappingsProxy] to generate an icon lookup key.
*/
-sealed interface ResolvedNetworkType {
+sealed interface ResolvedNetworkType : Diffable<ResolvedNetworkType> {
val lookupKey: String
+ override fun logDiffs(prevVal: ResolvedNetworkType, row: TableRowLogger) {
+ if (prevVal != this) {
+ row.logChange(COL_NETWORK_TYPE, this.toString())
+ }
+ }
+
object UnknownNetworkType : ResolvedNetworkType {
- override val lookupKey: String = "unknown"
+ override val lookupKey: String = MobileMappings.toIconKey(NETWORK_TYPE_UNKNOWN)
+
+ override fun toString(): String = "Unknown"
}
data class DefaultNetworkType(
@@ -47,5 +59,11 @@ sealed interface ResolvedNetworkType {
override val lookupKey: String = "cwf"
val iconGroupOverride: SignalIcon.MobileIconGroup = TelephonyIcons.CARRIER_MERGED_WIFI
+
+ override fun toString(): String = "CarrierMerged"
+ }
+
+ companion object {
+ private const val COL_NETWORK_TYPE = "networkType"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt
index 8c82fbac90b8..f4e3eab8593d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt
@@ -45,7 +45,7 @@ import kotlinx.coroutines.flow.asStateFlow
* 1. Define a new `private val` wrapping the key using [BooleanCarrierConfig]
* 2. Define a public `val` exposing the wrapped flow using [BooleanCarrierConfig.config]
* 3. Add the new [BooleanCarrierConfig] to the list of tracked configs, so they are properly
- * updated when a new carrier config comes down
+ * updated when a new carrier config comes down
*/
class SystemUiCarrierConfig
internal constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
index bb3b9b2166c3..efdce062bb37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
@@ -30,8 +30,8 @@ import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
-import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
index 6187f64e011d..90c32dc08045 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
@@ -17,11 +17,12 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
import android.telephony.SubscriptionInfo
-import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import kotlinx.coroutines.flow.StateFlow
/**
@@ -45,11 +46,57 @@ interface MobileConnectionRepository {
*/
val tableLogBuffer: TableLogBuffer
+ /** True if the [android.telephony.ServiceState] says this connection is emergency calls only */
+ val isEmergencyOnly: StateFlow<Boolean>
+
+ /** True if [android.telephony.ServiceState] says we are roaming */
+ val isRoaming: StateFlow<Boolean>
+
+ /**
+ * See [android.telephony.ServiceState.getOperatorAlphaShort], this value is defined as the
+ * current registered operator name in short alphanumeric format. In some cases this name might
+ * be preferred over other methods of calculating the network name
+ */
+ val operatorAlphaShort: StateFlow<String?>
+
+ /**
+ * TODO (b/263167683): Clarify this field
+ *
+ * This check comes from [com.android.settingslib.Utils.isInService]. It is intended to be a
+ * mapping from a ServiceState to a notion of connectivity. Notably, it will consider a
+ * connection to be in-service if either the voice registration state is IN_SERVICE or the data
+ * registration state is IN_SERVICE and NOT IWLAN.
+ */
+ val isInService: StateFlow<Boolean>
+
+ /** True if [android.telephony.SignalStrength] told us that this connection is using GSM */
+ val isGsm: StateFlow<Boolean>
+
+ /**
+ * There is still specific logic in the pipeline that calls out CDMA level explicitly. This
+ * field is not completely orthogonal to [primaryLevel], because CDMA could be primary.
+ */
+ // @IntRange(from = 0, to = 4)
+ val cdmaLevel: StateFlow<Int>
+
+ /** [android.telephony.SignalStrength]'s concept of the overall signal level */
+ // @IntRange(from = 0, to = 4)
+ val primaryLevel: StateFlow<Int>
+
+ /** The current data connection state. See [DataConnectionState] */
+ val dataConnectionState: StateFlow<DataConnectionState>
+
+ /** The current data activity direction. See [DataActivityModel] */
+ val dataActivityDirection: StateFlow<DataActivityModel>
+
+ /** True if there is currently a carrier network change in process */
+ val carrierNetworkChangeActive: StateFlow<Boolean>
+
/**
- * A flow that aggregates all necessary callbacks from [TelephonyCallback] into a single
- * listener + model.
+ * [resolvedNetworkType] is the [TelephonyDisplayInfo.getOverrideNetworkType] if it exists or
+ * [TelephonyDisplayInfo.getNetworkType]. This is used to look up the proper network type icon
*/
- val connectionInfo: StateFlow<MobileConnectionModel>
+ val resolvedNetworkType: StateFlow<ResolvedNetworkType>
/** The total number of levels. Used with [SignalDrawable]. */
val numberOfLevels: StateFlow<Int>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
new file mode 100644
index 000000000000..809772eec2f0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
@@ -0,0 +1,231 @@
+/*
+ * 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.pipeline.mobile.data.repository.demo
+
+import android.telephony.CellSignalStrength
+import android.telephony.TelephonyManager
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_CARRIER_NETWORK_CHANGE
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_CDMA_LEVEL
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_EMERGENCY
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_IS_GSM
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_IS_IN_SERVICE
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_OPERATOR
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_PRIMARY_LEVEL
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_ROAMING
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Demo version of [MobileConnectionRepository]. Note that this class shares all of its flows using
+ * [SharingStarted.WhileSubscribed()] to give the same semantics as using a regular
+ * [MutableStateFlow] while still logging all of the inputs in the same manor as the production
+ * repos.
+ */
+class DemoMobileConnectionRepository(
+ override val subId: Int,
+ override val tableLogBuffer: TableLogBuffer,
+ val scope: CoroutineScope,
+) : MobileConnectionRepository {
+ private val _isEmergencyOnly = MutableStateFlow(false)
+ override val isEmergencyOnly =
+ _isEmergencyOnly
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ columnName = COL_EMERGENCY,
+ _isEmergencyOnly.value
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), _isEmergencyOnly.value)
+
+ private val _isRoaming = MutableStateFlow(false)
+ override val isRoaming =
+ _isRoaming
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ columnName = COL_ROAMING,
+ _isRoaming.value
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), _isRoaming.value)
+
+ private val _operatorAlphaShort: MutableStateFlow<String?> = MutableStateFlow(null)
+ override val operatorAlphaShort =
+ _operatorAlphaShort
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ columnName = COL_OPERATOR,
+ _operatorAlphaShort.value
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), _operatorAlphaShort.value)
+
+ private val _isInService = MutableStateFlow(false)
+ override val isInService =
+ _isInService
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ columnName = COL_IS_IN_SERVICE,
+ _isInService.value
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), _isInService.value)
+
+ private val _isGsm = MutableStateFlow(false)
+ override val isGsm =
+ _isGsm
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ columnName = COL_IS_GSM,
+ _isGsm.value
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), _isGsm.value)
+
+ private val _cdmaLevel = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+ override val cdmaLevel =
+ _cdmaLevel
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ columnName = COL_CDMA_LEVEL,
+ _cdmaLevel.value
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), _cdmaLevel.value)
+
+ private val _primaryLevel = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+ override val primaryLevel =
+ _primaryLevel
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ columnName = COL_PRIMARY_LEVEL,
+ _primaryLevel.value
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), _primaryLevel.value)
+
+ private val _dataConnectionState = MutableStateFlow(DataConnectionState.Disconnected)
+ override val dataConnectionState =
+ _dataConnectionState
+ .logDiffsForTable(tableLogBuffer, columnPrefix = "", _dataConnectionState.value)
+ .stateIn(scope, SharingStarted.WhileSubscribed(), _dataConnectionState.value)
+
+ private val _dataActivityDirection =
+ MutableStateFlow(
+ DataActivityModel(
+ hasActivityIn = false,
+ hasActivityOut = false,
+ )
+ )
+ override val dataActivityDirection =
+ _dataActivityDirection
+ .logDiffsForTable(tableLogBuffer, columnPrefix = "", _dataActivityDirection.value)
+ .stateIn(scope, SharingStarted.WhileSubscribed(), _dataActivityDirection.value)
+
+ private val _carrierNetworkChangeActive = MutableStateFlow(false)
+ override val carrierNetworkChangeActive =
+ _carrierNetworkChangeActive
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ columnName = COL_CARRIER_NETWORK_CHANGE,
+ _carrierNetworkChangeActive.value
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), _carrierNetworkChangeActive.value)
+
+ private val _resolvedNetworkType: MutableStateFlow<ResolvedNetworkType> =
+ MutableStateFlow(ResolvedNetworkType.UnknownNetworkType)
+ override val resolvedNetworkType =
+ _resolvedNetworkType
+ .logDiffsForTable(tableLogBuffer, columnPrefix = "", _resolvedNetworkType.value)
+ .stateIn(scope, SharingStarted.WhileSubscribed(), _resolvedNetworkType.value)
+
+ override val numberOfLevels = MutableStateFlow(MobileConnectionRepository.DEFAULT_NUM_LEVELS)
+
+ override val dataEnabled = MutableStateFlow(true)
+
+ override val cdmaRoaming = MutableStateFlow(false)
+
+ override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived("demo network"))
+
+ /**
+ * Process a new demo mobile event. Note that [resolvedNetworkType] must be passed in separately
+ * from the event, due to the requirement to reverse the mobile mappings lookup in the top-level
+ * repository.
+ */
+ fun processDemoMobileEvent(
+ event: FakeNetworkEventModel.Mobile,
+ resolvedNetworkType: ResolvedNetworkType,
+ ) {
+ // This is always true here, because we split out disabled states at the data-source level
+ dataEnabled.value = true
+ networkName.value = NetworkNameModel.IntentDerived(event.name)
+
+ cdmaRoaming.value = event.roaming
+ _isRoaming.value = event.roaming
+ // TODO(b/261029387): not yet supported
+ _isEmergencyOnly.value = false
+ _operatorAlphaShort.value = event.name
+ _isInService.value = (event.level ?: 0) > 0
+ // TODO(b/261029387): not yet supported
+ _isGsm.value = false
+ _cdmaLevel.value = event.level ?: 0
+ _primaryLevel.value = event.level ?: 0
+ // TODO(b/261029387): not yet supported
+ _dataConnectionState.value = DataConnectionState.Connected
+ _dataActivityDirection.value =
+ (event.activity ?: TelephonyManager.DATA_ACTIVITY_NONE).toMobileDataActivityModel()
+ _carrierNetworkChangeActive.value = event.carrierNetworkChange
+ _resolvedNetworkType.value = resolvedNetworkType
+ }
+
+ fun processCarrierMergedEvent(event: FakeWifiEventModel.CarrierMerged) {
+ // This is always true here, because we split out disabled states at the data-source level
+ dataEnabled.value = true
+ networkName.value = NetworkNameModel.IntentDerived(CARRIER_MERGED_NAME)
+ numberOfLevels.value = event.numberOfLevels
+ cdmaRoaming.value = false
+ _primaryLevel.value = event.level
+ _cdmaLevel.value = event.level
+ _dataActivityDirection.value = event.activity.toMobileDataActivityModel()
+
+ // These fields are always the same for carrier-merged networks
+ _resolvedNetworkType.value = ResolvedNetworkType.CarrierMergedNetworkType
+ _dataConnectionState.value = DataConnectionState.Connected
+ _isRoaming.value = false
+ _isEmergencyOnly.value = false
+ _operatorAlphaShort.value = null
+ _isInService.value = true
+ _isGsm.value = false
+ _carrierNetworkChangeActive.value = false
+ }
+
+ companion object {
+ private const val CARRIER_MERGED_NAME = "Carrier Merged Network"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
index e92483232186..3cafb7377260 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
@@ -18,30 +18,22 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo
import android.content.Context
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
-import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
import android.util.Log
import com.android.settingslib.SignalIcon
import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
-import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
-import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.Mobile
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.CarrierMergedConnectionRepository.Companion.createCarrierMergedConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.MOBILE_CONNECTION_BUFFER_SIZE
-import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
import javax.inject.Inject
@@ -183,7 +175,7 @@ constructor(
private fun createDemoMobileConnectionRepo(subId: Int): CacheContainer {
val tableLogBuffer =
logFactory.getOrCreate(
- "DemoMobileConnectionLog [$subId]",
+ "DemoMobileConnectionLog[$subId]",
MOBILE_CONNECTION_BUFFER_SIZE,
)
@@ -191,6 +183,7 @@ constructor(
DemoMobileConnectionRepository(
subId,
tableLogBuffer,
+ scope,
)
return CacheContainer(repo, lastMobileState = null)
}
@@ -237,23 +230,18 @@ constructor(
}
}
- private fun processEnabledMobileState(state: Mobile) {
+ private fun processEnabledMobileState(event: Mobile) {
// get or create the connection repo, and set its values
- val subId = state.subId ?: DEFAULT_SUB_ID
+ val subId = event.subId ?: DEFAULT_SUB_ID
maybeCreateSubscription(subId)
val connection = getRepoForSubId(subId)
- connectionRepoCache[subId]?.lastMobileState = state
+ connectionRepoCache[subId]?.lastMobileState = event
// TODO(b/261029387): until we have a command, use the most recent subId
defaultDataSubId.value = subId
- // This is always true here, because we split out disabled states at the data-source level
- connection.dataEnabled.value = true
- connection.networkName.value = NetworkNameModel.IntentDerived(state.name)
-
- connection.cdmaRoaming.value = state.roaming
- connection.connectionInfo.value = state.toMobileConnectionModel()
+ connection.processDemoMobileEvent(event, event.dataType.toResolvedNetworkType())
}
private fun processCarrierMergedWifiState(event: FakeWifiEventModel.CarrierMerged) {
@@ -272,13 +260,7 @@ constructor(
defaultDataSubId.value = subId
val connection = getRepoForSubId(subId)
- // This is always true here, because we split out disabled states at the data-source level
- connection.dataEnabled.value = true
- connection.networkName.value = NetworkNameModel.IntentDerived(CARRIER_MERGED_NAME)
- connection.numberOfLevels.value = event.numberOfLevels
- connection.cdmaRoaming.value = false
- connection.connectionInfo.value = event.toMobileConnectionModel()
- Log.e("CCS", "output connection info = ${connection.connectionInfo.value}")
+ connection.processCarrierMergedEvent(event)
}
private fun maybeRemoveSubscription(subId: Int?) {
@@ -332,29 +314,6 @@ constructor(
private fun subIdsString(): String =
_subscriptions.value.joinToString(",") { it.subscriptionId.toString() }
- private fun Mobile.toMobileConnectionModel(): MobileConnectionModel {
- return MobileConnectionModel(
- isEmergencyOnly = false, // TODO(b/261029387): not yet supported
- isRoaming = roaming,
- isInService = (level ?: 0) > 0,
- isGsm = false, // TODO(b/261029387): not yet supported
- cdmaLevel = level ?: 0,
- primaryLevel = level ?: 0,
- dataConnectionState =
- DataConnectionState.Connected, // TODO(b/261029387): not yet supported
- dataActivityDirection = (activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel(),
- carrierNetworkChangeActive = carrierNetworkChange,
- resolvedNetworkType = dataType.toResolvedNetworkType()
- )
- }
-
- private fun FakeWifiEventModel.CarrierMerged.toMobileConnectionModel(): MobileConnectionModel {
- return createCarrierMergedConnectionModel(
- this.level,
- activity.toMobileDataActivityModel(),
- )
- }
-
private fun SignalIcon.MobileIconGroup?.toResolvedNetworkType(): ResolvedNetworkType {
val key = mobileMappingsReverseLookup.value[this] ?: "dis"
return DefaultNetworkType(key)
@@ -364,8 +323,6 @@ constructor(
private const val TAG = "DemoMobileConnectionsRepo"
private const val DEFAULT_SUB_ID = 1
-
- private const val CARRIER_MERGED_NAME = "Carrier Merged Network"
}
}
@@ -374,18 +331,3 @@ class CacheContainer(
/** The last received [Mobile] event. Used when switching from carrier merged back to mobile. */
var lastMobileState: Mobile?,
)
-
-class DemoMobileConnectionRepository(
- override val subId: Int,
- override val tableLogBuffer: TableLogBuffer,
-) : MobileConnectionRepository {
- override val connectionInfo = MutableStateFlow(MobileConnectionModel())
-
- override val numberOfLevels = MutableStateFlow(DEFAULT_NUM_LEVELS)
-
- override val dataEnabled = MutableStateFlow(true)
-
- override val cdmaRoaming = MutableStateFlow(false)
-
- override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived("demo network"))
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
index 8f6a87b089f2..94d6d0b1db44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
@@ -16,18 +16,17 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
+import android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
import android.telephony.TelephonyManager
import android.util.Log
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
-import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import javax.inject.Inject
@@ -94,16 +93,6 @@ class CarrierMergedConnectionRepository(
}
}
- override val connectionInfo: StateFlow<MobileConnectionModel> =
- combine(network, wifiRepository.wifiActivity) { network, activity ->
- if (network == null) {
- MobileConnectionModel()
- } else {
- createCarrierMergedConnectionModel(network.level, activity)
- }
- }
- .stateIn(scope, SharingStarted.WhileSubscribed(), MobileConnectionModel())
-
override val cdmaRoaming: StateFlow<Boolean> = MutableStateFlow(ROAMING).asStateFlow()
override val networkName: StateFlow<NetworkNameModel> =
@@ -129,34 +118,54 @@ class CarrierMergedConnectionRepository(
}
.stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)
- override val dataEnabled: StateFlow<Boolean> = wifiRepository.isWifiEnabled
+ override val primaryLevel =
+ network
+ .map { it?.level ?: SIGNAL_STRENGTH_NONE_OR_UNKNOWN }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
- companion object {
- /**
- * Creates an instance of [MobileConnectionModel] that represents a carrier merged network
- * with the given [level] and [activity].
- */
- fun createCarrierMergedConnectionModel(
- level: Int,
- activity: DataActivityModel,
- ): MobileConnectionModel {
- return MobileConnectionModel(
- primaryLevel = level,
- cdmaLevel = level,
- dataActivityDirection = activity,
- // Here and below: These values are always the same for every carrier-merged
- // connection.
- resolvedNetworkType = ResolvedNetworkType.CarrierMergedNetworkType,
- dataConnectionState = DataConnectionState.Connected,
- isRoaming = ROAMING,
- isEmergencyOnly = false,
- operatorAlphaShort = null,
- isInService = true,
- isGsm = false,
- carrierNetworkChangeActive = false,
+ override val cdmaLevel =
+ network
+ .map { it?.level ?: SIGNAL_STRENGTH_NONE_OR_UNKNOWN }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+
+ override val dataActivityDirection = wifiRepository.wifiActivity
+
+ override val resolvedNetworkType =
+ network
+ .map {
+ if (it != null) {
+ ResolvedNetworkType.CarrierMergedNetworkType
+ } else {
+ ResolvedNetworkType.UnknownNetworkType
+ }
+ }
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ ResolvedNetworkType.UnknownNetworkType
)
- }
+ override val dataConnectionState =
+ network
+ .map {
+ if (it != null) {
+ DataConnectionState.Connected
+ } else {
+ DataConnectionState.Disconnected
+ }
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), DataConnectionState.Disconnected)
+
+ override val isRoaming = MutableStateFlow(false).asStateFlow()
+ override val isEmergencyOnly = MutableStateFlow(false).asStateFlow()
+ override val operatorAlphaShort = MutableStateFlow(null).asStateFlow()
+ override val isInService = MutableStateFlow(true).asStateFlow()
+ override val isGsm = MutableStateFlow(false).asStateFlow()
+ override val carrierNetworkChangeActive = MutableStateFlow(false).asStateFlow()
+
+ override val dataEnabled: StateFlow<Boolean> = wifiRepository.isWifiEnabled
+
+ companion object {
// Carrier merged is never roaming
private const val ROAMING = false
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
index a39ea0abce5a..b3737ecd1e0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
@@ -114,15 +114,147 @@ class FullMobileConnectionRepository(
.flatMapLatest { it.cdmaRoaming }
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.cdmaRoaming.value)
- override val connectionInfo =
+ override val isEmergencyOnly =
activeRepo
- .flatMapLatest { it.connectionInfo }
+ .flatMapLatest { it.isEmergencyOnly }
.logDiffsForTable(
tableLogBuffer,
columnPrefix = "",
- initialValue = activeRepo.value.connectionInfo.value,
+ columnName = COL_EMERGENCY,
+ activeRepo.value.isEmergencyOnly.value
+ )
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ activeRepo.value.isEmergencyOnly.value
+ )
+
+ override val isRoaming =
+ activeRepo
+ .flatMapLatest { it.isRoaming }
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ columnName = COL_ROAMING,
+ activeRepo.value.isRoaming.value
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isRoaming.value)
+
+ override val operatorAlphaShort =
+ activeRepo
+ .flatMapLatest { it.operatorAlphaShort }
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ columnName = COL_OPERATOR,
+ activeRepo.value.operatorAlphaShort.value
+ )
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ activeRepo.value.operatorAlphaShort.value
+ )
+
+ override val isInService =
+ activeRepo
+ .flatMapLatest { it.isInService }
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ columnName = COL_IS_IN_SERVICE,
+ activeRepo.value.isInService.value
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isInService.value)
+
+ override val isGsm =
+ activeRepo
+ .flatMapLatest { it.isGsm }
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ columnName = COL_IS_GSM,
+ activeRepo.value.isGsm.value
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isGsm.value)
+
+ override val cdmaLevel =
+ activeRepo
+ .flatMapLatest { it.cdmaLevel }
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ columnName = COL_CDMA_LEVEL,
+ activeRepo.value.cdmaLevel.value
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.cdmaLevel.value)
+
+ override val primaryLevel =
+ activeRepo
+ .flatMapLatest { it.primaryLevel }
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ columnName = COL_PRIMARY_LEVEL,
+ activeRepo.value.primaryLevel.value
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.primaryLevel.value)
+
+ override val dataConnectionState =
+ activeRepo
+ .flatMapLatest { it.dataConnectionState }
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ activeRepo.value.dataConnectionState.value
+ )
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ activeRepo.value.dataConnectionState.value
+ )
+
+ override val dataActivityDirection =
+ activeRepo
+ .flatMapLatest { it.dataActivityDirection }
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ activeRepo.value.dataActivityDirection.value
+ )
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ activeRepo.value.dataActivityDirection.value
+ )
+
+ override val carrierNetworkChangeActive =
+ activeRepo
+ .flatMapLatest { it.carrierNetworkChangeActive }
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ columnName = COL_CARRIER_NETWORK_CHANGE,
+ activeRepo.value.carrierNetworkChangeActive.value
+ )
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ activeRepo.value.carrierNetworkChangeActive.value
+ )
+
+ override val resolvedNetworkType =
+ activeRepo
+ .flatMapLatest { it.resolvedNetworkType }
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ activeRepo.value.resolvedNetworkType.value
+ )
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ activeRepo.value.resolvedNetworkType.value
)
- .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.connectionInfo.value)
override val dataEnabled =
activeRepo
@@ -187,4 +319,15 @@ class FullMobileConnectionRepository(
fun tableBufferLogName(subId: Int): String = "MobileConnectionLog[$subId]"
}
}
+
+ companion object {
+ const val COL_EMERGENCY = "emergencyOnly"
+ const val COL_ROAMING = "roaming"
+ const val COL_OPERATOR = "operatorName"
+ const val COL_IS_IN_SERVICE = "isInService"
+ const val COL_IS_GSM = "isGsm"
+ const val COL_CDMA_LEVEL = "cdmaLevel"
+ const val COL_PRIMARY_LEVEL = "primaryLevel"
+ const val COL_CARRIER_NETWORK_CHANGE = "carrierNetworkChangeActive"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
index 96b96f14d6aa..f1fc3868d690 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
import android.content.Context
import android.content.IntentFilter
import android.telephony.CellSignalStrength
+import android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
import android.telephony.CellSignalStrengthCdma
import android.telephony.ServiceState
import android.telephony.SignalStrength
@@ -36,7 +37,8 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Disconnected
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
@@ -47,8 +49,8 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameMo
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
-import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -62,10 +64,10 @@ import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.mapNotNull
-import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
@@ -165,83 +167,100 @@ class MobileConnectionRepositoryImpl(
}
.shareIn(scope, SharingStarted.WhileSubscribed())
- private fun updateConnectionState(
- prevState: MobileConnectionModel,
- callbackEvent: CallbackEvent,
- ): MobileConnectionModel =
- when (callbackEvent) {
- is CallbackEvent.OnServiceStateChanged -> {
- val serviceState = callbackEvent.serviceState
- prevState.copy(
- isEmergencyOnly = serviceState.isEmergencyOnly,
- isRoaming = serviceState.roaming,
- operatorAlphaShort = serviceState.operatorAlphaShort,
- isInService = Utils.isInService(serviceState),
- )
- }
- is CallbackEvent.OnSignalStrengthChanged -> {
- val signalStrength = callbackEvent.signalStrength
- val cdmaLevel =
- signalStrength.getCellSignalStrengths(CellSignalStrengthCdma::class.java).let {
- strengths ->
- if (!strengths.isEmpty()) {
- strengths[0].level
- } else {
- CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
- }
- }
+ override val isEmergencyOnly =
+ callbackEvents
+ .filterIsInstance<CallbackEvent.OnServiceStateChanged>()
+ .map { it.serviceState.isEmergencyOnly }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
- val primaryLevel = signalStrength.level
+ override val isRoaming =
+ callbackEvents
+ .filterIsInstance<CallbackEvent.OnServiceStateChanged>()
+ .map { it.serviceState.roaming }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
- prevState.copy(
- cdmaLevel = cdmaLevel,
- primaryLevel = primaryLevel,
- isGsm = signalStrength.isGsm,
- )
- }
- is CallbackEvent.OnDataConnectionStateChanged -> {
- prevState.copy(dataConnectionState = callbackEvent.dataState.toDataConnectionType())
- }
- is CallbackEvent.OnDataActivity -> {
- prevState.copy(
- dataActivityDirection = callbackEvent.direction.toMobileDataActivityModel()
- )
- }
- is CallbackEvent.OnCarrierNetworkChange -> {
- prevState.copy(carrierNetworkChangeActive = callbackEvent.active)
- }
- is CallbackEvent.OnDisplayInfoChanged -> {
- val telephonyDisplayInfo = callbackEvent.telephonyDisplayInfo
- val networkType =
- if (telephonyDisplayInfo.networkType == NETWORK_TYPE_UNKNOWN) {
- UnknownNetworkType
- } else if (
- telephonyDisplayInfo.overrideNetworkType == OVERRIDE_NETWORK_TYPE_NONE
- ) {
- DefaultNetworkType(
- mobileMappingsProxy.toIconKey(telephonyDisplayInfo.networkType)
- )
+ override val operatorAlphaShort =
+ callbackEvents
+ .filterIsInstance<CallbackEvent.OnServiceStateChanged>()
+ .map { it.serviceState.operatorAlphaShort }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+ override val isInService =
+ callbackEvents
+ .filterIsInstance<CallbackEvent.OnServiceStateChanged>()
+ .map { Utils.isInService(it.serviceState) }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+ override val isGsm =
+ callbackEvents
+ .filterIsInstance<CallbackEvent.OnSignalStrengthChanged>()
+ .map { it.signalStrength.isGsm }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+ override val cdmaLevel =
+ callbackEvents
+ .filterIsInstance<CallbackEvent.OnSignalStrengthChanged>()
+ .map {
+ it.signalStrength.getCellSignalStrengths(CellSignalStrengthCdma::class.java).let {
+ strengths ->
+ if (strengths.isNotEmpty()) {
+ strengths[0].level
} else {
- OverrideNetworkType(
- mobileMappingsProxy.toIconKeyOverride(
- telephonyDisplayInfo.overrideNetworkType
- )
- )
+ CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
}
- prevState.copy(resolvedNetworkType = networkType)
- }
- is CallbackEvent.OnDataEnabledChanged -> {
- // Not part of this object, handled in a separate flow
- prevState
+ }
}
- }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
- override val connectionInfo = run {
- val initial = MobileConnectionModel()
+ override val primaryLevel =
callbackEvents
- .scan(initial, ::updateConnectionState)
- .stateIn(scope, SharingStarted.WhileSubscribed(), initial)
- }
+ .filterIsInstance<CallbackEvent.OnSignalStrengthChanged>()
+ .map { it.signalStrength.level }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+
+ override val dataConnectionState =
+ callbackEvents
+ .filterIsInstance<CallbackEvent.OnDataConnectionStateChanged>()
+ .map { it.dataState.toDataConnectionType() }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), Disconnected)
+
+ override val dataActivityDirection =
+ callbackEvents
+ .filterIsInstance<CallbackEvent.OnDataActivity>()
+ .map { it.direction.toMobileDataActivityModel() }
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ DataActivityModel(hasActivityIn = false, hasActivityOut = false)
+ )
+
+ override val carrierNetworkChangeActive =
+ callbackEvents
+ .filterIsInstance<CallbackEvent.OnCarrierNetworkChange>()
+ .map { it.active }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+ override val resolvedNetworkType =
+ callbackEvents
+ .filterIsInstance<CallbackEvent.OnDisplayInfoChanged>()
+ .map {
+ if (it.telephonyDisplayInfo.networkType == NETWORK_TYPE_UNKNOWN) {
+ UnknownNetworkType
+ } else if (
+ it.telephonyDisplayInfo.overrideNetworkType == OVERRIDE_NETWORK_TYPE_NONE
+ ) {
+ DefaultNetworkType(
+ mobileMappingsProxy.toIconKey(it.telephonyDisplayInfo.networkType)
+ )
+ } else {
+ OverrideNetworkType(
+ mobileMappingsProxy.toIconKeyOverride(
+ it.telephonyDisplayInfo.overrideNetworkType
+ )
+ )
+ }
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), UnknownNetworkType)
override val numberOfLevels =
systemUiCarrierConfig.shouldInflateSignalStrength
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index b3d5b1e7e450..b7da3f27c70a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -45,11 +45,11 @@ import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
-import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
@@ -266,6 +266,7 @@ constructor(
val callback =
object : NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
override fun onLost(network: Network) {
+ logger.logOnLost(network, isDefaultNetworkCallback = true)
// Send a disconnected model when lost. Maybe should create a sealed
// type or null here?
trySend(MobileConnectivityModel())
@@ -275,6 +276,11 @@ constructor(
network: Network,
caps: NetworkCapabilities
) {
+ logger.logOnCapabilitiesChanged(
+ network,
+ caps,
+ isDefaultNetworkCallback = true,
+ )
trySend(
MobileConnectivityModel(
isConnected = caps.hasTransport(TRANSPORT_CELLULAR),
@@ -353,8 +359,8 @@ constructor(
* True if the checked subId is in the list of current subs or the active mobile data subId
*
* @param checkedSubs the list to validate [subId] against. To invalidate the cache, pass in the
- * new subscription list. Otherwise use [subscriptions.value] to validate a subId against the
- * current known subscriptions
+ * new subscription list. Otherwise use [subscriptions.value] to validate a subId against the
+ * current known subscriptions
*/
private fun checkSub(subId: Int, checkedSubs: List<SubscriptionModel>): Boolean {
if (activeMobileDataSubscriptionId.value == subId) return true
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
index 7b0f95271d63..7df6764fda1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
@@ -34,6 +34,7 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
@@ -92,7 +93,8 @@ interface MobileIconInteractor {
* 1. The default network name, if one is configured
* 2. A derived name based off of the intent [ACTION_SERVICE_PROVIDERS_UPDATED]
* 3. Or, in the case where the repository sends us the default network name, we check for an
- * override in [connectionInfo.operatorAlphaShort], a value that is derived from [ServiceState]
+ * override in [connectionInfo.operatorAlphaShort], a value that is derived from
+ * [ServiceState]
*/
val networkName: StateFlow<NetworkNameModel>
@@ -132,11 +134,9 @@ class MobileIconInteractorImpl(
override val isForceHidden: Flow<Boolean>,
connectionRepository: MobileConnectionRepository,
) : MobileIconInteractor {
- private val connectionInfo = connectionRepository.connectionInfo
-
override val tableLogBuffer: TableLogBuffer = connectionRepository.tableLogBuffer
- override val activity = connectionInfo.mapLatest { it.dataActivityDirection }
+ override val activity = connectionRepository.dataActivityDirection
override val isConnected: Flow<Boolean> = defaultMobileConnectivity.mapLatest { it.isConnected }
@@ -154,11 +154,11 @@ class MobileIconInteractorImpl(
override val isDefaultDataEnabled = defaultSubscriptionHasDataEnabled
override val networkName =
- combine(connectionInfo, connectionRepository.networkName) { connection, networkName ->
- if (
- networkName is NetworkNameModel.Default && connection.operatorAlphaShort != null
- ) {
- NetworkNameModel.IntentDerived(connection.operatorAlphaShort)
+ combine(connectionRepository.operatorAlphaShort, connectionRepository.networkName) {
+ operatorAlphaShort,
+ networkName ->
+ if (networkName is NetworkNameModel.Default && operatorAlphaShort != null) {
+ NetworkNameModel.IntentDerived(operatorAlphaShort)
} else {
networkName
}
@@ -172,19 +172,19 @@ class MobileIconInteractorImpl(
/** Observable for the current RAT indicator icon ([MobileIconGroup]) */
override val networkTypeIconGroup: StateFlow<MobileIconGroup> =
combine(
- connectionInfo,
+ connectionRepository.resolvedNetworkType,
defaultMobileIconMapping,
defaultMobileIconGroup,
isDefault,
- ) { info, mapping, defaultGroup, isDefault ->
+ ) { resolvedNetworkType, mapping, defaultGroup, isDefault ->
if (!isDefault) {
return@combine NOT_DEFAULT_DATA
}
- when (info.resolvedNetworkType) {
+ when (resolvedNetworkType) {
is ResolvedNetworkType.CarrierMergedNetworkType ->
- info.resolvedNetworkType.iconGroupOverride
- else -> mapping[info.resolvedNetworkType.lookupKey] ?: defaultGroup
+ resolvedNetworkType.iconGroupOverride
+ else -> mapping[resolvedNetworkType.lookupKey] ?: defaultGroup
}
}
.distinctUntilChanged()
@@ -199,17 +199,19 @@ class MobileIconInteractorImpl(
}
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultMobileIconGroup.value)
- override val isEmergencyOnly: StateFlow<Boolean> =
- connectionInfo
- .mapLatest { it.isEmergencyOnly }
- .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+ override val isEmergencyOnly = connectionRepository.isEmergencyOnly
override val isRoaming: StateFlow<Boolean> =
- combine(connectionInfo, connectionRepository.cdmaRoaming) { connection, cdmaRoaming ->
- if (connection.carrierNetworkChangeActive) {
+ combine(
+ connectionRepository.carrierNetworkChangeActive,
+ connectionRepository.isGsm,
+ connectionRepository.isRoaming,
+ connectionRepository.cdmaRoaming,
+ ) { carrierNetworkChangeActive, isGsm, isRoaming, cdmaRoaming ->
+ if (carrierNetworkChangeActive) {
false
- } else if (connection.isGsm) {
- connection.isRoaming
+ } else if (isGsm) {
+ isRoaming
} else {
cdmaRoaming
}
@@ -217,12 +219,17 @@ class MobileIconInteractorImpl(
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
override val level: StateFlow<Int> =
- combine(connectionInfo, alwaysUseCdmaLevel) { connection, alwaysUseCdmaLevel ->
+ combine(
+ connectionRepository.isGsm,
+ connectionRepository.primaryLevel,
+ connectionRepository.cdmaLevel,
+ alwaysUseCdmaLevel,
+ ) { isGsm, primaryLevel, cdmaLevel, alwaysUseCdmaLevel ->
when {
// GSM connections should never use the CDMA level
- connection.isGsm -> connection.primaryLevel
- alwaysUseCdmaLevel -> connection.cdmaLevel
- else -> connection.primaryLevel
+ isGsm -> primaryLevel
+ alwaysUseCdmaLevel -> cdmaLevel
+ else -> primaryLevel
}
}
.stateIn(scope, SharingStarted.WhileSubscribed(), 0)
@@ -235,12 +242,9 @@ class MobileIconInteractorImpl(
)
override val isDataConnected: StateFlow<Boolean> =
- connectionInfo
- .mapLatest { connection -> connection.dataConnectionState == Connected }
+ connectionRepository.dataConnectionState
+ .map { it == Connected }
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
- override val isInService =
- connectionRepository.connectionInfo
- .mapLatest { it.isInService }
- .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+ override val isInService = connectionRepository.isInService
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
index da63ab10f733..075e6ec11ae7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
@@ -22,7 +22,6 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.statusbar.phone.StatusBarIconController
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
-import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
import java.io.PrintWriter
import javax.inject.Inject
@@ -55,17 +54,14 @@ constructor(
interactor: MobileIconsInteractor,
private val iconController: StatusBarIconController,
private val iconsViewModelFactory: MobileIconsViewModel.Factory,
- private val logger: MobileInputLogger,
+ private val logger: MobileViewLogger,
@Application private val scope: CoroutineScope,
private val statusBarPipelineFlags: StatusBarPipelineFlags,
) : CoreStartable {
private val mobileSubIds: Flow<List<Int>> =
- interactor.filteredSubscriptions
- .mapLatest { subscriptions ->
- subscriptions.map { subscriptionModel -> subscriptionModel.subscriptionId }
- }
- .distinctUntilChanged()
- .onEach { logger.logUiAdapterSubIdsUpdated(it) }
+ interactor.filteredSubscriptions.mapLatest { subscriptions ->
+ subscriptions.map { subscriptionModel -> subscriptionModel.subscriptionId }
+ }
/**
* We expose the list of tracked subscriptions as a flow of a list of ints, where each int is
@@ -75,7 +71,10 @@ constructor(
* NOTE: this should go away as the view presenter learns more about this data pipeline
*/
private val mobileSubIdsState: StateFlow<List<Int>> =
- mobileSubIds.stateIn(scope, SharingStarted.WhileSubscribed(), listOf())
+ mobileSubIds
+ .distinctUntilChanged()
+ .onEach { logger.logUiAdapterSubIdsUpdated(it) }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), listOf())
/** In order to keep the logs tame, we will reuse the same top-level mobile icons view model */
val mobileIconsViewModel = iconsViewModelFactory.create(mobileSubIdsState)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
new file mode 100644
index 000000000000..90dff23c637c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
@@ -0,0 +1,118 @@
+/*
+ * 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.pipeline.mobile.ui
+
+import android.view.View
+import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.statusbar.pipeline.dagger.MobileViewLog
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
+import java.io.PrintWriter
+import javax.inject.Inject
+
+/** Logs for changes with the new mobile views. */
+@SysUISingleton
+class MobileViewLogger
+@Inject
+constructor(
+ @MobileViewLog private val buffer: LogBuffer,
+ dumpManager: DumpManager,
+) : Dumpable {
+ init {
+ dumpManager.registerNormalDumpable(this)
+ }
+
+ private val collectionStatuses = mutableMapOf<String, Boolean>()
+
+ fun logUiAdapterSubIdsUpdated(subs: List<Int>) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ { str1 = subs.toString() },
+ { "Sub IDs in MobileUiAdapter updated internally: $str1" },
+ )
+ }
+
+ fun logUiAdapterSubIdsSentToIconController(subs: List<Int>) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ { str1 = subs.toString() },
+ { "Sub IDs in MobileUiAdapter being sent to icon controller: $str1" },
+ )
+ }
+
+ fun logNewViewBinding(view: View, viewModel: LocationBasedMobileViewModel) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ str1 = view.getIdForLogging()
+ str2 = viewModel.getIdForLogging()
+ str3 = viewModel.locationName
+ },
+ { "New view binding. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" },
+ )
+ }
+
+ fun logCollectionStarted(view: View, viewModel: LocationBasedMobileViewModel) {
+ collectionStatuses[view.getIdForLogging()] = true
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ str1 = view.getIdForLogging()
+ str2 = viewModel.getIdForLogging()
+ str3 = viewModel.locationName
+ },
+ { "Collection started. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" },
+ )
+ }
+
+ fun logCollectionStopped(view: View, viewModel: LocationBasedMobileViewModel) {
+ collectionStatuses[view.getIdForLogging()] = false
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ str1 = view.getIdForLogging()
+ str2 = viewModel.getIdForLogging()
+ str3 = viewModel.locationName
+ },
+ { "Collection stopped. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" },
+ )
+ }
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ pw.println("Collection statuses per view:---")
+ collectionStatuses.forEach { viewId, isCollecting ->
+ pw.println("viewId=$viewId, isCollecting=$isCollecting")
+ }
+ }
+
+ companion object {
+ fun Any.getIdForLogging(): String {
+ // The identityHashCode is guaranteed to be constant for the lifetime of the object.
+ return Integer.toHexString(System.identityHashCode(this))
+ }
+ }
+}
+
+private const val TAG = "MobileViewLogger"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt
new file mode 100644
index 000000000000..f67bc8f14447
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.pipeline.mobile.ui
+
+import android.view.View
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.statusbar.pipeline.dagger.VerboseMobileViewLog
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger.Companion.getIdForLogging
+import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel
+import javax.inject.Inject
+
+/**
+ * Logs for **verbose** changes with the new mobile views.
+ *
+ * This is a hopefully temporary log until we resolve some open bugs (b/267236367, b/269565345,
+ * b/270300839).
+ */
+@SysUISingleton
+class VerboseMobileViewLogger
+@Inject
+constructor(
+ @VerboseMobileViewLog private val buffer: LogBuffer,
+) {
+ fun logBinderReceivedSignalIcon(parentView: View, subId: Int, icon: SignalIconModel) {
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ str1 = parentView.getIdForLogging()
+ int1 = subId
+ int2 = icon.level
+ bool1 = icon.showExclamationMark
+ },
+ {
+ "Binder[subId=$int1, viewId=$str1] received new signal icon: " +
+ "level=$int2 showExclamation=$bool1"
+ },
+ )
+ }
+
+ fun logBinderReceivedNetworkTypeIcon(parentView: View, subId: Int, icon: Icon.Resource?) {
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ str1 = parentView.getIdForLogging()
+ int1 = subId
+ bool1 = icon != null
+ int2 = icon?.res ?: -1
+ },
+ {
+ "Binder[subId=$int1, viewId=$str1] received new network type icon: " +
+ if (bool1) "resId=$int2" else "null"
+ },
+ )
+ }
+}
+
+private const val TAG = "VerboseMobileViewLogger"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
index db585e68d185..5b7d45b55c5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
@@ -36,8 +36,10 @@ import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarViewBinding
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
@@ -48,6 +50,7 @@ object MobileIconBinder {
fun bind(
view: ViewGroup,
viewModel: LocationBasedMobileViewModel,
+ logger: MobileViewLogger,
): ModernStatusBarViewBinding {
val mobileGroupView = view.requireViewById<ViewGroup>(R.id.mobile_group)
val activityContainer = view.requireViewById<View>(R.id.inout_container)
@@ -70,8 +73,13 @@ object MobileIconBinder {
val iconTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
val decorTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
+ var isCollecting: Boolean = false
+
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
+ logger.logCollectionStarted(view, viewModel)
+ isCollecting = true
+
launch {
visibilityState.collect { state ->
when (state) {
@@ -96,6 +104,11 @@ object MobileIconBinder {
// Set the icon for the triangle
launch {
viewModel.icon.distinctUntilChanged().collect { icon ->
+ viewModel.verboseLogger?.logBinderReceivedSignalIcon(
+ view,
+ viewModel.subscriptionId,
+ icon,
+ )
mobileDrawable.level =
SignalDrawable.getState(
icon.level,
@@ -114,6 +127,11 @@ object MobileIconBinder {
// Set the network type icon
launch {
viewModel.networkTypeIcon.distinctUntilChanged().collect { dataTypeId ->
+ viewModel.verboseLogger?.logBinderReceivedNetworkTypeIcon(
+ view,
+ viewModel.subscriptionId,
+ dataTypeId,
+ )
dataTypeId?.let { IconViewBinder.bind(dataTypeId, networkTypeView) }
networkTypeView.visibility = if (dataTypeId != null) VISIBLE else GONE
}
@@ -150,6 +168,13 @@ object MobileIconBinder {
}
launch { decorTint.collect { tint -> dotView.setDecorColor(tint) } }
+
+ try {
+ awaitCancellation()
+ } finally {
+ isCollecting = false
+ logger.logCollectionStopped(view, viewModel)
+ }
}
}
@@ -175,6 +200,10 @@ object MobileIconBinder {
}
decorTint.value = newTint
}
+
+ override fun isCollecting(): Boolean {
+ return isCollecting
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
index ed9a1884a7b4..4144293d5ccd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
@@ -20,6 +20,8 @@ import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import com.android.systemui.R
+import com.android.systemui.statusbar.StatusBarIconView.getVisibleStateString
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconBinder
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarView
@@ -31,6 +33,15 @@ class ModernStatusBarMobileView(
var subId: Int = -1
+ override fun toString(): String {
+ return "ModernStatusBarMobileView(" +
+ "slot='$slot', " +
+ "subId=$subId, " +
+ "isCollecting=${binding.isCollecting()}, " +
+ "visibleState=${getVisibleStateString(visibleState)}); " +
+ "viewString=${super.toString()}"
+ }
+
companion object {
/**
@@ -40,6 +51,7 @@ class ModernStatusBarMobileView(
@JvmStatic
fun constructAndBind(
context: Context,
+ logger: MobileViewLogger,
slot: String,
viewModel: LocationBasedMobileViewModel,
): ModernStatusBarMobileView {
@@ -48,7 +60,8 @@ class ModernStatusBarMobileView(
as ModernStatusBarMobileView)
.also {
it.subId = viewModel.subscriptionId
- it.initView(slot) { MobileIconBinder.bind(it, viewModel) }
+ it.initView(slot) { MobileIconBinder.bind(it, viewModel, logger) }
+ logger.logNewViewBinding(it, viewModel)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt
index 24cd9304f8dd..f775940140cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt
@@ -19,18 +19,23 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
import android.graphics.Color
import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
/**
* A view model for an individual mobile icon that embeds the notion of a [StatusBarLocation]. This
* allows the mobile icon to change some view parameters at different locations
*
* @param commonImpl for convenience, this class wraps a base interface that can provides all of the
- * common implementations between locations. See [MobileIconViewModel]
+ * common implementations between locations. See [MobileIconViewModel]
+ * @property locationName the name of the location of this VM, used for logging.
+ * @property verboseLogger an optional logger to log extremely verbose view updates.
*/
abstract class LocationBasedMobileViewModel(
val commonImpl: MobileIconViewModelCommon,
statusBarPipelineFlags: StatusBarPipelineFlags,
debugTint: Int,
+ val locationName: String,
+ val verboseLogger: VerboseMobileViewLogger?,
) : MobileIconViewModelCommon by commonImpl {
val useDebugColoring: Boolean = statusBarPipelineFlags.useDebugColoring()
@@ -45,11 +50,16 @@ abstract class LocationBasedMobileViewModel(
fun viewModelForLocation(
commonImpl: MobileIconViewModelCommon,
statusBarPipelineFlags: StatusBarPipelineFlags,
+ verboseMobileViewLogger: VerboseMobileViewLogger,
loc: StatusBarLocation,
): LocationBasedMobileViewModel =
when (loc) {
StatusBarLocation.HOME ->
- HomeMobileIconViewModel(commonImpl, statusBarPipelineFlags)
+ HomeMobileIconViewModel(
+ commonImpl,
+ statusBarPipelineFlags,
+ verboseMobileViewLogger,
+ )
StatusBarLocation.KEYGUARD ->
KeyguardMobileIconViewModel(commonImpl, statusBarPipelineFlags)
StatusBarLocation.QS -> QsMobileIconViewModel(commonImpl, statusBarPipelineFlags)
@@ -60,20 +70,41 @@ abstract class LocationBasedMobileViewModel(
class HomeMobileIconViewModel(
commonImpl: MobileIconViewModelCommon,
statusBarPipelineFlags: StatusBarPipelineFlags,
+ verboseMobileViewLogger: VerboseMobileViewLogger,
) :
MobileIconViewModelCommon,
- LocationBasedMobileViewModel(commonImpl, statusBarPipelineFlags, debugTint = Color.CYAN)
+ LocationBasedMobileViewModel(
+ commonImpl,
+ statusBarPipelineFlags,
+ debugTint = Color.CYAN,
+ locationName = "Home",
+ verboseMobileViewLogger,
+ )
class QsMobileIconViewModel(
commonImpl: MobileIconViewModelCommon,
statusBarPipelineFlags: StatusBarPipelineFlags,
) :
MobileIconViewModelCommon,
- LocationBasedMobileViewModel(commonImpl, statusBarPipelineFlags, debugTint = Color.GREEN)
+ LocationBasedMobileViewModel(
+ commonImpl,
+ statusBarPipelineFlags,
+ debugTint = Color.GREEN,
+ locationName = "QS",
+ // Only do verbose logging for the Home location.
+ verboseLogger = null,
+ )
class KeyguardMobileIconViewModel(
commonImpl: MobileIconViewModelCommon,
statusBarPipelineFlags: StatusBarPipelineFlags,
) :
MobileIconViewModelCommon,
- LocationBasedMobileViewModel(commonImpl, statusBarPipelineFlags, debugTint = Color.MAGENTA)
+ LocationBasedMobileViewModel(
+ commonImpl,
+ statusBarPipelineFlags,
+ debugTint = Color.MAGENTA,
+ locationName = "Keyguard",
+ // Only do verbose logging for the Home location.
+ verboseLogger = null,
+ )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
index 049627899eff..dbb534b24471 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
@@ -49,7 +49,7 @@ interface MobileIconViewModelCommon {
val contentDescription: Flow<ContentDescription>
val roaming: Flow<Boolean>
/** The RAT icon (LTE, 3G, 5G, etc) to be displayed. Null if we shouldn't show anything */
- val networkTypeIcon: Flow<Icon?>
+ val networkTypeIcon: Flow<Icon.Resource?>
val activityInVisible: Flow<Boolean>
val activityOutVisible: Flow<Boolean>
val activityContainerVisible: Flow<Boolean>
@@ -161,7 +161,7 @@ constructor(
)
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
- override val networkTypeIcon: Flow<Icon?> =
+ override val networkTypeIcon: Flow<Icon.Resource?> =
combine(
iconInteractor.networkTypeIconGroup,
showNetworkTypeIcon,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
index 8cb52af336da..2b90065284d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
@@ -23,6 +23,8 @@ import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
+import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
import javax.inject.Inject
@@ -39,6 +41,8 @@ class MobileIconsViewModel
@Inject
constructor(
val subscriptionIdsFlow: StateFlow<List<Int>>,
+ val logger: MobileViewLogger,
+ private val verboseLogger: VerboseMobileViewLogger,
private val interactor: MobileIconsInteractor,
private val airplaneModeInteractor: AirplaneModeInteractor,
private val constants: ConnectivityConstants,
@@ -66,6 +70,7 @@ constructor(
return LocationBasedMobileViewModel.viewModelForLocation(
common,
statusBarPipelineFlags,
+ verboseLogger,
location,
)
}
@@ -79,6 +84,8 @@ constructor(
class Factory
@Inject
constructor(
+ private val logger: MobileViewLogger,
+ private val verboseLogger: VerboseMobileViewLogger,
private val interactor: MobileIconsInteractor,
private val airplaneModeInteractor: AirplaneModeInteractor,
private val constants: ConnectivityConstants,
@@ -88,6 +95,8 @@ constructor(
fun create(subscriptionIdsFlow: StateFlow<List<Int>>): MobileIconsViewModel {
return MobileIconsViewModel(
subscriptionIdsFlow,
+ logger,
+ verboseLogger,
interactor,
airplaneModeInteractor,
constants,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
index 6f29e33b5a17..a96e8ff20dd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
@@ -38,11 +38,24 @@ object LoggerHelper {
int1 = network.getNetId()
str1 = networkCapabilities.toString()
},
- { "onCapabilitiesChanged[default=$bool1]: net=$int1 capabilities=$str1" }
+ { "on${if (bool1) "Default" else ""}CapabilitiesChanged: net=$int1 capabilities=$str1" }
)
}
- fun logOnLost(buffer: LogBuffer, tag: String, network: Network) {
- buffer.log(tag, LogLevel.INFO, { int1 = network.getNetId() }, { "onLost: net=$int1" })
+ fun logOnLost(
+ buffer: LogBuffer,
+ tag: String,
+ network: Network,
+ isDefaultNetworkCallback: Boolean,
+ ) {
+ buffer.log(
+ tag,
+ LogLevel.INFO,
+ {
+ int1 = network.getNetId()
+ bool1 = isDefaultNetworkCallback
+ },
+ { "on${if (bool1) "Default" else ""}Lost: net=$int1" }
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/ModernStatusBarViewBinding.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/ModernStatusBarViewBinding.kt
index f67876b50233..81f8683411ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/ModernStatusBarViewBinding.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/ModernStatusBarViewBinding.kt
@@ -37,4 +37,7 @@ interface ModernStatusBarViewBinding {
/** Notifies that the decor tint has been updated (used only for the dot). */
fun onDecorTintChanged(newTint: Int)
+
+ /** Returns true if the binding between the view and view-model is currently collecting. */
+ fun isCollecting(): Boolean
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt
index b1e28129a690..1a1340484bfc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt
@@ -36,7 +36,7 @@ open class ModernStatusBarView(context: Context, attrs: AttributeSet?) :
BaseStatusBarFrameLayout(context, attrs) {
private lateinit var slot: String
- private lateinit var binding: ModernStatusBarViewBinding
+ internal lateinit var binding: ModernStatusBarViewBinding
@StatusBarIconView.VisibleState
private var iconVisibleState: Int = STATE_HIDDEN
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt
index e0e0ed795e4a..b1296179d7f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt
@@ -41,7 +41,6 @@ import kotlinx.coroutines.flow.stateIn
* or the [WifiRepositoryImpl]'s prod implementation, based on the current demo mode value. In this
* way, downstream clients can all consist of real implementations and not care about which
* repository is responsible for the data. Graphically:
- *
* ```
* RealRepository
* │
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
index ee58160a7d3b..b5e7b7a13505 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
@@ -128,6 +128,7 @@ constructor(
}
override fun onLost(network: Network) {
+ logger.logOnLost(network, isDefaultNetworkCallback = true)
// The system no longer has a default network, so wifi is definitely not
// default.
trySend(false)
@@ -179,7 +180,7 @@ constructor(
}
override fun onLost(network: Network) {
- logger.logOnLost(network)
+ logger.logOnLost(network, isDefaultNetworkCallback = false)
wifiNetworkChangeEvents.tryEmit(Unit)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
index a32e47592355..bb0b166f7aba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
@@ -48,8 +48,8 @@ constructor(
)
}
- fun logOnLost(network: Network) {
- LoggerHelper.logOnLost(buffer, TAG, network)
+ fun logOnLost(network: Network, isDefaultNetworkCallback: Boolean) {
+ LoggerHelper.logOnLost(buffer, TAG, network, isDefaultNetworkCallback)
}
fun logIntent(intentName: String) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
index 2aff12c8721d..9e8c814ca2a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
@@ -34,6 +34,7 @@ import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarV
import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel
import kotlinx.coroutines.InternalCoroutinesApi
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -74,8 +75,12 @@ object WifiViewBinder {
val iconTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
val decorTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
+ var isCollecting: Boolean = false
+
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
+ isCollecting = true
+
launch {
visibilityState.collect { visibilityState ->
groupView.isVisible = visibilityState == STATE_ICON
@@ -127,6 +132,12 @@ object WifiViewBinder {
airplaneSpacer.isVisible = visible
}
}
+
+ try {
+ awaitCancellation()
+ } finally {
+ isCollecting = false
+ }
}
}
@@ -152,6 +163,10 @@ object WifiViewBinder {
}
decorTint.value = newTint
}
+
+ override fun isCollecting(): Boolean {
+ return isCollecting
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
index 7a734862fe1b..f23e10287164 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
@@ -21,6 +21,7 @@ import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import com.android.systemui.R
+import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarView
import com.android.systemui.statusbar.pipeline.wifi.ui.binder.WifiViewBinder
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel
@@ -33,6 +34,15 @@ class ModernStatusBarWifiView(
context: Context,
attrs: AttributeSet?,
) : ModernStatusBarView(context, attrs) {
+
+ override fun toString(): String {
+ return "ModernStatusBarWifiView(" +
+ "slot='$slot', " +
+ "isCollecting=${binding.isCollecting()}, " +
+ "visibleState=${StatusBarIconView.getVisibleStateString(visibleState)}); " +
+ "viewString=${super.toString()}"
+ }
+
companion object {
/**
* Inflates a new instance of [ModernStatusBarWifiView], binds it to a view model, and
@@ -45,12 +55,9 @@ class ModernStatusBarWifiView(
slot: String,
wifiViewModel: LocationBasedWifiViewModel,
): ModernStatusBarWifiView {
- return (
- LayoutInflater.from(context).inflate(R.layout.new_status_bar_wifi_group, null)
- as ModernStatusBarWifiView
- ).also {
- it.initView(slot) { WifiViewBinder.bind(it, wifiViewModel) }
- }
+ return (LayoutInflater.from(context).inflate(R.layout.new_status_bar_wifi_group, null)
+ as ModernStatusBarWifiView)
+ .also { it.initView(slot) { WifiViewBinder.bind(it, wifiViewModel) } }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
index 7acdaffb48c4..01fabcc8bc1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
@@ -22,13 +22,18 @@ import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_LOCKED
import android.annotation.Nullable;
import android.hardware.devicestate.DeviceStateManager;
import android.os.Trace;
-import android.util.Log;
+import android.util.IndentingPrintWriter;
+
+import androidx.annotation.NonNull;
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
+import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.util.wrapper.RotationPolicyWrapper;
+import java.io.PrintWriter;
import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -39,19 +44,19 @@ import javax.inject.Inject;
*/
@SysUISingleton
public final class DeviceStateRotationLockSettingController
- implements Listenable, RotationLockController.RotationLockControllerCallback {
-
- private static final String TAG = "DSRotateLockSettingCon";
+ implements Listenable, RotationLockController.RotationLockControllerCallback, Dumpable {
private final RotationPolicyWrapper mRotationPolicyWrapper;
private final DeviceStateManager mDeviceStateManager;
private final Executor mMainExecutor;
private final DeviceStateRotationLockSettingsManager mDeviceStateRotationLockSettingsManager;
+ private final DeviceStateRotationLockSettingControllerLogger mLogger;
// On registration for DeviceStateCallback, we will receive a callback with the current state
// and this will be initialized.
private int mDeviceState = -1;
- @Nullable private DeviceStateManager.DeviceStateCallback mDeviceStateCallback;
+ @Nullable
+ private DeviceStateManager.DeviceStateCallback mDeviceStateCallback;
private DeviceStateRotationLockSettingsManager.DeviceStateRotationLockSettingsListener
mDeviceStateRotationLockSettingsListener;
@@ -60,21 +65,27 @@ public final class DeviceStateRotationLockSettingController
RotationPolicyWrapper rotationPolicyWrapper,
DeviceStateManager deviceStateManager,
@Main Executor executor,
- DeviceStateRotationLockSettingsManager deviceStateRotationLockSettingsManager) {
+ DeviceStateRotationLockSettingsManager deviceStateRotationLockSettingsManager,
+ DeviceStateRotationLockSettingControllerLogger logger,
+ DumpManager dumpManager) {
mRotationPolicyWrapper = rotationPolicyWrapper;
mDeviceStateManager = deviceStateManager;
mMainExecutor = executor;
mDeviceStateRotationLockSettingsManager = deviceStateRotationLockSettingsManager;
+ mLogger = logger;
+ dumpManager.registerDumpable(this);
}
@Override
public void setListening(boolean listening) {
+ mLogger.logListeningChange(listening);
if (listening) {
// Note that this is called once with the initial state of the device, even if there
// is no user action.
mDeviceStateCallback = this::updateDeviceState;
mDeviceStateManager.registerCallback(mMainExecutor, mDeviceStateCallback);
- mDeviceStateRotationLockSettingsListener = () -> readPersistedSetting(mDeviceState);
+ mDeviceStateRotationLockSettingsListener = () ->
+ readPersistedSetting("deviceStateRotationLockChange", mDeviceState);
mDeviceStateRotationLockSettingsManager.registerListener(
mDeviceStateRotationLockSettingsListener);
} else {
@@ -89,35 +100,28 @@ public final class DeviceStateRotationLockSettingController
}
@Override
- public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
- if (mDeviceState == -1) {
- Log.wtf(TAG, "Device state was not initialized.");
+ public void onRotationLockStateChanged(boolean newRotationLocked, boolean affordanceVisible) {
+ int deviceState = mDeviceState;
+ boolean currentRotationLocked = mDeviceStateRotationLockSettingsManager
+ .isRotationLocked(deviceState);
+ mLogger.logRotationLockStateChanged(deviceState, newRotationLocked, currentRotationLocked);
+ if (deviceState == -1) {
return;
}
-
- if (rotationLocked
- == mDeviceStateRotationLockSettingsManager.isRotationLocked(mDeviceState)) {
- Log.v(TAG, "Rotation lock same as the current setting, no need to update.");
+ if (newRotationLocked == currentRotationLocked) {
return;
}
-
- saveNewRotationLockSetting(rotationLocked);
+ saveNewRotationLockSetting(newRotationLocked);
}
private void saveNewRotationLockSetting(boolean isRotationLocked) {
- Log.v(
- TAG,
- "saveNewRotationLockSetting [state="
- + mDeviceState
- + "] [isRotationLocked="
- + isRotationLocked
- + "]");
-
- mDeviceStateRotationLockSettingsManager.updateSetting(mDeviceState, isRotationLocked);
+ int deviceState = mDeviceState;
+ mLogger.logSaveNewRotationLockSetting(isRotationLocked, deviceState);
+ mDeviceStateRotationLockSettingsManager.updateSetting(deviceState, isRotationLocked);
}
private void updateDeviceState(int state) {
- Log.v(TAG, "updateDeviceState [state=" + state + "]");
+ mLogger.logUpdateDeviceState(mDeviceState, state);
if (Trace.isEnabled()) {
Trace.traceBegin(
Trace.TRACE_TAG_APP, "updateDeviceState [state=" + state + "]");
@@ -127,22 +131,26 @@ public final class DeviceStateRotationLockSettingController
return;
}
- readPersistedSetting(state);
+ readPersistedSetting("updateDeviceState", state);
} finally {
Trace.endSection();
}
}
- private void readPersistedSetting(int state) {
+ private void readPersistedSetting(String caller, int state) {
int rotationLockSetting =
mDeviceStateRotationLockSettingsManager.getRotationLockSetting(state);
+ boolean shouldBeLocked = rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_LOCKED;
+ boolean isLocked = mRotationPolicyWrapper.isRotationLocked();
+
+ mLogger.readPersistedSetting(caller, state, rotationLockSetting, shouldBeLocked, isLocked);
+
if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) {
// This should not happen. Device states that have an ignored setting, should also
// specify a fallback device state which is not ignored.
// We won't handle this device state. The same rotation lock setting as before should
// apply and any changes to the rotation lock setting will be written for the previous
// valid device state.
- Log.w(TAG, "Missing fallback. Ignoring new device state: " + state);
return;
}
@@ -150,9 +158,18 @@ public final class DeviceStateRotationLockSettingController
mDeviceState = state;
// Update the rotation policy, if needed, for this new device state
- boolean newRotationLockSetting = rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_LOCKED;
- if (newRotationLockSetting != mRotationPolicyWrapper.isRotationLocked()) {
- mRotationPolicyWrapper.setRotationLock(newRotationLockSetting);
+ if (shouldBeLocked != isLocked) {
+ mRotationPolicyWrapper.setRotationLock(shouldBeLocked);
}
}
+
+ @Override
+ public void dump(@NonNull PrintWriter printWriter, @NonNull String[] args) {
+ IndentingPrintWriter pw = new IndentingPrintWriter(printWriter);
+ mDeviceStateRotationLockSettingsManager.dump(pw);
+ pw.println("DeviceStateRotationLockSettingController");
+ pw.increaseIndent();
+ pw.println("mDeviceState: " + mDeviceState);
+ pw.decreaseIndent();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt
new file mode 100644
index 000000000000..aa502bc48149
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt
@@ -0,0 +1,140 @@
+/*
+ * 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 android.content.Context
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_LOCKED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED
+import com.android.internal.R
+import com.android.systemui.log.dagger.DeviceStateAutoRotationLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.VERBOSE
+import javax.inject.Inject
+
+class DeviceStateRotationLockSettingControllerLogger
+@Inject
+constructor(@DeviceStateAutoRotationLog private val logBuffer: LogBuffer, context: Context) {
+
+ private val foldedStates = context.resources.getIntArray(R.array.config_foldedDeviceStates)
+ private val halfFoldedStates =
+ context.resources.getIntArray(R.array.config_halfFoldedDeviceStates)
+ private val unfoldedStates = context.resources.getIntArray(R.array.config_openDeviceStates)
+
+ fun logListeningChange(listening: Boolean) {
+ logBuffer.log(TAG, VERBOSE, { bool1 = listening }, { "setListening: $bool1" })
+ }
+
+ fun logRotationLockStateChanged(
+ state: Int,
+ newRotationLocked: Boolean,
+ currentRotationLocked: Boolean
+ ) {
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ {
+ int1 = state
+ bool1 = newRotationLocked
+ bool2 = currentRotationLocked
+ },
+ {
+ "onRotationLockStateChanged: " +
+ "state=$int1 [${int1.toDevicePostureString()}], " +
+ "newRotationLocked=$bool1, " +
+ "currentRotationLocked=$bool2"
+ }
+ )
+ }
+
+ fun logSaveNewRotationLockSetting(isRotationLocked: Boolean, state: Int) {
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ {
+ bool1 = isRotationLocked
+ int1 = state
+ },
+ { "saveNewRotationLockSetting: isRotationLocked=$bool1, state=$int1" }
+ )
+ }
+
+ fun logUpdateDeviceState(currentState: Int, newState: Int) {
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ {
+ int1 = currentState
+ int2 = newState
+ },
+ {
+ "updateDeviceState: " +
+ "current=$int1 [${int1.toDevicePostureString()}], " +
+ "new=$int2 [${int2.toDevicePostureString()}]"
+ }
+ )
+ }
+
+ fun readPersistedSetting(
+ caller: String,
+ state: Int,
+ rotationLockSetting: Int,
+ shouldBeLocked: Boolean,
+ isLocked: Boolean
+ ) {
+ logBuffer.log(
+ TAG,
+ VERBOSE,
+ {
+ str1 = caller
+ int1 = state
+ int2 = rotationLockSetting
+ bool1 = shouldBeLocked
+ bool2 = isLocked
+ },
+ {
+ "readPersistedSetting: " +
+ "caller=$str1, " +
+ "state=$int1 [${int1.toDevicePostureString()}], " +
+ "rotationLockSettingForState: ${int2.toRotationLockSettingString()}, " +
+ "shouldBeLocked=$bool1, " +
+ "isLocked=$bool2"
+ }
+ )
+ }
+
+ private fun Int.toDevicePostureString(): String {
+ return when (this) {
+ in foldedStates -> "Folded"
+ in unfoldedStates -> "Unfolded"
+ in halfFoldedStates -> "Half-Folded"
+ -1 -> "Uninitialized"
+ else -> "Unknown"
+ }
+ }
+}
+
+private fun Int.toRotationLockSettingString(): String {
+ return when (this) {
+ DEVICE_STATE_ROTATION_LOCK_IGNORED -> "IGNORED"
+ DEVICE_STATE_ROTATION_LOCK_LOCKED -> "LOCKED"
+ DEVICE_STATE_ROTATION_LOCK_UNLOCKED -> "UNLOCKED"
+ else -> "Unknown"
+ }
+}
+
+private const val TAG = "DSRotateLockSettingCon"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt
index bdb656b9d2d5..1e223b1920ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt
@@ -146,7 +146,7 @@ constructor(
*
* @param guestUserId id of the guest user to remove
* @param targetUserId id of the user to switch to after guest is removed. If
- * `UserHandle.USER_NULL`, then switch immediately to the newly created guest user.
+ * `UserHandle.USER_NULL`, then switch immediately to the newly created guest user.
*/
fun removeGuestUser(guestUserId: Int, targetUserId: Int) {
userInteractor.removeGuestUser(
@@ -160,9 +160,9 @@ constructor(
*
* @param guestUserId user id of the guest user to exit
* @param targetUserId user id of the guest user to exit, set to UserHandle#USER_NULL when
- * target user id is not known
+ * target user id is not known
* @param forceRemoveGuestOnExit true: remove guest before switching user, false: remove guest
- * only if its ephemeral, else keep guest
+ * only if its ephemeral, else keep guest
*/
fun exitGuestUser(guestUserId: Int, targetUserId: Int, forceRemoveGuestOnExit: Boolean) {
userInteractor.exitGuestUser(guestUserId, targetUserId, forceRemoveGuestOnExit)
diff --git a/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt b/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt
index e092f01d19f6..8e2b05cd9526 100644
--- a/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt
@@ -66,7 +66,7 @@ class SwitchToManagedProfileForCallActivity : AlertActivity(), DialogInterface.O
private fun switchToManagedProfile() {
try {
applicationContext.startActivityAsUser(
- Intent(Intent.ACTION_DIAL, phoneNumber),
+ Intent(Intent.ACTION_CALL, phoneNumber),
ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle(),
UserHandle.of(managedProfileUserId)
)
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TouchableRegionViewController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TouchableRegionViewController.kt
index 60241a9684d9..cf0184f9e1ae 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TouchableRegionViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TouchableRegionViewController.kt
@@ -27,7 +27,7 @@ import com.android.systemui.util.ViewController
* pass through to the window below.
*
* @param touchableRegionSetter a function that, given the view and an out rect, fills the rect with
- * the touchable region of this view.
+ * the touchable region of this view.
*/
class TouchableRegionViewController(
view: View,
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt
index 01a81deabc95..16123882046c 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt
@@ -35,7 +35,7 @@ open class ChipbarAnimator @Inject constructor() {
* Animates [innerView] and its children into view.
*
* @return true if the animation was successfully started and false if the animation can't be
- * run for any reason.
+ * run for any reason.
*
* See [ViewHierarchyAnimator.animateAddition].
*/
@@ -55,7 +55,7 @@ open class ChipbarAnimator @Inject constructor() {
* Animates [innerView] and its children out of view.
*
* @return true if the animation was successfully started and false if the animation can't be
- * run for any reason.
+ * run for any reason.
*
* See [ViewHierarchyAnimator.animateRemoval].
*/
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt
index fe46318daa30..125cc761d400 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt
@@ -28,10 +28,10 @@ import com.android.systemui.temporarydisplay.ViewPriority
* A container for all the state needed to display a chipbar via [ChipbarCoordinator].
*
* @property startIcon the icon to display at the start of the chipbar (on the left in LTR locales;
- * on the right in RTL locales).
+ * on the right in RTL locales).
* @property text the text to display.
* @property endItem an optional end item to display at the end of the chipbar (on the right in LTR
- * locales; on the left in RTL locales).
+ * locales; on the left in RTL locales).
* @property vibrationEffect an optional vibration effect when the chipbar is displayed
* @property allowSwipeToDismiss true if users are allowed to swipe up to dismiss this chipbar.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index b23d870fb82f..8cfe2eac3d33 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -42,7 +42,7 @@ import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.demomode.DemoModeController;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -68,7 +68,7 @@ public class TunerServiceImpl extends TunerService {
// Things that use the tunable infrastructure but are now real user settings and
// shouldn't be reset with tuner settings.
private static final String[] RESET_EXCEPTION_LIST = new String[] {
- QSTileHost.TILES_SETTING,
+ QSHost.TILES_SETTING,
Settings.Secure.DOZE_ALWAYS_ON,
Settings.Secure.MEDIA_CONTROLS_RESUME,
Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldStateLoggingProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldStateLoggingProviderImpl.kt
index 2683971f852c..981f429d1f8f 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/FoldStateLoggingProviderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldStateLoggingProviderImpl.kt
@@ -61,8 +61,6 @@ class FoldStateLoggingProviderImpl(
foldStateProvider.stop()
}
- override fun onHingeAngleUpdate(angle: Float) {}
-
override fun onFoldUpdate(@FoldUpdate update: Int) {
val now = clock.elapsedRealtime()
when (update) {
@@ -77,6 +75,10 @@ class FoldStateLoggingProviderImpl(
}
}
+ override fun onUnfoldedScreenAvailable() {
+ Log.d(TAG, "Unfolded screen available")
+ }
+
private fun dispatchState(@LoggedFoldedStates current: Int) {
val now = clock.elapsedRealtime()
val previous = lastState
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
index d5d3efd78d13..3a7ac9c8a8bd 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
@@ -31,6 +31,9 @@ import android.view.WindowManager;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+
+import javax.inject.Inject;
/**
* If the attached USB accessory has a URL associated with it, and that URL is valid,
@@ -46,13 +49,27 @@ public class UsbAccessoryUriActivity extends AlertActivity
private UsbAccessory mAccessory;
private Uri mUri;
+ private final DeviceProvisionedController mDeviceProvisionedController;
+
+ @Inject
+ UsbAccessoryUriActivity(DeviceProvisionedController deviceProvisionedController) {
+ mDeviceProvisionedController = deviceProvisionedController;
+ }
+
@Override
public void onCreate(Bundle icicle) {
- getWindow().addSystemFlags(
+ getWindow().addSystemFlags(
WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
- super.onCreate(icicle);
+ super.onCreate(icicle);
+
+ // Don't show this dialog during Setup Wizard
+ if (!mDeviceProvisionedController.isDeviceProvisioned()) {
+ Log.e(TAG, "device not provisioned");
+ finish();
+ return;
+ }
- Intent intent = getIntent();
+ Intent intent = getIntent();
mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
String uriString = intent.getStringExtra("uri");
mUri = (uriString == null ? null : Uri.parse(uriString));
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
index ad1e5fe08619..b2b7c0b8056f 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
@@ -17,11 +17,8 @@
package com.android.systemui.user.data.repository
-import android.app.IActivityManager
-import android.app.UserSwitchObserver
import android.content.Context
import android.content.pm.UserInfo
-import android.os.IRemoteCallback
import android.os.UserHandle
import android.os.UserManager
import android.provider.Settings
@@ -118,7 +115,6 @@ constructor(
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val globalSettings: GlobalSettings,
private val tracker: UserTracker,
- private val activityManager: IActivityManager,
featureFlags: FeatureFlags,
) : UserRepository {
@@ -203,18 +199,18 @@ constructor(
private fun observeUserSwitching() {
conflatedCallbackFlow {
val callback =
- object : UserSwitchObserver() {
- override fun onUserSwitching(newUserId: Int, reply: IRemoteCallback) {
+ object : UserTracker.Callback {
+ override fun onUserChanging(newUser: Int, userContext: Context) {
trySendWithFailureLogging(true, TAG, "userSwitching started")
}
- override fun onUserSwitchComplete(newUserId: Int) {
+ override fun onUserChanged(newUserId: Int, userContext: Context) {
trySendWithFailureLogging(false, TAG, "userSwitching completed")
}
}
- activityManager.registerUserSwitchObserver(callback, TAG)
+ tracker.addCallback(callback, mainDispatcher.asExecutor())
trySendWithFailureLogging(false, TAG, "initial value defaulting to false")
- awaitClose { activityManager.unregisterUserSwitchObserver(callback) }
+ awaitClose { tracker.removeCallback(callback) }
}
.onEach { _isUserSwitchingInProgress.value = it }
// TODO (b/262838215), Make this stateIn and initialize directly in field declaration
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
index 208061433325..42cd5bca376d 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
@@ -297,7 +297,7 @@ constructor(
* to create a new one.
*
* @return The multi-user user ID of the newly created guest user, or [UserHandle.USER_NULL] if
- * the guest couldn't be created.
+ * the guest couldn't be created.
*/
@UserIdInt
private suspend fun createInBackground(): Int {
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
index 81ae6e851fb9..c72853ef37be 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
@@ -115,6 +115,17 @@ public abstract class SysUIConcurrencyModule {
}
/**
+ * Provide a Long running Executor.
+ */
+ @Provides
+ @SysUISingleton
+ @LongRunning
+ public static DelayableExecutor provideLongRunningDelayableExecutor(
+ @LongRunning Looper looper) {
+ return new ExecutorImpl(looper);
+ }
+
+ /**
* Provide a Background-Thread Executor.
*/
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index 8b925b7ad312..b962148b79dc 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -35,7 +35,7 @@ import android.view.WindowManager;
import androidx.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.LongRunning;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -61,17 +61,16 @@ public class ImageWallpaper extends WallpaperService {
private final UserTracker mUserTracker;
// used for most tasks (call canvas.drawBitmap, load/unload the bitmap)
- @Background
- private final DelayableExecutor mBackgroundExecutor;
+ @LongRunning
+ private final DelayableExecutor mLongExecutor;
// wait at least this duration before unloading the bitmap
private static final int DELAY_UNLOAD_BITMAP = 2000;
@Inject
- public ImageWallpaper(@Background DelayableExecutor backgroundExecutor,
- UserTracker userTracker) {
+ public ImageWallpaper(@LongRunning DelayableExecutor longExecutor, UserTracker userTracker) {
super();
- mBackgroundExecutor = backgroundExecutor;
+ mLongExecutor = longExecutor;
mUserTracker = userTracker;
}
@@ -105,7 +104,7 @@ public class ImageWallpaper extends WallpaperService {
setFixedSizeAllowed(true);
setShowForAllUsers(true);
mWallpaperLocalColorExtractor = new WallpaperLocalColorExtractor(
- mBackgroundExecutor,
+ mLongExecutor,
new WallpaperLocalColorExtractor.WallpaperLocalColorExtractorCallback() {
@Override
public void onColorsProcessed(List<RectF> regions,
@@ -202,7 +201,7 @@ public class ImageWallpaper extends WallpaperService {
}
private void drawFrame() {
- mBackgroundExecutor.execute(this::drawFrameSynchronized);
+ mLongExecutor.execute(this::drawFrameSynchronized);
}
private void drawFrameSynchronized() {
@@ -257,7 +256,7 @@ public class ImageWallpaper extends WallpaperService {
}
private void unloadBitmapIfNotUsed() {
- mBackgroundExecutor.execute(this::unloadBitmapIfNotUsedSynchronized);
+ mLongExecutor.execute(this::unloadBitmapIfNotUsedSynchronized);
}
private void unloadBitmapIfNotUsedSynchronized() {
@@ -341,7 +340,7 @@ public class ImageWallpaper extends WallpaperService {
* - the mini bitmap from color extractor is recomputed
* - the DELAY_UNLOAD_BITMAP has passed
*/
- mBackgroundExecutor.executeDelayed(
+ mLongExecutor.executeDelayed(
this::unloadBitmapIfNotUsedSynchronized, DELAY_UNLOAD_BITMAP);
}
// even if the bitmap cannot be loaded, call reportEngineShown
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java b/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java
index 988fd710d2dc..1e8446f8df1d 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java
@@ -29,7 +29,7 @@ import android.util.MathUtils;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
-import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.LongRunning;
import com.android.systemui.util.Assert;
import java.io.FileDescriptor;
@@ -66,8 +66,8 @@ public class WallpaperLocalColorExtractor {
private final List<RectF> mPendingRegions = new ArrayList<>();
private final Set<RectF> mProcessedRegions = new ArraySet<>();
- @Background
- private final Executor mBackgroundExecutor;
+ @LongRunning
+ private final Executor mLongExecutor;
private final WallpaperLocalColorExtractorCallback mWallpaperLocalColorExtractorCallback;
@@ -101,13 +101,13 @@ public class WallpaperLocalColorExtractor {
/**
* Creates a new color extractor.
- * @param backgroundExecutor the executor on which the color extraction will be performed
+ * @param longExecutor the executor on which the color extraction will be performed
* @param wallpaperLocalColorExtractorCallback an interface to handle the callbacks from
* the color extractor.
*/
- public WallpaperLocalColorExtractor(@Background Executor backgroundExecutor,
+ public WallpaperLocalColorExtractor(@LongRunning Executor longExecutor,
WallpaperLocalColorExtractorCallback wallpaperLocalColorExtractorCallback) {
- mBackgroundExecutor = backgroundExecutor;
+ mLongExecutor = longExecutor;
mWallpaperLocalColorExtractorCallback = wallpaperLocalColorExtractorCallback;
}
@@ -117,7 +117,7 @@ public class WallpaperLocalColorExtractor {
* not recomputed.
*/
public void setDisplayDimensions(int displayWidth, int displayHeight) {
- mBackgroundExecutor.execute(() ->
+ mLongExecutor.execute(() ->
setDisplayDimensionsSynchronized(displayWidth, displayHeight));
}
@@ -144,7 +144,7 @@ public class WallpaperLocalColorExtractor {
* @param bitmap the new wallpaper
*/
public void onBitmapChanged(@NonNull Bitmap bitmap) {
- mBackgroundExecutor.execute(() -> onBitmapChangedSynchronized(bitmap));
+ mLongExecutor.execute(() -> onBitmapChangedSynchronized(bitmap));
}
private void onBitmapChangedSynchronized(@NonNull Bitmap bitmap) {
@@ -167,7 +167,7 @@ public class WallpaperLocalColorExtractor {
* @param pages the total number of pages of the launcher
*/
public void onPageChanged(int pages) {
- mBackgroundExecutor.execute(() -> onPageChangedSynchronized(pages));
+ mLongExecutor.execute(() -> onPageChangedSynchronized(pages));
}
private void onPageChangedSynchronized(int pages) {
@@ -194,7 +194,7 @@ public class WallpaperLocalColorExtractor {
*/
public void addLocalColorsAreas(@NonNull List<RectF> regions) {
if (regions.size() > 0) {
- mBackgroundExecutor.execute(() -> addLocalColorsAreasSynchronized(regions));
+ mLongExecutor.execute(() -> addLocalColorsAreasSynchronized(regions));
} else {
Log.w(TAG, "Attempt to add colors with an empty list");
}
@@ -218,7 +218,7 @@ public class WallpaperLocalColorExtractor {
* @param regions The areas of interest in our wallpaper (in screen pixel coordinates)
*/
public void removeLocalColorAreas(@NonNull List<RectF> regions) {
- mBackgroundExecutor.execute(() -> removeLocalColorAreasSynchronized(regions));
+ mLongExecutor.execute(() -> removeLocalColorAreasSynchronized(regions));
}
private void removeLocalColorAreasSynchronized(@NonNull List<RectF> regions) {
@@ -236,7 +236,7 @@ public class WallpaperLocalColorExtractor {
* Clean up the memory (in particular, the mini bitmap) used by this class.
*/
public void cleanUp() {
- mBackgroundExecutor.execute(this::cleanUpSynchronized);
+ mLongExecutor.execute(this::cleanUpSynchronized);
}
private void cleanUpSynchronized() {
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 5d896cbbdab4..56df3e114c0b 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -25,7 +25,6 @@ import static android.service.notification.NotificationListenerService.REASON_GR
import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE;
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
-import static com.android.systemui.flags.Flags.WM_BUBBLE_BAR;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -358,7 +357,6 @@ public class BubblesManager {
});
}
};
- mBubbles.setBubbleBarEnabled(featureFlags.isEnabled(WM_BUBBLE_BAR));
mBubbles.setSysuiProxy(mSysuiProxy);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt
new file mode 100644
index 000000000000..30fed0b0316f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt
@@ -0,0 +1,112 @@
+/*
+ * 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.keyguard
+
+import android.app.ActivityTaskManager
+import android.content.pm.PackageManager
+import android.os.PowerManager
+import android.telecom.TelecomManager
+import android.telephony.TelephonyManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.widget.LockPatternUtils
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.shade.ShadeController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class EmergencyButtonControllerTest : SysuiTestCase() {
+ lateinit var underTest: EmergencyButtonController
+ @Mock lateinit var emergencyButton: EmergencyButton
+ @Mock lateinit var configurationController: ConfigurationController
+ @Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock lateinit var telephonyManager: TelephonyManager
+ @Mock lateinit var powerManager: PowerManager
+ @Mock lateinit var activityTaskManager: ActivityTaskManager
+ @Mock lateinit var shadeController: ShadeController
+ @Mock lateinit var telecomManager: TelecomManager
+ @Mock lateinit var metricsLogger: MetricsLogger
+ @Mock lateinit var lockPatternUtils: LockPatternUtils
+ @Mock lateinit var packageManager: PackageManager
+ val fakeSystemClock = FakeSystemClock()
+ val mainExecutor = FakeExecutor(fakeSystemClock)
+ val backgroundExecutor = FakeExecutor(fakeSystemClock)
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ underTest =
+ EmergencyButtonController(
+ emergencyButton,
+ configurationController,
+ keyguardUpdateMonitor,
+ telephonyManager,
+ powerManager,
+ activityTaskManager,
+ shadeController,
+ telecomManager,
+ metricsLogger,
+ lockPatternUtils,
+ mainExecutor,
+ backgroundExecutor
+ )
+ context.setMockPackageManager(packageManager)
+ Mockito.`when`(emergencyButton.context).thenReturn(context)
+ }
+
+ @Test
+ fun testUpdateEmergencyButton() {
+ Mockito.`when`(telecomManager.isInCall).thenReturn(true)
+ Mockito.`when`(lockPatternUtils.isSecure(anyInt())).thenReturn(true)
+ Mockito.`when`(packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY))
+ .thenReturn(true)
+ underTest.updateEmergencyCallButton()
+ backgroundExecutor.runAllReady()
+ verify(emergencyButton, never())
+ .updateEmergencyCallButton(
+ /* isInCall= */ any(),
+ /* hasTelephonyRadio= */ any(),
+ /* simLocked= */ any(),
+ /* isSecure= */ any()
+ )
+ mainExecutor.runAllReady()
+ verify(emergencyButton)
+ .updateEmergencyCallButton(
+ /* isInCall= */ eq(true),
+ /* hasTelephonyRadio= */ eq(true),
+ /* simLocked= */ any(),
+ /* isSecure= */ eq(true)
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
index d91279399341..ed928702b981 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
@@ -18,8 +18,10 @@ package com.android.keyguard
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
+import android.widget.ImageView
import androidx.test.filters.SmallTest
import com.android.internal.util.LatencyTracker
import com.android.internal.widget.LockPatternUtils
@@ -30,6 +32,7 @@ import com.android.systemui.util.concurrency.DelayableExecutor
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
@@ -37,6 +40,7 @@ import org.mockito.Mockito
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations
@SmallTest
@@ -76,7 +80,9 @@ class KeyguardPasswordViewControllerTest : SysuiTestCase() {
Mockito.`when`(keyguardPasswordView.findViewById<EditText>(R.id.passwordEntry))
.thenReturn(passwordEntry)
`when`(keyguardPasswordView.resources).thenReturn(context.resources)
- keyguardPasswordViewController =
+ `when`(keyguardPasswordView.findViewById<ImageView>(R.id.switch_ime_button))
+ .thenReturn(mock(ImageView::class.java))
+ keyguardPasswordViewController =
KeyguardPasswordViewController(
keyguardPasswordView,
keyguardUpdateMonitor,
@@ -113,6 +119,18 @@ class KeyguardPasswordViewControllerTest : SysuiTestCase() {
}
@Test
+ fun onApplyWindowInsetsListener_onApplyWindowInsets() {
+ `when`(keyguardViewController.isBouncerShowing).thenReturn(false)
+ val argumentCaptor = ArgumentCaptor.forClass(View.OnApplyWindowInsetsListener::class.java)
+
+ keyguardPasswordViewController.onViewAttached()
+ verify(keyguardPasswordView).setOnApplyWindowInsetsListener(argumentCaptor.capture())
+ argumentCaptor.value.onApplyWindowInsets(keyguardPasswordView, null)
+
+ verify(keyguardPasswordView).hideKeyboard()
+ }
+
+ @Test
fun testHideKeyboardWhenOnPause() {
keyguardPasswordViewController.onPause()
keyguardPasswordView.post {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 1bbc19931c21..531006da8210 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -37,6 +37,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -160,6 +161,29 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
}
@Test
+ public void testOnApplyWindowInsets_disappearAnimation_paddingNotSet() {
+ int paddingBottom = getContext().getResources()
+ .getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin);
+ int imeInsetAmount = paddingBottom + 1;
+ int systemBarInsetAmount = 0;
+ initMode(MODE_DEFAULT);
+
+ Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
+ Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
+
+ WindowInsets insets = new WindowInsets.Builder()
+ .setInsets(ime(), imeInset)
+ .setInsetsIgnoringVisibility(systemBars(), systemBarInset)
+ .build();
+
+ ensureViewFlipperIsMocked();
+ mKeyguardSecurityContainer.startDisappearAnimation(
+ KeyguardSecurityModel.SecurityMode.Password);
+ mKeyguardSecurityContainer.onApplyWindowInsets(insets);
+ assertThat(mKeyguardSecurityContainer.getPaddingBottom()).isNotEqualTo(imeInsetAmount);
+ }
+
+ @Test
public void testDefaultViewMode() {
initMode(MODE_ONE_HANDED);
initMode(MODE_DEFAULT);
@@ -376,6 +400,17 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
assertThat(mKeyguardSecurityContainer.getScaleY()).isEqualTo(1);
}
+ @Test
+ public void testDisappearAnimationPassword() {
+ ensureViewFlipperIsMocked();
+ KeyguardPasswordView keyguardPasswordView = mock(KeyguardPasswordView.class);
+ when(mSecurityViewFlipper.getSecurityView()).thenReturn(keyguardPasswordView);
+
+ mKeyguardSecurityContainer
+ .startDisappearAnimation(KeyguardSecurityModel.SecurityMode.Password);
+ verify(keyguardPasswordView).setDisappearAnimationListener(any());
+ }
+
private BackEvent createBackEvent(float touchX, float progress) {
return new BackEvent(0, 0, progress, BackEvent.EDGE_LEFT);
}
@@ -446,4 +481,12 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
mUserSwitcherController, () -> {
}, mFalsingA11yDelegate);
}
+
+ private void ensureViewFlipperIsMocked() {
+ mSecurityViewFlipper = mock(KeyguardSecurityViewFlipper.class);
+ KeyguardPasswordView keyguardPasswordView = mock(KeyguardPasswordView.class);
+ when(mSecurityViewFlipper.getSecurityView()).thenReturn(keyguardPasswordView);
+ mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper;
+ }
+
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index dfad15d68375..71449145d668 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -26,7 +26,6 @@ import android.testing.AndroidTestingRunner;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ClockAnimations;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
@@ -61,8 +60,6 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
@Mock
DozeParameters mDozeParameters;
@Mock
- FeatureFlags mFeatureFlags;
- @Mock
ScreenOffAnimationController mScreenOffAnimationController;
@Captor
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor;
@@ -83,7 +80,6 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
mKeyguardUpdateMonitor,
mConfigurationController,
mDozeParameters,
- mFeatureFlags,
mScreenOffAnimationController,
mKeyguardLogger);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index dc90e2d0a656..4c92eddd66fb 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -28,7 +28,6 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.keyguard.FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_AVAILABLE;
-import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_STATE_CANCELLING;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_STATE_CANCELLING_RESTARTING;
import static com.android.keyguard.KeyguardUpdateMonitor.DEFAULT_CANCEL_SIGNAL_TIMEOUT;
import static com.android.keyguard.KeyguardUpdateMonitor.HAL_POWER_PRESS_TIMEOUT;
@@ -56,8 +55,6 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.IActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.IStrongAuthTracker;
import android.app.trust.TrustManager;
@@ -90,7 +87,6 @@ import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
-import android.os.IRemoteCallback;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -148,6 +144,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -231,8 +228,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Mock
private KeyguardUpdateMonitorLogger mKeyguardUpdateMonitorLogger;
@Mock
- private IActivityManager mActivityService;
- @Mock
private SessionTracker mSessionTracker;
@Mock
private UiEventLogger mUiEventLogger;
@@ -269,8 +264,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Before
public void setup() throws RemoteException {
MockitoAnnotations.initMocks(this);
- when(mActivityService.getCurrentUser()).thenReturn(mCurrentUserInfo);
- when(mActivityService.getCurrentUserId()).thenReturn(mCurrentUserId);
when(mFaceManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.hasEnrolledTemplates()).thenReturn(true);
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
@@ -310,13 +303,11 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mMockitoSession = ExtendedMockito.mockitoSession()
.spyStatic(SubscriptionManager.class)
- .spyStatic(ActivityManager.class)
.startMocking();
ExtendedMockito.doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
.when(SubscriptionManager::getDefaultSubscriptionId);
KeyguardUpdateMonitor.setCurrentUser(mCurrentUserId);
when(mUserTracker.getUserId()).thenReturn(mCurrentUserId);
- ExtendedMockito.doReturn(mActivityService).when(ActivityManager::getService);
mContext.getOrCreateTestableResources().addOverride(
com.android.systemui.R.integer.config_face_auth_supported_posture,
@@ -604,9 +595,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
mTestableLooper.processAllMessages();
- verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
- anyInt());
- verify(mFingerprintManager, never()).detectFingerprint(any(), any(), anyInt());
+ verifyFingerprintAuthenticateCall();
+ verifyFingerprintDetectNeverCalled();
}
@Test
@@ -616,24 +606,51 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
mTestableLooper.processAllMessages();
- verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
- anyInt(), anyInt());
- verify(mFingerprintManager, never()).detectFingerprint(any(), any(), anyInt());
+ verifyFingerprintAuthenticateNeverCalled();
+ verifyFingerprintDetectNeverCalled();
}
@Test
public void testOnlyDetectFingerprint_whenFingerprintUnlockNotAllowed() {
- // Clear invocations, since previous setup (e.g. registering BiometricManager callbacks)
- // will trigger updateBiometricListeningState();
- clearInvocations(mFingerprintManager);
- mKeyguardUpdateMonitor.resetBiometricListeningState();
+ givenDetectFingerprintWithClearingFingerprintManagerInvocations();
- when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
- mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
- mTestableLooper.processAllMessages();
+ verifyFingerprintAuthenticateNeverCalled();
+ verifyFingerprintDetectCall();
+ }
- verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt());
- verify(mFingerprintManager).detectFingerprint(any(), any(), anyInt());
+ @Test
+ public void whenDetectFingerprint_biometricDetectCallback() {
+ ArgumentCaptor<FingerprintManager.FingerprintDetectionCallback> fpDetectCallbackCaptor =
+ ArgumentCaptor.forClass(FingerprintManager.FingerprintDetectionCallback.class);
+
+ givenDetectFingerprintWithClearingFingerprintManagerInvocations();
+ verify(mFingerprintManager).detectFingerprint(
+ any(), fpDetectCallbackCaptor.capture(), anyInt());
+ fpDetectCallbackCaptor.getValue().onFingerprintDetected(0, 0, true);
+
+ // THEN verify keyguardUpdateMonitorCallback receives a detect callback
+ // and NO authenticate callbacks
+ verify(mTestCallback).onBiometricDetected(
+ eq(0), eq(BiometricSourceType.FINGERPRINT), eq(true));
+ verify(mTestCallback, never()).onBiometricAuthenticated(
+ anyInt(), any(), anyBoolean());
+ }
+
+ @Test
+ public void whenDetectFace_biometricDetectCallback() {
+ ArgumentCaptor<FaceManager.FaceDetectionCallback> faceDetectCallbackCaptor =
+ ArgumentCaptor.forClass(FaceManager.FaceDetectionCallback.class);
+
+ givenDetectFace();
+ verify(mFaceManager).detectFace(any(), faceDetectCallbackCaptor.capture(), anyInt());
+ faceDetectCallbackCaptor.getValue().onFaceDetected(0, 0, false);
+
+ // THEN verify keyguardUpdateMonitorCallback receives a detect callback
+ // and NO authenticate callbacks
+ verify(mTestCallback).onBiometricDetected(
+ eq(0), eq(BiometricSourceType.FACE), eq(false));
+ verify(mTestCallback, never()).onBiometricAuthenticated(
+ anyInt(), any(), anyBoolean());
}
@Test
@@ -664,7 +681,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
strongAuthNotRequired();
// WHEN fingerprint is locked out
- fingerprintErrorLockedOut();
+ fingerprintErrorTemporaryLockedOut();
// THEN unlocking with face is not allowed
Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
@@ -687,7 +704,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
strongAuthNotRequired();
// WHEN fingerprint is locked out
- fingerprintErrorLockedOut();
+ fingerprintErrorTemporaryLockedOut();
// THEN unlocking with fingerprint is not allowed
Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
@@ -711,7 +728,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
Assert.assertTrue(mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser()));
// WHEN fingerprint is locked out
- fingerprintErrorLockedOut();
+ fingerprintErrorTemporaryLockedOut();
// THEN user is NOT considered as "having trust" and bouncer cannot be skipped
Assert.assertFalse(mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser()));
@@ -722,7 +739,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
public void testTriesToAuthenticate_whenBouncer() {
setKeyguardBouncerVisibility(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
+ verifyFaceAuthenticateCall();
verify(mFaceManager).isHardwareDetected();
verify(mFaceManager).hasEnrolledTemplates(anyInt());
}
@@ -732,8 +749,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.sendPrimaryBouncerChanged(
/* bouncerIsOrWillBeShowing */ true, /* bouncerFullyShown */ false);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
- anyBoolean());
+ verifyFaceAuthenticateNeverCalled();
}
@Test
@@ -741,7 +757,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
keyguardIsVisible();
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
+
+ verifyFaceAuthenticateCall();
verify(mUiEventLogger).logWithInstanceIdAndPosition(
eq(FaceAuthUiEvent.FACE_AUTH_UPDATED_STARTED_WAKING_UP),
eq(0),
@@ -757,8 +774,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
keyguardIsVisible();
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
- anyBoolean());
+ verifyFaceAuthenticateNeverCalled();
}
@Test
@@ -769,17 +785,11 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
keyguardIsVisible();
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
- anyBoolean());
+ verifyFaceAuthenticateNeverCalled();
}
@Test
public void nofaceDetect_whenStrongAuthRequiredAndBypassUdfpsSupportedAndFpRunning() {
- // GIVEN mocked keyguardUpdateMonitorCallback
- KeyguardUpdateMonitorCallback keyguardUpdateMonitorCallback =
- mock(KeyguardUpdateMonitorCallback.class);
- mKeyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback);
-
// GIVEN bypass is enabled, face detection is supported
lockscreenBypassIsAllowed();
supportsFaceDetection();
@@ -794,32 +804,21 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
// THEN face detect and authenticate are NOT triggered
- verify(mFaceManager, never()).detectFace(any(), any(), anyInt());
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
- anyBoolean());
+ verifyFaceDetectNeverCalled();
+ verifyFaceAuthenticateNeverCalled();
// THEN biometric help message sent to callback
- verify(keyguardUpdateMonitorCallback).onBiometricHelp(
+ verify(mTestCallback).onBiometricHelp(
eq(BIOMETRIC_HELP_FACE_NOT_AVAILABLE), anyString(), eq(BiometricSourceType.FACE));
}
@Test
public void faceDetect_whenStrongAuthRequiredAndBypass() {
- // GIVEN bypass is enabled, face detection is supported and strong auth is required
- lockscreenBypassIsAllowed();
- supportsFaceDetection();
- strongAuthRequiredEncrypted();
- keyguardIsVisible();
- // fingerprint is NOT running, UDFPS is NOT supported
-
- // WHEN the device wakes up
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- mTestableLooper.processAllMessages();
+ givenDetectFace();
// FACE detect is triggered, not authenticate
- verify(mFaceManager).detectFace(any(), any(), anyInt());
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
- anyBoolean());
+ verifyFaceDetectCall();
+ verifyFaceAuthenticateNeverCalled();
// WHEN bouncer becomes visible
setKeyguardBouncerVisibility(true);
@@ -827,9 +826,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
// THEN face scanning is not run
mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
- anyBoolean());
- verify(mFaceManager, never()).detectFace(any(), any(), anyInt());
+ verifyFaceAuthenticateNeverCalled();
+ verifyFaceDetectNeverCalled();
}
@Test
@@ -844,9 +842,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
// FACE detect and authenticate are NOT triggered
- verify(mFaceManager, never()).detectFace(any(), any(), anyInt());
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
- anyBoolean());
+ verifyFaceDetectNeverCalled();
+ verifyFaceAuthenticateNeverCalled();
}
@Test
@@ -884,7 +881,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.setKeyguardShowing(true, true);
mKeyguardUpdateMonitor.setAssistantVisible(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
+ verifyFaceAuthenticateCall();
}
@Test
@@ -892,12 +889,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.setKeyguardShowing(false, true);
mKeyguardUpdateMonitor.setAssistantVisible(true);
- verify(mFaceManager, never()).authenticate(any(),
- any(),
- any(),
- any(),
- anyInt(),
- anyBoolean());
+ verifyFaceAuthenticateNeverCalled();
}
@Test
@@ -908,15 +900,12 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
// THEN fingerprint shouldn't listen
assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isFalse();
- verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
- anyInt(), anyInt());
-
+ verifyFingerprintAuthenticateNeverCalled();
// WHEN alternate bouncer is shown
mKeyguardUpdateMonitor.setAlternateBouncerShowing(true);
// THEN make sure FP listening begins
- verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
- anyInt());
+ verifyFingerprintAuthenticateCall();
}
@Test
@@ -928,7 +917,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */,
new ArrayList<>());
keyguardIsVisible();
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
+ verifyFaceAuthenticateCall();
}
@Test
@@ -936,7 +925,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.setKeyguardShowing(true, true);
mKeyguardUpdateMonitor.setAssistantVisible(true);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
+ verifyFaceAuthenticateCall();
mTestableLooper.processAllMessages();
clearInvocations(mFaceManager);
@@ -949,12 +938,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.handleKeyguardReset();
assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isFalse();
- verify(mFaceManager, never()).authenticate(any(),
- any(),
- any(),
- any(),
- anyInt(),
- anyBoolean());
+ verifyFaceAuthenticateNeverCalled();
}
@Test
@@ -964,8 +948,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, true /* newlyUnlocked */,
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */, new ArrayList<>());
keyguardIsVisible();
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
- anyBoolean());
+ verifyFaceAuthenticateNeverCalled();
}
@Test
@@ -977,9 +960,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
keyguardIsVisible();
mTestableLooper.processAllMessages();
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
- anyBoolean());
- verify(mFaceManager, never()).detectFace(any(), any(), anyInt());
+ verifyFaceAuthenticateNeverCalled();
+ verifyFaceDetectNeverCalled();
}
@Test
@@ -988,16 +970,14 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
.onAuthenticationError(FingerprintManager.BIOMETRIC_ERROR_POWER_PRESSED, "");
// THEN doesn't authenticate immediately
- verify(mFingerprintManager, never()).authenticate(any(),
- any(), any(), any(), anyInt(), anyInt(), anyInt());
+ verifyFingerprintAuthenticateNeverCalled();
// WHEN all messages (with delays) are processed
mTestableLooper.moveTimeForward(HAL_POWER_PRESS_TIMEOUT);
mTestableLooper.processAllMessages();
// THEN fingerprint manager attempts to authenticate again
- verify(mFingerprintManager).authenticate(any(),
- any(), any(), any(), anyInt(), anyInt(), anyInt());
+ verifyFingerprintAuthenticateCall();
}
@Test
@@ -1009,8 +989,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
setKeyguardBouncerVisibility(true);
mTestableLooper.processAllMessages();
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
- anyBoolean());
+ verifyFaceAuthenticateNeverCalled();
}
@Test
@@ -1083,11 +1062,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Test
public void testBiometricsCleared_whenUserSwitches() throws Exception {
- final IRemoteCallback reply = new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle data) {
- } // do nothing
- };
final BiometricAuthenticated dummyAuthentication =
new BiometricAuthenticated(true /* authenticated */, true /* strong */);
mKeyguardUpdateMonitor.mUserFaceAuthenticated.put(0 /* user */, dummyAuthentication);
@@ -1095,18 +1069,13 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
assertThat(mKeyguardUpdateMonitor.mUserFingerprintAuthenticated.size()).isEqualTo(1);
assertThat(mKeyguardUpdateMonitor.mUserFaceAuthenticated.size()).isEqualTo(1);
- mKeyguardUpdateMonitor.handleUserSwitching(10 /* user */, reply);
+ mKeyguardUpdateMonitor.handleUserSwitching(10 /* user */, new CountDownLatch(0));
assertThat(mKeyguardUpdateMonitor.mUserFingerprintAuthenticated.size()).isEqualTo(0);
assertThat(mKeyguardUpdateMonitor.mUserFaceAuthenticated.size()).isEqualTo(0);
}
@Test
public void testMultiUserJankMonitor_whenUserSwitches() throws Exception {
- final IRemoteCallback reply = new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle data) {
- } // do nothing
- };
mKeyguardUpdateMonitor.handleUserSwitchComplete(10 /* user */);
verify(mInteractionJankMonitor).end(InteractionJankMonitor.CUJ_USER_SWITCH);
verify(mLatencyTracker).onActionEnd(LatencyTracker.ACTION_USER_SWITCH);
@@ -1137,9 +1106,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
keyguardIsVisible();
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
- verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
- anyInt());
+ verifyFaceAuthenticateCall();
+ verifyFingerprintAuthenticateCall();
when(mFingerprintManager.getLockoutModeForUser(eq(FINGERPRINT_SENSOR_ID), eq(newUser)))
.thenReturn(fingerprintLockoutMode);
@@ -1170,8 +1138,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
// Fingerprint should be cancelled on lockout if going to lockout state, else
// restarted if it's not
assertThat(mKeyguardUpdateMonitor.mFingerprintRunningState)
- .isEqualTo(fpLocked
- ? BIOMETRIC_STATE_CANCELLING : BIOMETRIC_STATE_CANCELLING_RESTARTING);
+ .isEqualTo(BIOMETRIC_STATE_CANCELLING_RESTARTING);
}
@Test
@@ -1587,10 +1554,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
public void testFaceDoesNotAuth_afterPinAttempt() {
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.setCredentialAttempted();
- verify(mFingerprintManager, never()).authenticate(any(), any(), any(),
- any(), anyInt());
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
- anyBoolean());
+ verifyFaceAuthenticateNeverCalled();
}
@Test
@@ -1633,7 +1597,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
// Fingerprint is locked out.
- fingerprintErrorLockedOut();
+ fingerprintErrorTemporaryLockedOut();
assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
}
@@ -1965,9 +1929,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
keyguardIsVisible();
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
- verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
- anyInt());
+ verifyFaceAuthenticateCall();
+ verifyFingerprintAuthenticateCall();
mKeyguardUpdateMonitor.onFaceAuthenticated(0, false);
// Make sure keyguard is going away after face auth attempt, and that it calls
@@ -1993,8 +1956,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.dispatchDreamingStopped();
mTestableLooper.processAllMessages();
- verify(mFaceManager, never()).authenticate(
- any(), any(), any(), any(), anyInt(), anyBoolean());
+ verifyFaceAuthenticateNeverCalled();
}
@Test
@@ -2007,15 +1969,14 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
// THEN face auth isn't triggered
- verify(mFaceManager, never()).authenticate(
- any(), any(), any(), any(), anyInt(), anyBoolean());
+ verifyFaceAuthenticateNeverCalled();
// WHEN device wakes up from the power button
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
// THEN face auth is triggered
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
+ verifyFaceAuthenticateCall();
}
@@ -2186,7 +2147,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
keyguardIsVisible();
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
+ verifyFaceAuthenticateCall();
verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
anyInt());
@@ -2219,7 +2180,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
keyguardIsVisible();
- verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
+ verifyFaceAuthenticateCall();
final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal);
mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel;
@@ -2238,6 +2199,32 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
}
@Test
+ public void testPostureChangeToUnsupported_stopsFaceListeningState() {
+ // GIVEN device is listening for face
+ mKeyguardUpdateMonitor.mConfigFaceAuthSupportedPosture = DEVICE_POSTURE_CLOSED;
+ deviceInPostureStateClosed();
+ mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
+ mTestableLooper.processAllMessages();
+ keyguardIsVisible();
+
+ verifyFaceAuthenticateCall();
+
+ final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal);
+ mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel;
+ KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
+ mKeyguardUpdateMonitor.registerCallback(callback);
+
+ // WHEN device is opened
+ deviceInPostureStateOpened();
+ mTestableLooper.processAllMessages();
+
+ // THEN face listening is stopped.
+ verify(faceCancel).cancel();
+ verify(callback).onBiometricRunningStateChanged(
+ eq(false), eq(BiometricSourceType.FACE));
+ }
+
+ @Test
public void testShouldListenForFace_withLockedDown_returnsFalse()
throws RemoteException {
keyguardNotGoingAway();
@@ -2445,6 +2432,64 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
eq(false));
}
+ @Test
+ public void detectFingerprint_onTemporaryLockoutReset_authenticateFingerprint() {
+ ArgumentCaptor<FingerprintManager.LockoutResetCallback> fpLockoutResetCallbackCaptor =
+ ArgumentCaptor.forClass(FingerprintManager.LockoutResetCallback.class);
+ verify(mFingerprintManager).addLockoutResetCallback(fpLockoutResetCallbackCaptor.capture());
+
+ // GIVEN device is locked out
+ fingerprintErrorTemporaryLockedOut();
+
+ // GIVEN FP detection is running
+ givenDetectFingerprintWithClearingFingerprintManagerInvocations();
+ verifyFingerprintDetectCall();
+ verifyFingerprintAuthenticateNeverCalled();
+
+ // WHEN temporary lockout resets
+ fpLockoutResetCallbackCaptor.getValue().onLockoutReset(0);
+ mTestableLooper.processAllMessages();
+
+ // THEN fingerprint detect state should cancel & then restart (for authenticate call)
+ assertThat(mKeyguardUpdateMonitor.mFingerprintRunningState)
+ .isEqualTo(BIOMETRIC_STATE_CANCELLING_RESTARTING);
+ }
+
+ private void verifyFingerprintAuthenticateNeverCalled() {
+ verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyInt(), anyInt());
+ }
+
+ private void verifyFingerprintAuthenticateCall() {
+ verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
+ anyInt());
+ }
+
+ private void verifyFingerprintDetectNeverCalled() {
+ verify(mFingerprintManager, never()).detectFingerprint(any(), any(), anyInt());
+ }
+
+ private void verifyFingerprintDetectCall() {
+ verify(mFingerprintManager).detectFingerprint(any(), any(), anyInt());
+ }
+
+ private void verifyFaceAuthenticateNeverCalled() {
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
+ }
+
+ private void verifyFaceAuthenticateCall() {
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
+ }
+
+ private void verifyFaceDetectNeverCalled() {
+ verify(mFaceManager, never()).detectFace(any(), any(), anyInt());
+ }
+
+ private void verifyFaceDetectCall() {
+ verify(mFaceManager).detectFace(any(), any(), anyInt());
+ }
+
private void userDeviceLockDown() {
when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
when(mStrongAuthTracker.getStrongAuthForUser(mCurrentUserId))
@@ -2514,7 +2559,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.setSwitchingUser(true);
}
- private void fingerprintErrorLockedOut() {
+ private void fingerprintErrorTemporaryLockedOut() {
mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
.onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT, "Fingerprint locked out");
}
@@ -2654,6 +2699,30 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
receiver.setPendingResult(pendingResult);
}
+ private void givenDetectFingerprintWithClearingFingerprintManagerInvocations() {
+ // Clear invocations, since previous setup (e.g. registering BiometricManager callbacks)
+ // will trigger updateBiometricListeningState();
+ clearInvocations(mFingerprintManager);
+ mKeyguardUpdateMonitor.resetBiometricListeningState();
+
+ when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
+ mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
+ mTestableLooper.processAllMessages();
+ }
+
+ private void givenDetectFace() {
+ // GIVEN bypass is enabled, face detection is supported and strong auth is required
+ lockscreenBypassIsAllowed();
+ supportsFaceDetection();
+ strongAuthRequiredEncrypted();
+ keyguardIsVisible();
+ // fingerprint is NOT running, UDFPS is NOT supported
+
+ // WHEN the device wakes up
+ mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
+ mTestableLooper.processAllMessages();
+ }
+
private Intent putPhoneInfo(Intent intent, Bundle data, Boolean simInited) {
int subscription = simInited
? 1/* mock subid=1 */ : SubscriptionManager.PLACEHOLDER_SUBSCRIPTION_ID_BASE;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index b765ab3c5eac..a245c01d74de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -25,7 +25,9 @@ import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.keyguard.logging.KeyguardLogger
import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -109,6 +111,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
udfpsControllerProvider,
statusBarStateController,
featureFlags,
+ KeyguardLogger(logcatLogBuffer(AuthRippleController.TAG)),
rippleView
)
controller.init()
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 f57b35a6a5eb..3ec49b263c54 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -63,6 +63,7 @@ import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintA
import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.recents.OverviewProxyService
+import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -97,6 +98,7 @@ class SideFpsControllerTest : SysuiTestCase() {
@JvmField @Rule var rule = MockitoJUnit.rule()
+ @Mock lateinit var keyguardStateController: KeyguardStateController
@Mock lateinit var layoutInflater: LayoutInflater
@Mock lateinit var fingerprintManager: FingerprintManager
@Mock lateinit var windowManager: WindowManager
@@ -136,6 +138,7 @@ class SideFpsControllerTest : SysuiTestCase() {
keyguardBouncerRepository = FakeKeyguardBouncerRepository()
alternateBouncerInteractor =
AlternateBouncerInteractor(
+ keyguardStateController,
keyguardBouncerRepository,
FakeBiometricSettingsRepository(),
FakeDeviceEntryFingerprintAuthRepository(),
@@ -351,7 +354,9 @@ class SideFpsControllerTest : SysuiTestCase() {
deviceConfig = DeviceConfig.X_ALIGNED,
isReverseDefaultRotation = false,
{ rotation = Surface.ROTATION_0 }
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_90() =
@@ -359,7 +364,9 @@ class SideFpsControllerTest : SysuiTestCase() {
deviceConfig = DeviceConfig.X_ALIGNED,
isReverseDefaultRotation = false,
{ rotation = Surface.ROTATION_90 }
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_180() =
@@ -367,7 +374,9 @@ class SideFpsControllerTest : SysuiTestCase() {
deviceConfig = DeviceConfig.X_ALIGNED,
isReverseDefaultRotation = false,
{ rotation = Surface.ROTATION_180 }
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarCollapsedDownForXAlignedSensor_180() =
@@ -376,7 +385,9 @@ class SideFpsControllerTest : SysuiTestCase() {
isReverseDefaultRotation = false,
{ rotation = Surface.ROTATION_180 },
windowInsets = insetsForSmallNavbar()
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun hidesSfpsIndicatorWhenOccludingTaskbarForXAlignedSensor_180() =
@@ -385,7 +396,9 @@ class SideFpsControllerTest : SysuiTestCase() {
isReverseDefaultRotation = false,
{ rotation = Surface.ROTATION_180 },
windowInsets = insetsForLargeNavbar()
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_270() =
@@ -393,7 +406,9 @@ class SideFpsControllerTest : SysuiTestCase() {
deviceConfig = DeviceConfig.X_ALIGNED,
isReverseDefaultRotation = false,
{ rotation = Surface.ROTATION_270 }
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_InReverseDefaultRotation_0() =
@@ -401,7 +416,9 @@ class SideFpsControllerTest : SysuiTestCase() {
deviceConfig = DeviceConfig.X_ALIGNED,
isReverseDefaultRotation = true,
{ rotation = Surface.ROTATION_0 }
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_InReverseDefaultRotation_90() =
@@ -409,7 +426,9 @@ class SideFpsControllerTest : SysuiTestCase() {
deviceConfig = DeviceConfig.X_ALIGNED,
isReverseDefaultRotation = true,
{ rotation = Surface.ROTATION_90 }
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarCollapsedDownForXAlignedSensor_InReverseDefaultRotation_90() =
@@ -418,7 +437,9 @@ class SideFpsControllerTest : SysuiTestCase() {
isReverseDefaultRotation = true,
{ rotation = Surface.ROTATION_90 },
windowInsets = insetsForSmallNavbar()
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun hidesSfpsIndicatorWhenOccludingTaskbarForXAlignedSensor_InReverseDefaultRotation_90() =
@@ -427,7 +448,9 @@ class SideFpsControllerTest : SysuiTestCase() {
isReverseDefaultRotation = true,
{ rotation = Surface.ROTATION_90 },
windowInsets = insetsForLargeNavbar()
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_InReverseDefaultRotation_180() =
@@ -435,7 +458,9 @@ class SideFpsControllerTest : SysuiTestCase() {
deviceConfig = DeviceConfig.X_ALIGNED,
isReverseDefaultRotation = true,
{ rotation = Surface.ROTATION_180 }
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_InReverseDefaultRotation_270() =
@@ -443,7 +468,9 @@ class SideFpsControllerTest : SysuiTestCase() {
deviceConfig = DeviceConfig.X_ALIGNED,
isReverseDefaultRotation = true,
{ rotation = Surface.ROTATION_270 }
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_0() =
@@ -451,7 +478,9 @@ class SideFpsControllerTest : SysuiTestCase() {
deviceConfig = DeviceConfig.Y_ALIGNED,
isReverseDefaultRotation = false,
{ rotation = Surface.ROTATION_0 }
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_90() =
@@ -459,7 +488,9 @@ class SideFpsControllerTest : SysuiTestCase() {
deviceConfig = DeviceConfig.Y_ALIGNED,
isReverseDefaultRotation = false,
{ rotation = Surface.ROTATION_90 }
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_180() =
@@ -477,7 +508,9 @@ class SideFpsControllerTest : SysuiTestCase() {
deviceConfig = DeviceConfig.Y_ALIGNED,
isReverseDefaultRotation = false,
{ rotation = Surface.ROTATION_270 }
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarCollapsedDownForYAlignedSensor_270() =
@@ -486,7 +519,9 @@ class SideFpsControllerTest : SysuiTestCase() {
isReverseDefaultRotation = false,
{ rotation = Surface.ROTATION_270 },
windowInsets = insetsForSmallNavbar()
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun hidesSfpsIndicatorWhenOccludingTaskbarForYAlignedSensor_270() =
@@ -495,7 +530,9 @@ class SideFpsControllerTest : SysuiTestCase() {
isReverseDefaultRotation = false,
{ rotation = Surface.ROTATION_270 },
windowInsets = insetsForLargeNavbar()
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_InReverseDefaultRotation_0() =
@@ -503,7 +540,9 @@ class SideFpsControllerTest : SysuiTestCase() {
deviceConfig = DeviceConfig.Y_ALIGNED,
isReverseDefaultRotation = true,
{ rotation = Surface.ROTATION_0 }
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_InReverseDefaultRotation_90() =
@@ -521,7 +560,9 @@ class SideFpsControllerTest : SysuiTestCase() {
deviceConfig = DeviceConfig.Y_ALIGNED,
isReverseDefaultRotation = true,
{ rotation = Surface.ROTATION_180 }
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarCollapsedDownForYAlignedSensor_InReverseDefaultRotation_180() =
@@ -530,7 +571,9 @@ class SideFpsControllerTest : SysuiTestCase() {
isReverseDefaultRotation = true,
{ rotation = Surface.ROTATION_180 },
windowInsets = insetsForSmallNavbar()
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun hidesSfpsIndicatorWhenOccludingTaskbarForYAlignedSensor_InReverseDefaultRotation_180() =
@@ -539,7 +582,9 @@ class SideFpsControllerTest : SysuiTestCase() {
isReverseDefaultRotation = true,
{ rotation = Surface.ROTATION_180 },
windowInsets = insetsForLargeNavbar()
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false)
+ }
@Test
fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_InReverseDefaultRotation_270() =
@@ -547,7 +592,9 @@ class SideFpsControllerTest : SysuiTestCase() {
deviceConfig = DeviceConfig.Y_ALIGNED,
isReverseDefaultRotation = true,
{ rotation = Surface.ROTATION_270 }
- ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) }
+ ) {
+ verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
+ }
@Test
fun verifiesSfpsIndicatorNotAddedInRearDisplayMode_0() =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
index 54c9d392ad1c..86fb279d4ed6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
@@ -37,6 +37,7 @@ import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.time.FakeSystemClock
import com.android.systemui.util.time.SystemClock
import kotlinx.coroutines.Dispatchers
@@ -92,6 +93,7 @@ class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControlle
)
mAlternateBouncerInteractor =
AlternateBouncerInteractor(
+ mock(KeyguardStateController::class.java),
keyguardBouncerRepository,
mock(BiometricSettingsRepository::class.java),
mock(DeviceEntryFingerprintAuthRepository::class.java),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java
index 35039026fe9e..9d16185e75c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java
@@ -45,8 +45,8 @@ import org.mockito.MockitoAnnotations;
public class BroadcastDialogTest extends SysuiTestCase {
private static final String CURRENT_BROADCAST_APP = "Music";
- private static final String SWITCH_APP = "Files by Google";
- private static final String TEST_PACKAGE = "com.google.android.apps.nbu.files";
+ private static final String SWITCH_APP = "System UI";
+ private static final String TEST_PACKAGE = "com.android.systemui";
private BroadcastDialog mBroadcastDialog;
private View mDialogView;
private TextView mTitle;
@@ -59,6 +59,7 @@ public class BroadcastDialogTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mBroadcastDialog = new BroadcastDialog(mContext, mock(MediaOutputDialogFactory.class),
CURRENT_BROADCAST_APP, TEST_PACKAGE, mock(UiEventLogger.class));
+
mBroadcastDialog.show();
mDialogView = mBroadcastDialog.mDialogView;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
index faa5db4327a6..ab6d5b771d5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
@@ -94,7 +94,9 @@ public class DistanceClassifierTest extends ClassifierTest {
mClassifier.onTouchEvent(appendMoveEvent(1, 16, 3));
mClassifier.onTouchEvent(appendMoveEvent(1, 17, 300));
mClassifier.onTouchEvent(appendMoveEvent(1, 18, 301));
- mClassifier.onTouchEvent(appendUpEvent(1, 19, 501));
+ mClassifier.onTouchEvent(appendMoveEvent(1, 19, 501));
+ mClassifier.onTouchEvent(appendUpEvent(1, 19, 501)); //event will be dropped
+
assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
index 2edc3d361316..8eadadff1ca5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
@@ -75,16 +75,17 @@ public class FalsingDataProviderTest extends ClassifierTest {
}
@Test
- public void test_trackMotionEvents() {
+ public void test_trackMotionEvents_dropUpEvent() {
mDataProvider.onMotionEvent(appendDownEvent(2, 9));
mDataProvider.onMotionEvent(appendMoveEvent(4, 7));
- mDataProvider.onMotionEvent(appendUpEvent(6, 5));
+ mDataProvider.onMotionEvent(appendMoveEvent(6, 5));
+ mDataProvider.onMotionEvent(appendUpEvent(0, 0)); // event will be dropped
List<MotionEvent> motionEventList = mDataProvider.getRecentMotionEvents();
assertThat(motionEventList.size()).isEqualTo(3);
assertThat(motionEventList.get(0).getActionMasked()).isEqualTo(MotionEvent.ACTION_DOWN);
assertThat(motionEventList.get(1).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE);
- assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_UP);
+ assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE);
assertThat(motionEventList.get(0).getEventTime()).isEqualTo(1L);
assertThat(motionEventList.get(1).getEventTime()).isEqualTo(2L);
assertThat(motionEventList.get(2).getEventTime()).isEqualTo(3L);
@@ -97,6 +98,28 @@ public class FalsingDataProviderTest extends ClassifierTest {
}
@Test
+ public void test_trackMotionEvents_keepUpEvent() {
+ mDataProvider.onMotionEvent(appendDownEvent(2, 9));
+ mDataProvider.onMotionEvent(appendMoveEvent(4, 7));
+ mDataProvider.onMotionEvent(appendUpEvent(0, 0, 100));
+ List<MotionEvent> motionEventList = mDataProvider.getRecentMotionEvents();
+
+ assertThat(motionEventList.size()).isEqualTo(3);
+ assertThat(motionEventList.get(0).getActionMasked()).isEqualTo(MotionEvent.ACTION_DOWN);
+ assertThat(motionEventList.get(1).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE);
+ assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_UP);
+ assertThat(motionEventList.get(0).getEventTime()).isEqualTo(1L);
+ assertThat(motionEventList.get(1).getEventTime()).isEqualTo(2L);
+ assertThat(motionEventList.get(2).getEventTime()).isEqualTo(100);
+ assertThat(motionEventList.get(0).getX()).isEqualTo(2f);
+ assertThat(motionEventList.get(1).getX()).isEqualTo(4f);
+ assertThat(motionEventList.get(2).getX()).isEqualTo(0f);
+ assertThat(motionEventList.get(0).getY()).isEqualTo(9f);
+ assertThat(motionEventList.get(1).getY()).isEqualTo(7f);
+ assertThat(motionEventList.get(2).getY()).isEqualTo(0f);
+ }
+
+ @Test
public void test_trackRecentMotionEvents() {
mDataProvider.onMotionEvent(appendDownEvent(2, 9, 1));
mDataProvider.onMotionEvent(appendMoveEvent(4, 7, 800));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
index c343c20398e9..ae2b8bbb4ce6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
@@ -68,6 +68,15 @@ public class ZigZagClassifierTest extends ClassifierTest {
}
@Test
+ public void testPass_dropClosingUpEvent() {
+ appendMoveEvent(0, 0);
+ appendMoveEvent(0, 100);
+ appendMoveEvent(0, 200);
+ appendUpEvent(0, 180); // this event would push us over the maxDevianceY
+ assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
+ }
+
+ @Test
public void testPass_fewTouchesHorizontal() {
assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
appendMoveEvent(0, 0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
index 2099281d694a..ffd75fb9bbc6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.app.RemoteAction;
import android.content.ClipData;
import android.content.ClipDescription;
@@ -101,6 +102,9 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
private ArgumentCaptor<ClipboardOverlayView.ClipboardOverlayCallbacks> mOverlayCallbacksCaptor;
private ClipboardOverlayView.ClipboardOverlayCallbacks mCallbacks;
+ @Captor
+ private ArgumentCaptor<AnimatorListenerAdapter> mAnimatorArgumentCaptor;
+
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
@Before
@@ -446,7 +450,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true);
when(mClipboardUtils.isRemoteCopy(any(Context.class), any(ClipData.class), anyString()))
.thenReturn(true);
- when(mClipboardUtils.getAction(any(CharSequence.class), any(TextLinks.class), anyString()))
+ when(mClipboardUtils.getAction(any(TextLinks.class), anyString()))
.thenReturn(Optional.of(Mockito.mock(RemoteAction.class)));
when(mClipboardOverlayView.post(any(Runnable.class))).thenAnswer(new Answer<Object>() {
@Override
@@ -478,12 +482,16 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
when(mClipboardOverlayWindow.getWindowInsets()).thenReturn(
getImeInsets(new Rect(0, 0, 0, 1)));
mOverlayController.setClipData(mSampleClipData, "");
+ Animator mockFadeoutAnimator = Mockito.mock(Animator.class);
+ when(mClipboardOverlayView.getMinimizedFadeoutAnimation()).thenReturn(mockFadeoutAnimator);
verify(mClipboardOverlayView).setMinimized(true);
verify(mClipboardOverlayView, never()).setMinimized(false);
verify(mClipboardOverlayView, never()).showTextPreview(any(), anyBoolean());
mCallbacks.onMinimizedViewTapped();
+ verify(mockFadeoutAnimator).addListener(mAnimatorArgumentCaptor.capture());
+ mAnimatorArgumentCaptor.getValue().onAnimationEnd(mockFadeoutAnimator);
verify(mClipboardOverlayView).setMinimized(false);
verify(mClipboardOverlayView).showTextPreview("Test Item", false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
index aea6be3d468b..3d8f04e08825 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.when;
@@ -77,6 +78,74 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase {
@Test
public void test_getAction_noLinks_returnsEmptyOptional() {
+ Optional<RemoteAction> action =
+ mClipboardUtils.getAction(Mockito.mock(TextLinks.class), "abc");
+
+ assertTrue(action.isEmpty());
+ }
+
+ @Test
+ public void test_getAction_returnsFirstLink() {
+ TextLinks links = getFakeTextLinksBuilder().build();
+ RemoteAction actionA = constructRemoteAction("abc");
+ RemoteAction actionB = constructRemoteAction("def");
+ TextClassification classificationA = Mockito.mock(TextClassification.class);
+ when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
+ TextClassification classificationB = Mockito.mock(TextClassification.class);
+ when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
+ when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn(
+ classificationA, classificationB);
+
+ RemoteAction result = mClipboardUtils.getAction(links, "test").orElse(null);
+
+ assertEquals(actionA, result);
+ }
+
+ @Test
+ public void test_getAction_skipsMatchingComponent() {
+ TextLinks links = getFakeTextLinksBuilder().build();
+ RemoteAction actionA = constructRemoteAction("abc");
+ RemoteAction actionB = constructRemoteAction("def");
+ TextClassification classificationA = Mockito.mock(TextClassification.class);
+ when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
+ TextClassification classificationB = Mockito.mock(TextClassification.class);
+ when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
+ when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn(
+ classificationA, classificationB);
+
+ RemoteAction result = mClipboardUtils.getAction(links, "abc").orElse(null);
+
+ assertEquals(actionB, result);
+ }
+
+ @Test
+ public void test_getAction_skipsShortEntity() {
+ TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22");
+ final Map<String, Float> scores = new ArrayMap<>();
+ scores.put(TextClassifier.TYPE_EMAIL, 1f);
+ textLinks.addLink(20, 22, scores);
+ textLinks.addLink(0, 22, scores);
+
+ RemoteAction actionA = constructRemoteAction("abc");
+ RemoteAction actionB = constructRemoteAction("def");
+ TextClassification classificationA = Mockito.mock(TextClassification.class);
+ when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
+ TextClassification classificationB = Mockito.mock(TextClassification.class);
+ when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
+ when(mTextClassifier.classifyText(anyString(), eq(20), eq(22), isNull())).thenReturn(
+ classificationA);
+ when(mTextClassifier.classifyText(anyString(), eq(0), eq(22), isNull())).thenReturn(
+ classificationB);
+
+ RemoteAction result = mClipboardUtils.getAction(textLinks.build(), "test").orElse(null);
+
+ assertEquals(actionB, result);
+ }
+
+ // TODO(b/267162944): Next four tests (marked "legacy") are obsolete once
+ // CLIPBOARD_MINIMIZED_LAYOUT flag is released and removed
+ @Test
+ public void test_getAction_noLinks_returnsEmptyOptional_legacy() {
ClipData.Item item = new ClipData.Item("no text links");
item.setTextLinks(Mockito.mock(TextLinks.class));
@@ -86,8 +155,8 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase {
}
@Test
- public void test_getAction_returnsFirstLink() {
- when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinks());
+ public void test_getAction_returnsFirstLink_legacy() {
+ when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinksBuilder().build());
when(mClipDataItem.getText()).thenReturn("");
RemoteAction actionA = constructRemoteAction("abc");
RemoteAction actionB = constructRemoteAction("def");
@@ -98,14 +167,14 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase {
when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn(
classificationA, classificationB);
- RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "def").orElse(null);
+ RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "test").orElse(null);
assertEquals(actionA, result);
}
@Test
- public void test_getAction_skipsMatchingComponent() {
- when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinks());
+ public void test_getAction_skipsMatchingComponent_legacy() {
+ when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinksBuilder().build());
when(mClipDataItem.getText()).thenReturn("");
RemoteAction actionA = constructRemoteAction("abc");
RemoteAction actionB = constructRemoteAction("def");
@@ -122,6 +191,33 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase {
}
@Test
+ public void test_getAction_skipsShortEntity_legacy() {
+ TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22");
+ final Map<String, Float> scores = new ArrayMap<>();
+ scores.put(TextClassifier.TYPE_EMAIL, 1f);
+ textLinks.addLink(20, 22, scores);
+ textLinks.addLink(0, 22, scores);
+
+ when(mClipDataItem.getTextLinks()).thenReturn(textLinks.build());
+ when(mClipDataItem.getText()).thenReturn(textLinks.build().getText());
+
+ RemoteAction actionA = constructRemoteAction("abc");
+ RemoteAction actionB = constructRemoteAction("def");
+ TextClassification classificationA = Mockito.mock(TextClassification.class);
+ when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
+ TextClassification classificationB = Mockito.mock(TextClassification.class);
+ when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
+ when(mTextClassifier.classifyText(anyString(), eq(20), eq(22), isNull())).thenReturn(
+ classificationA);
+ when(mTextClassifier.classifyText(anyString(), eq(0), eq(22), isNull())).thenReturn(
+ classificationB);
+
+ RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "test").orElse(null);
+
+ assertEquals(actionB, result);
+ }
+
+ @Test
public void test_extra_withPackage_returnsTrue() {
PersistableBundle b = new PersistableBundle();
b.putBoolean(ClipDescription.EXTRA_IS_REMOTE_DEVICE, true);
@@ -184,12 +280,12 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase {
return action;
}
- private static TextLinks getFakeTextLinks() {
- TextLinks.Builder textLinks = new TextLinks.Builder("test");
+ private static TextLinks.Builder getFakeTextLinksBuilder() {
+ TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22");
final Map<String, Float> scores = new ArrayMap<>();
scores.put(TextClassifier.TYPE_EMAIL, 1f);
- textLinks.addLink(0, 0, scores);
- textLinks.addLink(0, 0, scores);
- return textLinks.build();
+ textLinks.addLink(0, 22, scores);
+ textLinks.addLink(0, 22, scores);
+ return textLinks;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
index e35b2a384bd0..c98d5374311d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
@@ -34,16 +34,15 @@ import com.android.systemui.controls.ControlStatus
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
+import com.android.systemui.controls.panels.FakeSelectedComponentRepository
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.dump.DumpManager
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
-import java.io.File
-import java.util.Optional
-import java.util.function.Consumer
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
@@ -59,6 +58,7 @@ import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
@@ -67,8 +67,10 @@ import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.Mockito.`when`
-import org.mockito.Mockito.clearInvocations
import org.mockito.MockitoAnnotations
+import java.io.File
+import java.util.*
+import java.util.function.Consumer
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -107,6 +109,8 @@ class ControlsControllerImplTest : SysuiTestCase() {
private lateinit var listingCallbackCaptor:
ArgumentCaptor<ControlsListingController.ControlsListingCallback>
+ private val preferredPanelRepository = FakeSelectedComponentRepository()
+
private lateinit var delayableExecutor: FakeExecutor
private lateinit var controller: ControlsControllerImpl
private lateinit var canceller: DidRunRunnable
@@ -146,6 +150,7 @@ class ControlsControllerImplTest : SysuiTestCase() {
fun setUp() {
MockitoAnnotations.initMocks(this)
+ whenever(authorizedPanelsRepository.getAuthorizedPanels()).thenReturn(setOf())
`when`(userTracker.userHandle).thenReturn(UserHandle.of(user))
delayableExecutor = FakeExecutor(FakeSystemClock())
@@ -166,6 +171,7 @@ class ControlsControllerImplTest : SysuiTestCase() {
wrapper,
delayableExecutor,
uiController,
+ preferredPanelRepository,
bindingController,
listingController,
userFileManager,
@@ -219,6 +225,7 @@ class ControlsControllerImplTest : SysuiTestCase() {
mContext,
delayableExecutor,
uiController,
+ preferredPanelRepository,
bindingController,
listingController,
userFileManager,
@@ -238,6 +245,7 @@ class ControlsControllerImplTest : SysuiTestCase() {
mContext,
delayableExecutor,
uiController,
+ preferredPanelRepository,
bindingController,
listingController,
userFileManager,
@@ -945,6 +953,28 @@ class ControlsControllerImplTest : SysuiTestCase() {
controller.bindComponentForPanel(TEST_COMPONENT)
verify(bindingController).bindServiceForPanel(TEST_COMPONENT)
}
+
+ @Test
+ fun testRemoveFavoriteRemovesFavorite() {
+ val componentName = ComponentName(context, "test.Cls")
+ controller.addFavorite(
+ componentName,
+ "test structure",
+ ControlInfo(
+ controlId = "testId",
+ controlTitle = "Test Control",
+ controlSubtitle = "test control subtitle",
+ deviceType = DeviceTypes.TYPE_LIGHT,
+ ),
+ )
+
+ controller.removeFavorites(componentName)
+ delayableExecutor.runAllReady()
+
+ verify(authorizedPanelsRepository)
+ .removeAuthorizedPanels(eq(setOf(componentName.packageName)))
+ assertThat(controller.getFavorites()).isEmpty()
+ }
}
private class DidRunRunnable() : Runnable {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt
index b91a3fd4b28c..272f5895390c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt
@@ -22,6 +22,8 @@ import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.FakeSharedPreferences
@@ -40,6 +42,8 @@ class AuthorizedPanelsRepositoryImplTest : SysuiTestCase() {
@Mock private lateinit var userTracker: UserTracker
+ private val featureFlags = FakeFeatureFlags()
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -48,6 +52,7 @@ class AuthorizedPanelsRepositoryImplTest : SysuiTestCase() {
arrayOf<String>()
)
whenever(userTracker.userId).thenReturn(0)
+ featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, true)
}
@Test
@@ -115,8 +120,37 @@ class AuthorizedPanelsRepositoryImplTest : SysuiTestCase() {
assertThat(sharedPrefs.getStringSet(KEY, null)).containsExactly(TEST_PACKAGE)
}
+ @Test
+ fun testRemoveAuthorizedPackageRemovesIt() {
+ val sharedPrefs = FakeSharedPreferences()
+ val fileManager = FakeUserFileManager(mapOf(0 to sharedPrefs))
+ val repository = createRepository(fileManager)
+ repository.addAuthorizedPanels(setOf(TEST_PACKAGE))
+
+ repository.removeAuthorizedPanels(setOf(TEST_PACKAGE))
+
+ assertThat(sharedPrefs.getStringSet(KEY, null)).isEmpty()
+ }
+
+ @Test
+ fun testSetAuthorizedPackageAfterFeatureDisabled() {
+ mContext.orCreateTestableResources.addOverride(
+ R.array.config_controlsPreferredPackages,
+ arrayOf(TEST_PACKAGE)
+ )
+ val sharedPrefs = FakeSharedPreferences()
+ val fileManager = FakeUserFileManager(mapOf(0 to sharedPrefs))
+ val repository = createRepository(fileManager)
+
+ repository.removeAuthorizedPanels(setOf(TEST_PACKAGE))
+
+ featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, false)
+
+ assertThat(repository.getAuthorizedPanels()).isEqualTo(setOf(TEST_PACKAGE))
+ }
+
private fun createRepository(userFileManager: UserFileManager): AuthorizedPanelsRepositoryImpl {
- return AuthorizedPanelsRepositoryImpl(mContext, userFileManager, userTracker)
+ return AuthorizedPanelsRepositoryImpl(mContext, userFileManager, userTracker, featureFlags)
}
private class FakeUserFileManager(private val sharedPrefs: Map<Int, SharedPreferences>) :
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/FakeSelectedComponentRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/FakeSelectedComponentRepository.kt
new file mode 100644
index 000000000000..a7677cca9f29
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/FakeSelectedComponentRepository.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.controls.panels
+
+class FakeSelectedComponentRepository : SelectedComponentRepository {
+
+ private var selectedComponent: SelectedComponentRepository.SelectedComponent? = null
+ private var shouldAddDefaultPanel: Boolean = true
+
+ override fun getSelectedComponent(): SelectedComponentRepository.SelectedComponent? =
+ selectedComponent
+
+ override fun setSelectedComponent(
+ selectedComponent: SelectedComponentRepository.SelectedComponent
+ ) {
+ this.selectedComponent = selectedComponent
+ }
+
+ override fun removeSelectedComponent() {
+ selectedComponent = null
+ }
+
+ override fun shouldAddDefaultComponent(): Boolean = shouldAddDefaultPanel
+
+ override fun setShouldAddDefaultComponent(shouldAdd: Boolean) {
+ shouldAddDefaultPanel = shouldAdd
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt
new file mode 100644
index 000000000000..0c7b9cb82b94
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt
@@ -0,0 +1,163 @@
+/*
+ * 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.controls.panels
+
+import android.content.ComponentName
+import android.content.SharedPreferences
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.settings.UserFileManager
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
+import com.android.systemui.util.FakeSharedPreferences
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class SelectedComponentRepositoryTest : SysuiTestCase() {
+
+ private companion object {
+ val COMPONENT_A =
+ SelectedComponentRepository.SelectedComponent(
+ name = "a",
+ componentName = ComponentName.unflattenFromString("pkg/.cls_a"),
+ isPanel = false,
+ )
+ val COMPONENT_B =
+ SelectedComponentRepository.SelectedComponent(
+ name = "b",
+ componentName = ComponentName.unflattenFromString("pkg/.cls_b"),
+ isPanel = false,
+ )
+ }
+
+ @Mock private lateinit var userTracker: UserTracker
+ @Mock private lateinit var userFileManager: UserFileManager
+
+ private val featureFlags = FakeFeatureFlags()
+ private val sharedPreferences: SharedPreferences = FakeSharedPreferences()
+
+ // under test
+ private lateinit var repository: SelectedComponentRepository
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(userFileManager.getSharedPreferences(any(), any(), any()))
+ .thenReturn(sharedPreferences)
+
+ repository = SelectedComponentRepositoryImpl(userFileManager, userTracker, featureFlags)
+ }
+
+ @Test
+ fun testUnsetIsNull() {
+ assertThat(repository.getSelectedComponent()).isNull()
+ }
+
+ @Test
+ fun testGetReturnsSet() {
+ repository.setSelectedComponent(COMPONENT_A)
+
+ assertThat(repository.getSelectedComponent()).isEqualTo(COMPONENT_A)
+ }
+
+ @Test
+ fun testSetOverrides() {
+ repository.setSelectedComponent(COMPONENT_A)
+ repository.setSelectedComponent(COMPONENT_B)
+
+ assertThat(repository.getSelectedComponent()).isEqualTo(COMPONENT_B)
+ }
+
+ @Test
+ fun testRemove() {
+ repository.setSelectedComponent(COMPONENT_A)
+
+ repository.removeSelectedComponent()
+
+ assertThat(repository.getSelectedComponent()).isNull()
+ }
+
+ @Test
+ fun testFeatureEnabled_shouldAddDefaultPanelDefaultsToTrue() {
+ featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, true)
+
+ assertThat(repository.shouldAddDefaultComponent()).isTrue()
+ }
+
+ @Test
+ fun testFeatureDisabled_shouldAddDefaultPanelDefaultsToTrue() {
+ featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, false)
+
+ assertThat(repository.shouldAddDefaultComponent()).isTrue()
+ }
+
+ @Test
+ fun testFeatureEnabled_shouldAddDefaultPanelChecked() {
+ featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, true)
+ repository.setShouldAddDefaultComponent(false)
+
+ assertThat(repository.shouldAddDefaultComponent()).isFalse()
+ }
+
+ @Test
+ fun testFeatureDisabled_shouldAlwaysAddDefaultPanelAlwaysTrue() {
+ featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, false)
+ repository.setShouldAddDefaultComponent(false)
+
+ assertThat(repository.shouldAddDefaultComponent()).isTrue()
+ }
+
+ @Test
+ fun testGetPreferredStructure_differentUserId() {
+ sharedPreferences.savePanel(COMPONENT_A)
+ whenever(
+ userFileManager.getSharedPreferences(
+ DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
+ 0,
+ 1,
+ )
+ )
+ .thenReturn(FakeSharedPreferences().also { it.savePanel(COMPONENT_B) })
+
+ val previousPreferredStructure = repository.getSelectedComponent()
+ whenever(userTracker.userId).thenReturn(1)
+ val currentPreferredStructure = repository.getSelectedComponent()
+
+ assertThat(previousPreferredStructure).isEqualTo(COMPONENT_A)
+ assertThat(currentPreferredStructure).isNotEqualTo(previousPreferredStructure)
+ assertThat(currentPreferredStructure).isEqualTo(COMPONENT_B)
+ }
+
+ private fun SharedPreferences.savePanel(panel: SelectedComponentRepository.SelectedComponent) {
+ edit()
+ .putString("controls_component", panel.componentName?.flattenToString())
+ .putString("controls_structure", panel.name)
+ .putBoolean("controls_is_panel", panel.isPanel)
+ .commit()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt
index 0c9986d82447..5a613aa9225e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt
@@ -104,7 +104,9 @@ class ControlsSettingsDialogManagerImplTest : SysuiTestCase() {
controlsSettingsRepository,
userTracker,
activityStarter
- ) { context, _ -> TestableAlertDialog(context).also { dialog = it } }
+ ) { context, _ ->
+ TestableAlertDialog(context).also { dialog = it }
+ }
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt
index 7ecaca6c36d0..9d8084d4f2f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt
@@ -23,17 +23,19 @@ import android.content.pm.ApplicationInfo
import android.content.pm.ServiceInfo
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.dagger.ControlsComponent
import com.android.systemui.controls.management.ControlsListingController
+import com.android.systemui.controls.panels.AuthorizedPanelsRepository
+import com.android.systemui.controls.panels.FakeSelectedComponentRepository
import com.android.systemui.controls.ui.SelectedItem
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import java.util.Optional
import org.junit.Before
@@ -53,16 +55,16 @@ class ControlsStartableTest : SysuiTestCase() {
@Mock private lateinit var controlsController: ControlsController
@Mock private lateinit var controlsListingController: ControlsListingController
@Mock private lateinit var userTracker: UserTracker
+ @Mock private lateinit var authorizedPanelsRepository: AuthorizedPanelsRepository
+
+ private val preferredPanelsRepository = FakeSelectedComponentRepository()
private lateinit var fakeExecutor: FakeExecutor
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- context.orCreateTestableResources.addOverride(
- R.array.config_controlsPreferredPackages,
- arrayOf<String>()
- )
+ whenever(authorizedPanelsRepository.getPreferredPackages()).thenReturn(setOf())
fakeExecutor = FakeExecutor(FakeSystemClock())
}
@@ -87,10 +89,8 @@ class ControlsStartableTest : SysuiTestCase() {
@Test
fun testPreferredPackagesNotInstalled_noNewSelection() {
- context.orCreateTestableResources.addOverride(
- R.array.config_controlsPreferredPackages,
- arrayOf(TEST_PACKAGE_PANEL)
- )
+ whenever(authorizedPanelsRepository.getPreferredPackages())
+ .thenReturn(setOf(TEST_PACKAGE_PANEL))
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
`when`(controlsListingController.getCurrentServices()).thenReturn(emptyList())
@@ -101,10 +101,8 @@ class ControlsStartableTest : SysuiTestCase() {
@Test
fun testPreferredPackageNotPanel_noNewSelection() {
- context.orCreateTestableResources.addOverride(
- R.array.config_controlsPreferredPackages,
- arrayOf(TEST_PACKAGE_PANEL)
- )
+ whenever(authorizedPanelsRepository.getPreferredPackages())
+ .thenReturn(setOf(TEST_PACKAGE_PANEL))
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT, "not panel", hasPanel = false))
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
@@ -116,10 +114,8 @@ class ControlsStartableTest : SysuiTestCase() {
@Test
fun testExistingSelection_noNewSelection() {
- context.orCreateTestableResources.addOverride(
- R.array.config_controlsPreferredPackages,
- arrayOf(TEST_PACKAGE_PANEL)
- )
+ whenever(authorizedPanelsRepository.getPreferredPackages())
+ .thenReturn(setOf(TEST_PACKAGE_PANEL))
`when`(controlsController.getPreferredSelection())
.thenReturn(mock<SelectedItem.PanelItem>())
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
@@ -132,10 +128,8 @@ class ControlsStartableTest : SysuiTestCase() {
@Test
fun testPanelAdded() {
- context.orCreateTestableResources.addOverride(
- R.array.config_controlsPreferredPackages,
- arrayOf(TEST_PACKAGE_PANEL)
- )
+ whenever(authorizedPanelsRepository.getPreferredPackages())
+ .thenReturn(setOf(TEST_PACKAGE_PANEL))
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
@@ -147,10 +141,8 @@ class ControlsStartableTest : SysuiTestCase() {
@Test
fun testMultiplePreferredOnlyOnePanel_panelAdded() {
- context.orCreateTestableResources.addOverride(
- R.array.config_controlsPreferredPackages,
- arrayOf("other_package", TEST_PACKAGE_PANEL)
- )
+ whenever(authorizedPanelsRepository.getPreferredPackages())
+ .thenReturn(setOf(TEST_PACKAGE_PANEL))
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
val listings =
listOf(
@@ -166,10 +158,8 @@ class ControlsStartableTest : SysuiTestCase() {
@Test
fun testMultiplePreferredMultiplePanels_firstPreferredAdded() {
- context.orCreateTestableResources.addOverride(
- R.array.config_controlsPreferredPackages,
- arrayOf(TEST_PACKAGE_PANEL, "other_package")
- )
+ whenever(authorizedPanelsRepository.getPreferredPackages())
+ .thenReturn(setOf(TEST_PACKAGE_PANEL))
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
val listings =
listOf(
@@ -217,6 +207,20 @@ class ControlsStartableTest : SysuiTestCase() {
verify(controlsController, never()).bindComponentForPanel(any())
}
+ @Test
+ fun testAlreadyAddedPanel_noNewSelection() {
+ preferredPanelsRepository.setShouldAddDefaultComponent(false)
+ whenever(authorizedPanelsRepository.getPreferredPackages())
+ .thenReturn(setOf(TEST_PACKAGE_PANEL))
+ `when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
+ val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
+ `when`(controlsListingController.getCurrentServices()).thenReturn(listings)
+
+ createStartable(enabled = true).start()
+
+ verify(controlsController, never()).setPreferredSelection(any())
+ }
+
private fun createStartable(enabled: Boolean): ControlsStartable {
val component: ControlsComponent =
mock() {
@@ -230,7 +234,13 @@ class ControlsStartableTest : SysuiTestCase() {
`when`(getControlsListingController()).thenReturn(Optional.empty())
}
}
- return ControlsStartable(context.resources, fakeExecutor, component, userTracker)
+ return ControlsStartable(
+ fakeExecutor,
+ component,
+ userTracker,
+ authorizedPanelsRepository,
+ preferredPanelsRepository,
+ )
}
private fun ControlsServiceInfo(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsDialogsFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsDialogsFactoryTest.kt
new file mode 100644
index 000000000000..1e8cd4117688
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsDialogsFactoryTest.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.controls.ui
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.FakeSystemUIDialogController
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class ControlsDialogsFactoryTest : SysuiTestCase() {
+
+ private companion object {
+ const val APP_NAME = "Test App"
+ }
+
+ private val fakeDialogController = FakeSystemUIDialogController()
+
+ private lateinit var underTest: ControlsDialogsFactory
+
+ @Before
+ fun setup() {
+ underTest = ControlsDialogsFactory { fakeDialogController.dialog }
+ }
+
+ @Test
+ fun testCreatesRemoveAppDialog() {
+ val dialog = underTest.createRemoveAppDialog(context, APP_NAME) {}
+
+ verify(dialog)
+ .setTitle(
+ eq(context.getString(R.string.controls_panel_remove_app_authorization, APP_NAME))
+ )
+ verify(dialog).setCanceledOnTouchOutside(eq(true))
+ }
+
+ @Test
+ fun testPositiveClickRemoveAppDialogWorks() {
+ var dialogResult: Boolean? = null
+ underTest.createRemoveAppDialog(context, APP_NAME) { dialogResult = it }
+
+ fakeDialogController.clickPositive()
+
+ assertThat(dialogResult).isTrue()
+ }
+
+ @Test
+ fun testNeutralClickRemoveAppDialogWorks() {
+ var dialogResult: Boolean? = null
+ underTest.createRemoveAppDialog(context, APP_NAME) { dialogResult = it }
+
+ fakeDialogController.clickNeutral()
+
+ assertThat(dialogResult).isFalse()
+ }
+
+ @Test
+ fun testCancelRemoveAppDialogWorks() {
+ var dialogResult: Boolean? = null
+ underTest.createRemoveAppDialog(context, APP_NAME) { dialogResult = it }
+
+ fakeDialogController.cancel()
+
+ assertThat(dialogResult).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
index aa90e2a45f10..3f61bf75740a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
@@ -42,16 +42,15 @@ import com.android.systemui.controls.controller.StructureInfo
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
+import com.android.systemui.controls.panels.FakeSelectedComponentRepository
+import com.android.systemui.controls.panels.SelectedComponentRepository
import com.android.systemui.controls.settings.FakeControlsSettingsRepository
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
-import com.android.systemui.shade.ShadeController
-import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.util.FakeSharedPreferences
+import com.android.systemui.util.FakeSystemUIDialogController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
@@ -63,15 +62,12 @@ import com.android.systemui.util.time.FakeSystemClock
import com.android.wm.shell.TaskView
import com.android.wm.shell.TaskViewFactory
import com.google.common.truth.Truth.assertThat
-import dagger.Lazy
import java.util.Optional
import java.util.function.Consumer
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.anyInt
-import org.mockito.Mockito.anyString
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
@@ -87,24 +83,24 @@ class ControlsUiControllerImplTest : SysuiTestCase() {
@Mock lateinit var controlsListingController: ControlsListingController
@Mock lateinit var controlActionCoordinator: ControlActionCoordinator
@Mock lateinit var activityStarter: ActivityStarter
- @Mock lateinit var shadeController: ShadeController
@Mock lateinit var iconCache: CustomIconCache
@Mock lateinit var controlsMetricsLogger: ControlsMetricsLogger
@Mock lateinit var keyguardStateController: KeyguardStateController
- @Mock lateinit var userFileManager: UserFileManager
@Mock lateinit var userTracker: UserTracker
@Mock lateinit var taskViewFactory: TaskViewFactory
@Mock lateinit var dumpManager: DumpManager
@Mock lateinit var authorizedPanelsRepository: AuthorizedPanelsRepository
@Mock lateinit var featureFlags: FeatureFlags
@Mock lateinit var packageManager: PackageManager
- val sharedPreferences = FakeSharedPreferences()
- lateinit var controlsSettingsRepository: FakeControlsSettingsRepository
- var uiExecutor = FakeExecutor(FakeSystemClock())
- var bgExecutor = FakeExecutor(FakeSystemClock())
- lateinit var underTest: ControlsUiControllerImpl
- lateinit var parent: FrameLayout
+ private val preferredPanelRepository = FakeSelectedComponentRepository()
+ private val fakeDialogController = FakeSystemUIDialogController()
+ private val uiExecutor = FakeExecutor(FakeSystemClock())
+ private val bgExecutor = FakeExecutor(FakeSystemClock())
+
+ private lateinit var controlsSettingsRepository: FakeControlsSettingsRepository
+ private lateinit var parent: FrameLayout
+ private lateinit var underTest: ControlsUiControllerImpl
@Before
fun setup() {
@@ -125,104 +121,41 @@ class ControlsUiControllerImplTest : SysuiTestCase() {
underTest =
ControlsUiControllerImpl(
- Lazy { controlsController },
+ { controlsController },
context,
packageManager,
uiExecutor,
bgExecutor,
- Lazy { controlsListingController },
+ { controlsListingController },
controlActionCoordinator,
activityStarter,
iconCache,
controlsMetricsLogger,
keyguardStateController,
- userFileManager,
userTracker,
Optional.of(taskViewFactory),
controlsSettingsRepository,
authorizedPanelsRepository,
+ preferredPanelRepository,
featureFlags,
- dumpManager
- )
- `when`(
- userFileManager.getSharedPreferences(
- DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
- 0,
- 0
- )
+ ControlsDialogsFactory { fakeDialogController.dialog },
+ dumpManager,
)
- .thenReturn(sharedPreferences)
- `when`(userFileManager.getSharedPreferences(anyString(), anyInt(), anyInt()))
- .thenReturn(sharedPreferences)
`when`(userTracker.userId).thenReturn(0)
`when`(userTracker.userHandle).thenReturn(UserHandle.of(0))
}
@Test
- fun testGetPreferredStructure() {
- val structureInfo = mock<StructureInfo>()
- underTest.getPreferredSelectedItem(listOf(structureInfo))
- verify(userFileManager)
- .getSharedPreferences(
- fileName = DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
- mode = 0,
- userId = 0
- )
- }
-
- @Test
- fun testGetPreferredStructure_differentUserId() {
- val selectedItems =
- listOf(
- SelectedItem.StructureItem(
- StructureInfo(ComponentName.unflattenFromString("pkg/.cls1"), "a", ArrayList())
- ),
- SelectedItem.StructureItem(
- StructureInfo(ComponentName.unflattenFromString("pkg/.cls2"), "b", ArrayList())
- ),
- )
- val structures = selectedItems.map { it.structure }
- sharedPreferences
- .edit()
- .putString("controls_component", selectedItems[0].componentName.flattenToString())
- .putString("controls_structure", selectedItems[0].name.toString())
- .commit()
-
- val differentSharedPreferences = FakeSharedPreferences()
- differentSharedPreferences
- .edit()
- .putString("controls_component", selectedItems[1].componentName.flattenToString())
- .putString("controls_structure", selectedItems[1].name.toString())
- .commit()
-
- val previousPreferredStructure = underTest.getPreferredSelectedItem(structures)
-
- `when`(
- userFileManager.getSharedPreferences(
- DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
- 0,
- 1
- )
- )
- .thenReturn(differentSharedPreferences)
- `when`(userTracker.userId).thenReturn(1)
-
- val currentPreferredStructure = underTest.getPreferredSelectedItem(structures)
-
- assertThat(previousPreferredStructure).isEqualTo(selectedItems[0])
- assertThat(currentPreferredStructure).isEqualTo(selectedItems[1])
- assertThat(currentPreferredStructure).isNotEqualTo(previousPreferredStructure)
- }
-
- @Test
fun testGetPreferredPanel() {
val panel = SelectedItem.PanelItem("App name", ComponentName("pkg", "cls"))
- sharedPreferences
- .edit()
- .putString("controls_component", panel.componentName.flattenToString())
- .putString("controls_structure", panel.appName.toString())
- .putBoolean("controls_is_panel", true)
- .commit()
+
+ preferredPanelRepository.setSelectedComponent(
+ SelectedComponentRepository.SelectedComponent(
+ name = panel.appName.toString(),
+ componentName = panel.componentName,
+ isPanel = true,
+ )
+ )
val selected = underTest.getPreferredSelectedItem(emptyList())
@@ -366,11 +299,9 @@ class ControlsUiControllerImplTest : SysuiTestCase() {
StructureInfo(ComponentName.unflattenFromString("pkg/.cls1"), "a", ArrayList())
),
)
- sharedPreferences
- .edit()
- .putString("controls_component", selectedItems[0].componentName.flattenToString())
- .putString("controls_structure", selectedItems[0].name.toString())
- .commit()
+ preferredPanelRepository.setSelectedComponent(
+ SelectedComponentRepository.SelectedComponent(selectedItems[0])
+ )
assertThat(underTest.resolveActivity())
.isEqualTo(ControlsProviderSelectorActivity::class.java)
@@ -410,14 +341,42 @@ class ControlsUiControllerImplTest : SysuiTestCase() {
verify(controlsListingController, never()).removeCallback(any())
}
+ @Test
+ fun testRemovingAppsRemovesFavorite() {
+ val componentName = ComponentName(context, "cls")
+ whenever(controlsController.removeFavorites(eq(componentName))).thenReturn(true)
+ val panel = SelectedItem.PanelItem("App name", componentName)
+ preferredPanelRepository.setSelectedComponent(
+ SelectedComponentRepository.SelectedComponent(panel)
+ )
+ underTest.show(parent, {}, context)
+ underTest.startRemovingApp(componentName, "Test App")
+
+ fakeDialogController.clickPositive()
+
+ verify(controlsController).removeFavorites(eq(componentName))
+ assertThat(underTest.getPreferredSelectedItem(emptyList()))
+ .isEqualTo(SelectedItem.EMPTY_SELECTION)
+ assertThat(preferredPanelRepository.shouldAddDefaultComponent()).isFalse()
+ assertThat(preferredPanelRepository.getSelectedComponent()).isNull()
+ }
+
+ @Test
+ fun testHideCancelsTheRemoveAppDialog() {
+ val componentName = ComponentName(context, "cls")
+ underTest.show(parent, {}, context)
+ underTest.startRemovingApp(componentName, "Test App")
+
+ underTest.hide(parent)
+
+ verify(fakeDialogController.dialog).cancel()
+ }
+
private fun setUpPanel(panel: SelectedItem.PanelItem): ControlsServiceInfo {
- val activity = ComponentName("pkg", "activity")
- sharedPreferences
- .edit()
- .putString("controls_component", panel.componentName.flattenToString())
- .putString("controls_structure", panel.appName.toString())
- .putBoolean("controls_is_panel", true)
- .commit()
+ val activity = ComponentName(context, "activity")
+ preferredPanelRepository.setSelectedComponent(
+ SelectedComponentRepository.SelectedComponent(panel)
+ )
return ControlsServiceInfo(panel.componentName, panel.appName, activity)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt
index dbaf94f1018c..483ab3bae6f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt
@@ -37,7 +37,9 @@ class OverflowMenuAdapterTest : SysuiTestCase() {
context,
layoutId = 0,
labels.zip(ids).map { OverflowMenuAdapter.MenuItem(it.first, it.second) }
- ) { true }
+ ) {
+ true
+ }
ids.forEachIndexed { index, id -> assertThat(adapter.getItemId(index)).isEqualTo(id) }
}
@@ -51,7 +53,9 @@ class OverflowMenuAdapterTest : SysuiTestCase() {
context,
layoutId = 0,
labels.zip(ids).map { OverflowMenuAdapter.MenuItem(it.first, it.second) }
- ) { position -> position == 0 }
+ ) { position ->
+ position == 0
+ }
assertThat(adapter.isEnabled(0)).isTrue()
assertThat(adapter.isEnabled(1)).isFalse()
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 6c23254941a8..0a9470617a5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
@@ -1,6 +1,8 @@
package com.android.systemui.dreams
+import android.animation.Animator
import android.animation.AnimatorSet
+import android.animation.ValueAnimator
import android.testing.AndroidTestingRunner
import android.view.View
import androidx.test.filters.SmallTest
@@ -10,13 +12,16 @@ import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransition
import com.android.systemui.statusbar.BlurUtils
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
+import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.anyLong
import org.mockito.Mockito.eq
@@ -71,6 +76,19 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() {
}
@Test
+ fun testExitAnimationUpdatesState() {
+ controller.startExitAnimations(animatorBuilder = { mockAnimator })
+
+ verify(stateController).setExitAnimationsRunning(true)
+
+ val captor = argumentCaptor<Animator.AnimatorListener>()
+ verify(mockAnimator).addListener(captor.capture())
+
+ captor.value.onAnimationEnd(mockAnimator)
+ verify(stateController).setExitAnimationsRunning(false)
+ }
+
+ @Test
fun testWakeUpCallsExecutor() {
val mockExecutor: DelayableExecutor = mock()
val mockCallback: Runnable = mock()
@@ -87,7 +105,7 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() {
fun testWakeUpAfterStartWillCancel() {
val mockStartAnimator: AnimatorSet = mock()
- controller.startEntryAnimations(animatorBuilder = { mockStartAnimator })
+ controller.startEntryAnimations(false, animatorBuilder = { mockStartAnimator })
verify(mockStartAnimator, never()).cancel()
@@ -100,4 +118,50 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() {
// animator.
verify(mockStartAnimator, times(1)).cancel()
}
+
+ @Test
+ fun testEntryAnimations_translatesUpwards() {
+ val mockStartAnimator: AnimatorSet = mock()
+
+ controller.startEntryAnimations(
+ /* downwards= */ false,
+ animatorBuilder = { mockStartAnimator }
+ )
+
+ val animatorCaptor = ArgumentCaptor.forClass(Animator::class.java)
+ verify(mockStartAnimator).playTogether(animatorCaptor.capture())
+
+ // Check if there's a ValueAnimator starting at the expected Y distance.
+ val animators: List<ValueAnimator> = animatorCaptor.allValues as List<ValueAnimator>
+ assertTrue(
+ animators.any {
+ // Call setCurrentFraction so the animated value jumps to the initial value.
+ it.setCurrentFraction(0f)
+ it.animatedValue == DREAM_IN_TRANSLATION_Y_DISTANCE.toFloat()
+ }
+ )
+ }
+
+ @Test
+ fun testEntryAnimations_translatesDownwards() {
+ val mockStartAnimator: AnimatorSet = mock()
+
+ controller.startEntryAnimations(
+ /* downwards= */ true,
+ animatorBuilder = { mockStartAnimator }
+ )
+
+ val animatorCaptor = ArgumentCaptor.forClass(Animator::class.java)
+ verify(mockStartAnimator).playTogether(animatorCaptor.capture())
+
+ // Check if there's a ValueAnimator starting at the expected Y distance.
+ val animators: List<ValueAnimator> = animatorCaptor.allValues as List<ValueAnimator>
+ assertTrue(
+ animators.any {
+ // Call setCurrentFraction so the animated value jumps to the initial value.
+ it.setCurrentFraction(0f)
+ it.animatedValue == -DREAM_IN_TRANSLATION_Y_DISTANCE.toFloat()
+ }
+ )
+ }
}
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 6b095ffd3977..2a72e7d85d3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -17,6 +17,7 @@
package com.android.systemui.dreams;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -33,6 +34,7 @@ import android.view.ViewTreeObserver;
import androidx.test.filters.SmallTest;
+import com.android.dream.lowlight.LowLightTransitionCoordinator;
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.complication.ComplicationHostViewController;
@@ -65,6 +67,9 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
DreamOverlayStatusBarViewController mDreamOverlayStatusBarViewController;
@Mock
+ LowLightTransitionCoordinator mLowLightTransitionCoordinator;
+
+ @Mock
DreamOverlayContainerView mDreamOverlayContainerView;
@Mock
@@ -109,6 +114,7 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
mComplicationHostViewController,
mDreamOverlayContentView,
mDreamOverlayStatusBarViewController,
+ mLowLightTransitionCoordinator,
mBlurUtils,
mHandler,
mResources,
@@ -200,7 +206,7 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
mController.onViewAttached();
- verify(mAnimationsController).startEntryAnimations();
+ verify(mAnimationsController).startEntryAnimations(false);
verify(mAnimationsController, never()).cancelAnimations();
}
@@ -210,11 +216,11 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
mController.onViewAttached();
- verify(mAnimationsController, never()).startEntryAnimations();
+ verify(mAnimationsController, never()).startEntryAnimations(anyBoolean());
}
@Test
- public void testSkipEntryAnimationsWhenExitingLowLight() {
+ public void testDownwardEntryAnimationsWhenExitingLowLight() {
ArgumentCaptor<DreamOverlayStateController.Callback> callbackCaptor =
ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
when(mStateController.isLowLightActive()).thenReturn(false);
@@ -230,8 +236,14 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
mController.onViewAttached();
// Entry animations should be started then immediately ended to skip to the end.
- verify(mAnimationsController).startEntryAnimations();
- verify(mAnimationsController).endAnimations();
+ verify(mAnimationsController).startEntryAnimations(true);
+ }
+
+ @Test
+ public void testStartsExitAnimationsBeforeEnteringLowLight() {
+ mController.onBeforeEnterLowLight();
+
+ verify(mAnimationsController).startExitAnimations();
}
@Test
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 1820f6444fbd..de7003366469 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -70,6 +70,7 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
private static final ComponentName LOW_LIGHT_COMPONENT = new ComponentName("package",
"lowlight");
private static final String DREAM_COMPONENT = "package/dream";
+ private static final String WINDOW_NAME = "test";
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private final FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
@@ -149,7 +150,8 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
mKeyguardUpdateMonitor,
mUiEventLogger,
LOW_LIGHT_COMPONENT,
- mDreamOverlayCallbackController);
+ mDreamOverlayCallbackController,
+ WINDOW_NAME);
}
public IDreamOverlayClient getClient() throws RemoteException {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java
index dcd8736711f6..068852de7a43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java
@@ -22,6 +22,8 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.view.View;
@@ -33,6 +35,8 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.settings.SecureSettings;
import org.junit.Before;
import org.junit.Test;
@@ -96,6 +100,10 @@ public class ComplicationHostViewControllerTest extends SysuiTestCase {
private ComplicationHostViewController mController;
+ private SecureSettings mSecureSettings;
+
+ private static final int CURRENT_USER_ID = UserHandle.USER_SYSTEM;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -108,12 +116,17 @@ public class ComplicationHostViewControllerTest extends SysuiTestCase {
when(mViewHolder.getLayoutParams()).thenReturn(mComplicationLayoutParams);
when(mComplicationView.getParent()).thenReturn(mComplicationHostView);
+ mSecureSettings = new FakeSettings();
+ mSecureSettings.putFloatForUser(
+ Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f, CURRENT_USER_ID);
+
mController = new ComplicationHostViewController(
mComplicationHostView,
mLayoutEngine,
mDreamOverlayStateController,
mLifecycleOwner,
- mViewModel);
+ mViewModel,
+ mSecureSettings);
mController.init();
}
@@ -188,6 +201,23 @@ public class ComplicationHostViewControllerTest extends SysuiTestCase {
verify(mComplicationView, never()).setVisibility(View.INVISIBLE);
}
+ @Test
+ public void testAnimationsDisabled_ComplicationsNeverSetToInvisible() {
+ //Disable animations
+ mController.mIsAnimationEnabled = false;
+
+ final Observer<Collection<ComplicationViewModel>> observer =
+ captureComplicationViewModelsObserver();
+
+ // Add a complication before entry animations are finished.
+ final HashSet<ComplicationViewModel> complications = new HashSet<>(
+ Collections.singletonList(mComplicationViewModel));
+ observer.onChanged(complications);
+
+ // The complication view should not be set to invisible.
+ verify(mComplicationView, never()).setVisibility(View.INVISIBLE);
+ }
+
private Observer<Collection<ComplicationViewModel>> captureComplicationViewModelsObserver() {
verify(mComplicationViewModelLiveData).observe(eq(mLifecycleOwner),
mObserverCaptor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java
index ef62abfe36de..175da0b7a5c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java
@@ -33,6 +33,8 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.condition.SelfExecutingMonitor;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.smartspace.DreamSmartspaceController;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
import com.android.systemui.shared.condition.Condition;
import com.android.systemui.shared.condition.Monitor;
@@ -65,6 +67,9 @@ public class SmartSpaceComplicationTest extends SysuiTestCase {
@Mock
private View mBcSmartspaceView;
+ @Mock
+ private FeatureFlags mFeatureFlags;
+
private Monitor mMonitor;
private final Set<Condition> mPreconditions = new HashSet<>();
@@ -73,6 +78,8 @@ public class SmartSpaceComplicationTest extends SysuiTestCase {
public void setup() {
MockitoAnnotations.initMocks(this);
mMonitor = SelfExecutingMonitor.createInstance();
+
+ when(mFeatureFlags.isEnabled(Flags.HIDE_SMARTSPACE_ON_DREAM_OVERLAY)).thenReturn(false);
}
/**
@@ -85,12 +92,22 @@ public class SmartSpaceComplicationTest extends SysuiTestCase {
verify(mDreamOverlayStateController, never()).addComplication(eq(mComplication));
}
- private SmartSpaceComplication.Registrant getRegistrant() {
- return new SmartSpaceComplication.Registrant(
- mDreamOverlayStateController,
- mComplication,
- mSmartspaceController,
- mMonitor);
+ @Test
+ public void testRegistrantStart_featureEnabled_addOverlayStateCallback() {
+ final SmartSpaceComplication.Registrant registrant = getRegistrant();
+ registrant.start();
+
+ verify(mDreamOverlayStateController).addCallback(any());
+ }
+
+ @Test
+ public void testRegistrantStart_featureDisabled_doesNotAddOverlayStateCallback() {
+ when(mFeatureFlags.isEnabled(Flags.HIDE_SMARTSPACE_ON_DREAM_OVERLAY)).thenReturn(true);
+
+ final SmartSpaceComplication.Registrant registrant = getRegistrant();
+ registrant.start();
+
+ verify(mDreamOverlayStateController, never()).addCallback(any());
}
@Test
@@ -188,4 +205,13 @@ public class SmartSpaceComplicationTest extends SysuiTestCase {
when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mBcSmartspaceView);
assertEquals(viewHolder.getView(), viewHolder.getView());
}
+
+ private SmartSpaceComplication.Registrant getRegistrant() {
+ return new SmartSpaceComplication.Registrant(
+ mDreamOverlayStateController,
+ mComplication,
+ mSmartspaceController,
+ mMonitor,
+ mFeatureFlags);
+ }
}
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 3a168d4e234b..d6dbd730368e 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
@@ -450,6 +450,15 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
swipeToPosition(0f, Direction.DOWN, 0);
}
+ @Test
+ public void testTouchSessionOnRemovedCalledTwice() {
+ mTouchHandler.onSessionStart(mTouchSession);
+ ArgumentCaptor<DreamTouchHandler.TouchSession.Callback> onRemovedCallbackCaptor =
+ ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.Callback.class);
+ verify(mTouchSession).registerCallback(onRemovedCallbackCaptor.capture());
+ onRemovedCallbackCaptor.getValue().onRemoved();
+ onRemovedCallbackCaptor.getValue().onRemoved();
+ }
private void swipeToPosition(float percent, Direction direction, float velocityY) {
Mockito.clearInvocations(mTouchSession);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt
new file mode 100644
index 000000000000..ec94cdec78f0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.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.keyboard.backlight.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.first
+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)
+class KeyboardBacklightInteractorTest : SysuiTestCase() {
+
+ private val keyboardRepository = FakeKeyboardRepository()
+ private lateinit var underTest: KeyboardBacklightInteractor
+
+ @Before
+ fun setUp() {
+ underTest = KeyboardBacklightInteractor(keyboardRepository)
+ }
+
+ @Test
+ fun emitsNull_whenKeyboardJustConnected() = runTest {
+ val latest by collectLastValue(underTest.backlight)
+ keyboardRepository.setKeyboardConnected(true)
+
+ assertThat(latest).isNull()
+ }
+
+ @Test
+ fun emitsBacklight_whenKeyboardConnectedAndBacklightChanged() = runTest {
+ keyboardRepository.setKeyboardConnected(true)
+ keyboardRepository.setBacklight(BacklightModel(1, 5))
+
+ assertThat(underTest.backlight.first()).isEqualTo(BacklightModel(1, 5))
+ }
+
+ @Test
+ fun emitsNull_afterKeyboardDisconnecting() = runTest {
+ val latest by collectLastValue(underTest.backlight)
+ keyboardRepository.setKeyboardConnected(true)
+ keyboardRepository.setBacklight(BacklightModel(1, 5))
+
+ keyboardRepository.setKeyboardConnected(false)
+
+ assertThat(latest).isNull()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt
new file mode 100644
index 000000000000..ec05d10b793c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.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.
+ *
+ */
+
+package com.android.systemui.keyboard.backlight.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyboard.backlight.domain.interactor.KeyboardBacklightInteractor
+import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
+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 kotlinx.coroutines.flow.first
+import kotlinx.coroutines.test.advanceTimeBy
+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
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class BacklightDialogViewModelTest : SysuiTestCase() {
+
+ private val keyboardRepository = FakeKeyboardRepository()
+ private lateinit var underTest: BacklightDialogViewModel
+ @Mock private lateinit var accessibilityManagerWrapper: AccessibilityManagerWrapper
+ private val timeoutMillis = 3000L
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(accessibilityManagerWrapper.getRecommendedTimeoutMillis(any(), any()))
+ .thenReturn(timeoutMillis.toInt())
+ underTest =
+ BacklightDialogViewModel(
+ KeyboardBacklightInteractor(keyboardRepository),
+ accessibilityManagerWrapper
+ )
+ keyboardRepository.setKeyboardConnected(true)
+ }
+
+ @Test
+ fun emitsViewModel_whenBacklightChanged() = runTest {
+ keyboardRepository.setBacklight(BacklightModel(1, 5))
+
+ assertThat(underTest.dialogContent.first()).isEqualTo(BacklightDialogContentViewModel(1, 5))
+ }
+
+ @Test
+ fun emitsNull_afterTimeout() = runTest {
+ val latest by collectLastValue(underTest.dialogContent)
+ keyboardRepository.setBacklight(BacklightModel(1, 5))
+
+ assertThat(latest).isEqualTo(BacklightDialogContentViewModel(1, 5))
+ advanceTimeBy(timeoutMillis + 1)
+ assertThat(latest).isNull()
+ }
+
+ @Test
+ fun emitsNull_after5secDelay_fromLastBacklightChange() = runTest {
+ val latest by collectLastValue(underTest.dialogContent)
+ keyboardRepository.setKeyboardConnected(true)
+
+ keyboardRepository.setBacklight(BacklightModel(1, 5))
+ assertThat(latest).isEqualTo(BacklightDialogContentViewModel(1, 5))
+
+ advanceTimeBy(timeoutMillis * 2 / 3)
+ // timeout yet to pass, no new emission
+ keyboardRepository.setBacklight(BacklightModel(2, 5))
+ assertThat(latest).isEqualTo(BacklightDialogContentViewModel(2, 5))
+
+ advanceTimeBy(timeoutMillis * 2 / 3)
+ // timeout refreshed because of last `setBacklight`, still content present
+ assertThat(latest).isEqualTo(BacklightDialogContentViewModel(2, 5))
+
+ advanceTimeBy(timeoutMillis * 2 / 3)
+ // finally timeout reached and null emitted
+ assertThat(latest).isNull()
+ }
+}
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 f55b86686152..c93e677071cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -29,7 +29,6 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -67,7 +66,6 @@ import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.NotificationShadeWindowControllerImpl;
@@ -137,7 +135,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private @Mock AuthController mAuthController;
private @Mock ShadeExpansionStateManager mShadeExpansionStateManager;
private @Mock ShadeWindowLogger mShadeWindowLogger;
- private @Mock FeatureFlags mFeatureFlags;
private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -545,7 +542,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
mScreenOnCoordinator,
mInteractionJankMonitor,
mDreamOverlayStateController,
- mFeatureFlags,
() -> mShadeController,
() -> mNotificationShadeWindowController,
() -> mActivityLaunchAnimator,
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 21ad5e2cd311..5dc04f7efa63 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
@@ -30,6 +30,7 @@ import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
import com.android.systemui.coroutines.collectLastValue
@@ -38,11 +39,14 @@ import com.android.systemui.keyguard.data.repository.BiometricType.FACE
import com.android.systemui.keyguard.data.repository.BiometricType.REAR_FINGERPRINT
import com.android.systemui.keyguard.data.repository.BiometricType.SIDE_FINGERPRINT
import com.android.systemui.keyguard.data.repository.BiometricType.UNDER_DISPLAY_FINGERPRINT
+import com.android.systemui.keyguard.shared.model.DevicePosture
+import com.android.systemui.statusbar.policy.DevicePostureController
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.TestScope
@@ -62,6 +66,7 @@ import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner::class)
@@ -78,6 +83,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
private lateinit var biometricManagerCallback:
ArgumentCaptor<IBiometricEnabledOnKeyguardCallback.Stub>
private lateinit var userRepository: FakeUserRepository
+ private lateinit var devicePostureRepository: FakeDevicePostureRepository
private lateinit var testDispatcher: TestDispatcher
private lateinit var testScope: TestScope
@@ -90,6 +96,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
testDispatcher = StandardTestDispatcher()
testScope = TestScope(testDispatcher)
userRepository = FakeUserRepository()
+ devicePostureRepository = FakeDevicePostureRepository()
}
private suspend fun createBiometricSettingsRepository() {
@@ -108,6 +115,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
looper = testableLooper!!.looper,
dumpManager = dumpManager,
biometricManager = biometricManager,
+ devicePostureRepository = devicePostureRepository,
)
testScope.runCurrent()
}
@@ -299,6 +307,50 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() {
verify(biometricManager, times(1)).registerEnabledOnKeyguardCallback(any())
}
+ @Test
+ fun faceAuthIsAlwaysSupportedIfSpecificPostureIsNotConfigured() =
+ testScope.runTest {
+ overrideResource(
+ R.integer.config_face_auth_supported_posture,
+ DevicePostureController.DEVICE_POSTURE_UNKNOWN
+ )
+
+ createBiometricSettingsRepository()
+
+ assertThat(collectLastValue(underTest.isFaceAuthSupportedInCurrentPosture)()).isTrue()
+ }
+
+ @Test
+ fun faceAuthIsSupportedOnlyWhenDevicePostureMatchesConfigValue() =
+ testScope.runTest {
+ overrideResource(
+ R.integer.config_face_auth_supported_posture,
+ DevicePostureController.DEVICE_POSTURE_FLIPPED
+ )
+
+ createBiometricSettingsRepository()
+
+ val isFaceAuthSupported =
+ collectLastValue(underTest.isFaceAuthSupportedInCurrentPosture)
+
+ assertThat(isFaceAuthSupported()).isFalse()
+
+ devicePostureRepository.setCurrentPosture(DevicePosture.CLOSED)
+ assertThat(isFaceAuthSupported()).isFalse()
+
+ devicePostureRepository.setCurrentPosture(DevicePosture.HALF_OPENED)
+ assertThat(isFaceAuthSupported()).isFalse()
+
+ devicePostureRepository.setCurrentPosture(DevicePosture.OPENED)
+ assertThat(isFaceAuthSupported()).isFalse()
+
+ devicePostureRepository.setCurrentPosture(DevicePosture.UNKNOWN)
+ assertThat(isFaceAuthSupported()).isFalse()
+
+ devicePostureRepository.setCurrentPosture(DevicePosture.FLIPPED)
+ assertThat(isFaceAuthSupported()).isTrue()
+ }
+
private fun enrollmentChange(biometricType: BiometricType, userId: Int, enabled: Boolean) {
authControllerCallback.value.onEnrollmentsChanged(biometricType, userId, enabled)
}
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
new file mode 100644
index 000000000000..bd6b7a853dfc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DevicePostureRepositoryTest.kt
@@ -0,0 +1,80 @@
+/*
+ * 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.data.repository
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.shared.model.DevicePosture
+import com.android.systemui.statusbar.policy.DevicePostureController
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+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.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class DevicePostureRepositoryTest : SysuiTestCase() {
+ private lateinit var underTest: DevicePostureRepository
+ private lateinit var testScope: TestScope
+ @Mock private lateinit var devicePostureController: DevicePostureController
+ @Captor private lateinit var callback: ArgumentCaptor<DevicePostureController.Callback>
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ testScope = TestScope()
+ underTest = DevicePostureRepositoryImpl(postureController = devicePostureController)
+ }
+
+ @Test
+ fun postureChangesArePropagated() =
+ testScope.runTest {
+ whenever(devicePostureController.devicePosture)
+ .thenReturn(DevicePostureController.DEVICE_POSTURE_FLIPPED)
+ val currentPosture = collectLastValue(underTest.currentDevicePosture)
+ assertThat(currentPosture()).isEqualTo(DevicePosture.FLIPPED)
+
+ verify(devicePostureController).addCallback(callback.capture())
+
+ callback.value.onPostureChanged(DevicePostureController.DEVICE_POSTURE_UNKNOWN)
+ assertThat(currentPosture()).isEqualTo(DevicePosture.UNKNOWN)
+
+ callback.value.onPostureChanged(DevicePostureController.DEVICE_POSTURE_CLOSED)
+ assertThat(currentPosture()).isEqualTo(DevicePosture.CLOSED)
+
+ callback.value.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED)
+ assertThat(currentPosture()).isEqualTo(DevicePosture.HALF_OPENED)
+
+ callback.value.onPostureChanged(DevicePostureController.DEVICE_POSTURE_OPENED)
+ assertThat(currentPosture()).isEqualTo(DevicePosture.OPENED)
+
+ callback.value.onPostureChanged(DevicePostureController.DEVICE_POSTURE_FLIPPED)
+ assertThat(currentPosture()).isEqualTo(DevicePosture.FLIPPED)
+ }
+}
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 0469e77ca991..0e6f8d4e0720 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
@@ -219,6 +219,29 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
}
@Test
+ fun isKeyguardUnlocked() =
+ runTest(UnconfinedTestDispatcher()) {
+ whenever(keyguardStateController.isUnlocked).thenReturn(false)
+ var latest: Boolean? = null
+ val job = underTest.isKeyguardUnlocked.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isFalse()
+
+ val captor = argumentCaptor<KeyguardStateController.Callback>()
+ verify(keyguardStateController).addCallback(captor.capture())
+
+ whenever(keyguardStateController.isUnlocked).thenReturn(true)
+ captor.value.onUnlockedChanged()
+ assertThat(latest).isTrue()
+
+ whenever(keyguardStateController.isUnlocked).thenReturn(false)
+ captor.value.onUnlockedChanged()
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
fun isDozing() =
runTest(UnconfinedTestDispatcher()) {
var latest: Boolean? = null
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 d2db910ad443..f9493d10ff61 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
@@ -62,7 +62,9 @@ class LightRevealScrimRepositoryTest : SysuiTestCase() {
fakeKeyguardRepository.setBiometricUnlockState(BiometricUnlockModel.WAKE_AND_UNLOCK)
runCurrent()
- values.assertEffectsMatchPredicates({ it == DEFAULT_REVEAL_EFFECT },)
+ values.assertEffectsMatchPredicates(
+ { it == DEFAULT_REVEAL_EFFECT },
+ )
// We got a source but still have no sensor locations, so should be sticking with
// the default effect.
@@ -71,14 +73,18 @@ class LightRevealScrimRepositoryTest : SysuiTestCase() {
)
runCurrent()
- values.assertEffectsMatchPredicates({ it == DEFAULT_REVEAL_EFFECT },)
+ values.assertEffectsMatchPredicates(
+ { it == DEFAULT_REVEAL_EFFECT },
+ )
// We got a location for the face sensor, but we unlocked with fingerprint.
val faceLocation = Point(250, 0)
fakeKeyguardRepository.setFaceSensorLocation(faceLocation)
runCurrent()
- values.assertEffectsMatchPredicates({ it == DEFAULT_REVEAL_EFFECT },)
+ values.assertEffectsMatchPredicates(
+ { it == DEFAULT_REVEAL_EFFECT },
+ )
// Now we have fingerprint sensor locations, and wake and unlock via fingerprint.
val fingerprintLocation = Point(500, 500)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
index 18e80ea40c5c..1365132d6dac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
@@ -28,6 +28,8 @@ import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintA
import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepositoryImpl
import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.android.systemui.util.time.SystemClock
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -50,6 +52,7 @@ class AlternateBouncerInteractorTest : SysuiTestCase() {
private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
private lateinit var deviceEntryFingerprintAuthRepository:
FakeDeviceEntryFingerprintAuthRepository
+ @Mock private lateinit var keyguardStateController: KeyguardStateController
@Mock private lateinit var systemClock: SystemClock
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var bouncerLogger: TableLogBuffer
@@ -70,6 +73,7 @@ class AlternateBouncerInteractorTest : SysuiTestCase() {
featureFlags = FakeFeatureFlags().apply { this.set(Flags.MODERN_ALTERNATE_BOUNCER, true) }
underTest =
AlternateBouncerInteractor(
+ keyguardStateController,
bouncerRepository,
biometricSettingsRepository,
deviceEntryFingerprintAuthRepository,
@@ -134,6 +138,14 @@ class AlternateBouncerInteractorTest : SysuiTestCase() {
}
@Test
+ fun canShowAlternateBouncerForFingerprint_butCanDismissLockScreen() {
+ givenCanShowAlternateBouncer()
+ whenever(keyguardStateController.isUnlocked).thenReturn(true)
+
+ assertFalse(underTest.canShowAlternateBouncerForFingerprint())
+ }
+
+ @Test
fun show_whenCannotShow() {
givenCannotShowAlternateBouncer()
@@ -163,6 +175,7 @@ class AlternateBouncerInteractorTest : SysuiTestCase() {
biometricSettingsRepository.setStrongBiometricAllowed(true)
biometricSettingsRepository.setFingerprintEnabledByDevicePolicy(true)
deviceEntryFingerprintAuthRepository.setLockedOut(false)
+ whenever(keyguardStateController.isUnlocked).thenReturn(false)
}
private fun givenCannotShowAlternateBouncer() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index ae7a928cdb2c..fe9098fa5c25 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -19,6 +19,8 @@ package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.Interpolators
import com.android.systemui.flags.FakeFeatureFlags
@@ -40,6 +42,7 @@ import com.android.systemui.keyguard.util.KeyguardTransitionRunner
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.cancelChildren
@@ -51,6 +54,8 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
@@ -77,6 +82,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
// Used to verify transition requests for test output
@Mock private lateinit var mockTransitionRepository: KeyguardTransitionRepository
@Mock private lateinit var commandQueue: CommandQueue
+ @Mock private lateinit var keyguardSecurityModel: KeyguardSecurityModel
private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor
private lateinit var fromDreamingTransitionInteractor: FromDreamingTransitionInteractor
@@ -102,6 +108,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
transitionRepository = KeyguardTransitionRepositoryImpl()
runner = KeyguardTransitionRunner(transitionRepository)
+ whenever(keyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(PIN)
+
val featureFlags = FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, true) }
fromLockscreenTransitionInteractor =
FromLockscreenTransitionInteractor(
@@ -173,16 +181,17 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardSecurityModel = keyguardSecurityModel,
)
fromPrimaryBouncerTransitionInteractor.start()
}
@Test
- fun `DREAMING to LOCKSCREEN - dreaming state changes first`() =
+ fun `DREAMING to LOCKSCREEN`() =
testScope.runTest {
- // GIVEN a device is dreaming and occluded
+ // GIVEN a device is dreaming
keyguardRepository.setDreamingWithOverlay(true)
- keyguardRepository.setKeyguardOccluded(true)
+ keyguardRepository.setWakefulnessModel(startingToWake())
runCurrent()
// GIVEN a prior transition has run to DREAMING
@@ -215,56 +224,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
- }
- // THEN a transition to BOUNCER should occur
- assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.DREAMING)
- assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.animator).isNotNull()
-
- coroutineContext.cancelChildren()
- }
-
- @Test
- fun `DREAMING to LOCKSCREEN - occluded state changes first`() =
- testScope.runTest {
- // GIVEN a device is dreaming and occluded
- keyguardRepository.setDreamingWithOverlay(true)
- keyguardRepository.setKeyguardOccluded(true)
- runCurrent()
-
- // GIVEN a prior transition has run to DREAMING
- runner.startTransition(
- testScope,
- TransitionInfo(
- ownerName = "",
- from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.DREAMING,
- animator =
- ValueAnimator().apply {
- duration = 10
- interpolator = Interpolators.LINEAR
- },
- )
- )
- runCurrent()
- reset(mockTransitionRepository)
-
- // WHEN doze is complete
- keyguardRepository.setDozeTransitionModel(
- DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
- )
- // AND occluded has stopped
- keyguardRepository.setKeyguardOccluded(false)
- advanceUntilIdle()
- // AND then dreaming has stopped
- keyguardRepository.setDreamingWithOverlay(false)
- advanceUntilIdle()
-
- val info =
- withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to BOUNCER should occur
assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor")
@@ -304,7 +264,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to PRIMARY_BOUNCER should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -345,7 +305,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -386,7 +346,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -427,7 +387,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -468,7 +428,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -505,7 +465,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
@@ -542,7 +502,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
@@ -583,7 +543,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -624,7 +584,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -661,7 +621,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -677,6 +637,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
testScope.runTest {
// GIVEN a device that is not dreaming or dozing
keyguardRepository.setDreamingWithOverlay(false)
+ keyguardRepository.setWakefulnessModel(startingToWake())
keyguardRepository.setDozeTransitionModel(
DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
)
@@ -704,7 +665,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DREAMING should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -741,7 +702,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to PRIMARY_BOUNCER should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -784,7 +745,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -828,7 +789,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -870,7 +831,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to LOCKSCREEN should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -912,7 +873,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
@@ -954,7 +915,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
@@ -995,7 +956,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to LOCKSCREEN should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 8bd8be565eee..c727b3a6cd10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -308,7 +308,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
TestConfig(
isVisible = true,
isClickable = false,
- isActivated = true,
+ isActivated = false,
icon = icon,
canShowWhileLocked = false,
intent = Intent("action"),
@@ -363,7 +363,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
TestConfig(
isVisible = true,
isClickable = false,
- isActivated = true,
+ isActivated = false,
icon = icon,
canShowWhileLocked = false,
intent = Intent("action"),
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
new file mode 100644
index 000000000000..2a91799741b7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -0,0 +1,109 @@
+/*
+ * 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.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.util.mockito.whenever
+import com.google.common.collect.Range
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+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.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() {
+ private lateinit var underTest: PrimaryBouncerToGoneTransitionViewModel
+ private lateinit var repository: FakeKeyguardTransitionRepository
+ @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ repository = FakeKeyguardTransitionRepository()
+ val interactor = KeyguardTransitionInteractor(repository)
+ underTest = PrimaryBouncerToGoneTransitionViewModel(interactor, statusBarStateController)
+ }
+
+ @Test
+ fun scrimBehindAlpha_leaveShadeOpen() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+
+ val job = underTest.scrimBehindAlpha.onEach { values.add(it) }.launchIn(this)
+
+ whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(true)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.6f))
+ repository.sendTransitionStep(step(1f))
+
+ assertThat(values.size).isEqualTo(4)
+ values.forEach { assertThat(it).isEqualTo(1f) }
+
+ job.cancel()
+ }
+
+ @Test
+ fun scrimBehindAlpha_doNotLeaveShadeOpen() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+
+ val job = underTest.scrimBehindAlpha.onEach { values.add(it) }.launchIn(this)
+
+ whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.6f))
+ repository.sendTransitionStep(step(1f))
+
+ assertThat(values.size).isEqualTo(4)
+ values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
+ assertThat(values[3]).isEqualTo(0f)
+
+ job.cancel()
+ }
+
+ private fun step(
+ value: Float,
+ state: TransitionState = TransitionState.RUNNING
+ ): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.GONE,
+ value = value,
+ transitionState = state,
+ ownerName = "PrimaryBouncerToGoneTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
index 8c54da1c3153..ab0669a28f04 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
@@ -139,6 +139,7 @@ class MediaDataManagerTest : SysuiTestCase() {
@Mock private lateinit var logger: MediaUiEventLogger
lateinit var mediaDataManager: MediaDataManager
lateinit var mediaNotification: StatusBarNotification
+ lateinit var remoteCastNotification: StatusBarNotification
@Captor lateinit var mediaDataCaptor: ArgumentCaptor<MediaData>
private val clock = FakeSystemClock()
@Mock private lateinit var tunerService: TunerService
@@ -207,6 +208,20 @@ class MediaDataManagerTest : SysuiTestCase() {
}
build()
}
+ remoteCastNotification =
+ SbnBuilder().run {
+ setPkg(SYSTEM_PACKAGE_NAME)
+ modifyNotification(context).also {
+ it.setSmallIcon(android.R.drawable.ic_media_pause)
+ it.setStyle(
+ MediaStyle().apply {
+ setMediaSession(session.sessionToken)
+ setRemotePlaybackInfo("Remote device", 0, null)
+ }
+ )
+ }
+ build()
+ }
metadataBuilder =
MediaMetadata.Builder().apply {
putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
@@ -247,6 +262,7 @@ class MediaDataManagerTest : SysuiTestCase() {
whenever(mediaFlags.isExplicitIndicatorEnabled()).thenReturn(true)
whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(false)
whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false)
+ whenever(mediaFlags.isRemoteResumeAllowed()).thenReturn(false)
whenever(logger.getNewInstanceId()).thenReturn(instanceIdSequence.newInstanceId())
whenever(keyguardUpdateMonitor.isUserInLockdown(any())).thenReturn(false)
}
@@ -400,33 +416,8 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testOnNotificationAdded_isRcn_markedRemote() {
- val rcn =
- SbnBuilder().run {
- setPkg(SYSTEM_PACKAGE_NAME)
- modifyNotification(context).also {
- it.setSmallIcon(android.R.drawable.ic_media_pause)
- it.setStyle(
- MediaStyle().apply {
- setMediaSession(session.sessionToken)
- setRemotePlaybackInfo("Remote device", 0, null)
- }
- )
- }
- build()
- }
+ addNotificationAndLoad(remoteCastNotification)
- mediaDataManager.onNotificationAdded(KEY, rcn)
- assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
- assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(listener)
- .onMediaDataLoaded(
- eq(KEY),
- eq(null),
- capture(mediaDataCaptor),
- eq(true),
- eq(0),
- eq(false)
- )
assertThat(mediaDataCaptor.value!!.playbackLocation)
.isEqualTo(MediaData.PLAYBACK_CAST_REMOTE)
verify(logger)
@@ -710,6 +701,56 @@ class MediaDataManagerTest : SysuiTestCase() {
}
@Test
+ fun testOnNotificationRemoved_withResumption_isRemoteAndRemoteAllowed() {
+ // With the flag enabled to allow remote media to resume
+ whenever(mediaFlags.isRemoteResumeAllowed()).thenReturn(true)
+
+ // GIVEN that the manager has a notification with a resume action, but is not local
+ whenever(controller.metadata).thenReturn(metadataBuilder.build())
+ whenever(playbackInfo.playbackType)
+ .thenReturn(MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE)
+ addNotificationAndLoad()
+ val data = mediaDataCaptor.value
+ val dataRemoteWithResume =
+ data.copy(resumeAction = Runnable {}, playbackLocation = MediaData.PLAYBACK_CAST_LOCAL)
+ mediaDataManager.onMediaDataLoaded(KEY, null, dataRemoteWithResume)
+
+ // WHEN the notification is removed
+ mediaDataManager.onNotificationRemoved(KEY)
+
+ // THEN the media data is converted to a resume state
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(PACKAGE_NAME),
+ eq(KEY),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ assertThat(mediaDataCaptor.value.resumption).isTrue()
+ }
+
+ @Test
+ fun testOnNotificationRemoved_withResumption_isRcnAndRemoteAllowed() {
+ // With the flag enabled to allow remote media to resume
+ whenever(mediaFlags.isRemoteResumeAllowed()).thenReturn(true)
+
+ // GIVEN that the manager has a remote cast notification
+ addNotificationAndLoad(remoteCastNotification)
+ val data = mediaDataCaptor.value
+ assertThat(data.playbackLocation).isEqualTo(MediaData.PLAYBACK_CAST_REMOTE)
+ val dataRemoteWithResume = data.copy(resumeAction = Runnable {})
+ mediaDataManager.onMediaDataLoaded(KEY, null, dataRemoteWithResume)
+
+ // WHEN the RCN is removed
+ mediaDataManager.onNotificationRemoved(KEY)
+
+ // THEN the media data is removed
+ verify(listener).onMediaDataRemoved(eq(KEY))
+ }
+
+ @Test
fun testOnNotificationRemoved_withResumption_tooManyPlayers() {
// Given the maximum number of resume controls already
val desc =
@@ -1654,22 +1695,7 @@ class MediaDataManagerTest : SysuiTestCase() {
)
// update to remote cast
- val rcn =
- SbnBuilder().run {
- setPkg(SYSTEM_PACKAGE_NAME) // System package
- modifyNotification(context).also {
- it.setSmallIcon(android.R.drawable.ic_media_pause)
- it.setStyle(
- MediaStyle().apply {
- setMediaSession(session.sessionToken)
- setRemotePlaybackInfo("Remote device", 0, null)
- }
- )
- }
- build()
- }
-
- mediaDataManager.onNotificationAdded(KEY, rcn)
+ mediaDataManager.onNotificationAdded(KEY, remoteCastNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(logger)
@@ -2038,9 +2064,14 @@ class MediaDataManagerTest : SysuiTestCase() {
verify(listener).onMediaDataRemoved(eq(KEY))
}
- /** Helper function to add a media notification and capture the resulting MediaData */
+ /** Helper function to add a basic media notification and capture the resulting MediaData */
private fun addNotificationAndLoad() {
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ addNotificationAndLoad(mediaNotification)
+ }
+
+ /** Helper function to add the given notification and capture the resulting MediaData */
+ private fun addNotificationAndLoad(sbn: StatusBarNotification) {
+ mediaDataManager.onNotificationAdded(KEY, sbn)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt
index 136ace173795..9ab728949e40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt
@@ -38,6 +38,7 @@ import com.android.systemui.media.controls.models.player.MediaData
import com.android.systemui.media.controls.models.player.MediaDeviceData
import com.android.systemui.media.controls.pipeline.MediaDataManager
import com.android.systemui.media.controls.pipeline.RESUME_MEDIA_TIMEOUT
+import com.android.systemui.media.controls.util.MediaFlags
import com.android.systemui.settings.UserTracker
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.concurrency.FakeExecutor
@@ -92,6 +93,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
@Mock private lateinit var mockContext: Context
@Mock private lateinit var pendingIntent: PendingIntent
@Mock private lateinit var dumpManager: DumpManager
+ @Mock private lateinit var mediaFlags: MediaFlags
@Captor lateinit var callbackCaptor: ArgumentCaptor<ResumeMediaBrowser.Callback>
@Captor lateinit var actionCaptor: ArgumentCaptor<Runnable>
@@ -134,6 +136,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
whenever(mockContext.packageManager).thenReturn(context.packageManager)
whenever(mockContext.contentResolver).thenReturn(context.contentResolver)
whenever(mockContext.userId).thenReturn(context.userId)
+ whenever(mediaFlags.isRemoteResumeAllowed()).thenReturn(false)
executor = FakeExecutor(clock)
resumeListener =
@@ -146,7 +149,8 @@ class MediaResumeListenerTest : SysuiTestCase() {
tunerService,
resumeBrowserFactory,
dumpManager,
- clock
+ clock,
+ mediaFlags,
)
resumeListener.setManager(mediaDataManager)
mediaDataManager.addListener(resumeListener)
@@ -188,7 +192,8 @@ class MediaResumeListenerTest : SysuiTestCase() {
tunerService,
resumeBrowserFactory,
dumpManager,
- clock
+ clock,
+ mediaFlags,
)
listener.setManager(mediaDataManager)
verify(broadcastDispatcher, never())
@@ -244,6 +249,32 @@ class MediaResumeListenerTest : SysuiTestCase() {
}
@Test
+ fun testOnLoad_localCast_remoteResumeAllowed_doesCheck() {
+ // If local cast media is allowed to resume
+ whenever(mediaFlags.isRemoteResumeAllowed()).thenReturn(true)
+
+ // When media data is loaded that has not been checked yet, and is a local cast
+ val dataCast = data.copy(playbackLocation = MediaData.PLAYBACK_CAST_LOCAL)
+ resumeListener.onMediaDataLoaded(KEY, null, dataCast)
+
+ // Then we report back to the manager
+ verify(mediaDataManager).setResumeAction(KEY, null)
+ }
+
+ @Test
+ fun testOnLoad_remoteCast_remoteResumeAllowed_doesCheck() {
+ // If local cast media is allowed to resume
+ whenever(mediaFlags.isRemoteResumeAllowed()).thenReturn(true)
+
+ // When media data is loaded that has not been checked yet, and is a remote cast
+ val dataRcn = data.copy(playbackLocation = MediaData.PLAYBACK_CAST_REMOTE)
+ resumeListener.onMediaDataLoaded(KEY, null, dataRcn)
+
+ // Then we do not take action
+ verify(mediaDataManager, never()).setResumeAction(any(), any())
+ }
+
+ @Test
fun testOnLoad_checksForResume_hasService() {
setUpMbsWithValidResolveInfo()
@@ -282,6 +313,25 @@ class MediaResumeListenerTest : SysuiTestCase() {
}
@Test
+ fun testOnLoadTwice_onlyChecksOnce() {
+ // When data is first loaded,
+ setUpMbsWithValidResolveInfo()
+ resumeListener.onMediaDataLoaded(KEY, null, data)
+
+ // We notify the manager to set a null action
+ verify(mediaDataManager).setResumeAction(KEY, null)
+
+ // If we then get another update from the app before the first check completes
+ assertThat(executor.numPending()).isEqualTo(1)
+ var dataWithCheck = data.copy(hasCheckedForResume = true)
+ resumeListener.onMediaDataLoaded(KEY, null, dataWithCheck)
+
+ // We do not try to start another check
+ assertThat(executor.numPending()).isEqualTo(1)
+ verify(mediaDataManager).setResumeAction(KEY, null)
+ }
+
+ @Test
fun testOnUserUnlock_loadsTracks() {
// Set up mock service to successfully find valid media
val description = MediaDescription.Builder().setTitle(TITLE).build()
@@ -361,7 +411,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
assertThat(result.size).isEqualTo(3)
assertThat(result[2].toLong()).isEqualTo(currentTime)
}
- verify(sharedPrefsEditor, times(1)).apply()
+ verify(sharedPrefsEditor).apply()
}
@Test
@@ -389,7 +439,8 @@ class MediaResumeListenerTest : SysuiTestCase() {
tunerService,
resumeBrowserFactory,
dumpManager,
- clock
+ clock,
+ mediaFlags,
)
resumeListener.setManager(mediaDataManager)
mediaDataManager.addListener(resumeListener)
@@ -400,8 +451,8 @@ class MediaResumeListenerTest : SysuiTestCase() {
resumeListener.userUnlockReceiver.onReceive(mockContext, intent)
// We add its resume controls
- verify(resumeBrowser, times(1)).findRecentMedia()
- verify(mediaDataManager, times(1))
+ verify(resumeBrowser).findRecentMedia()
+ verify(mediaDataManager)
.addResumptionControls(anyInt(), any(), any(), any(), any(), any(), eq(PACKAGE_NAME))
}
@@ -421,7 +472,8 @@ class MediaResumeListenerTest : SysuiTestCase() {
tunerService,
resumeBrowserFactory,
dumpManager,
- clock
+ clock,
+ mediaFlags,
)
resumeListener.setManager(mediaDataManager)
mediaDataManager.addListener(resumeListener)
@@ -463,7 +515,8 @@ class MediaResumeListenerTest : SysuiTestCase() {
tunerService,
resumeBrowserFactory,
dumpManager,
- clock
+ clock,
+ mediaFlags,
)
resumeListener.setManager(mediaDataManager)
mediaDataManager.addListener(resumeListener)
@@ -482,7 +535,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
assertThat(result.size).isEqualTo(3)
assertThat(result[2].toLong()).isEqualTo(currentTime)
}
- verify(sharedPrefsEditor, times(1)).apply()
+ verify(sharedPrefsEditor).apply()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
index 7f5707722b9c..e0ca90ec2c58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.media.controls.ui
import android.app.PendingIntent
import android.content.res.ColorStateList
-import android.content.res.Configuration
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.util.MathUtils.abs
@@ -685,46 +684,6 @@ class MediaCarouselControllerTest : SysuiTestCase() {
}
@Test
- fun testOnConfigChanged_playersAreAddedBack() {
- mediaCarouselController.pageIndicator = pageIndicator
-
- listener.value.onMediaDataLoaded(
- "playing local",
- null,
- DATA.copy(
- active = true,
- isPlaying = true,
- playbackLocation = MediaData.PLAYBACK_LOCAL,
- resumption = false
- )
- )
- listener.value.onMediaDataLoaded(
- "paused local",
- null,
- DATA.copy(
- active = true,
- isPlaying = false,
- playbackLocation = MediaData.PLAYBACK_LOCAL,
- resumption = false
- )
- )
- runAllReady()
-
- val playersSize = MediaPlayerData.players().size
-
- configListener.value.onConfigChanged(Configuration())
- runAllReady()
-
- verify(pageIndicator).tintList =
- ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator))
- assertEquals(playersSize, MediaPlayerData.players().size)
- assertEquals(
- MediaPlayerData.getMediaPlayerIndex("playing local"),
- mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
- )
- }
-
- @Test
fun testOnUiModeChanged_playersAreAddedBack() {
mediaCarouselController.pageIndicator = pageIndicator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
index 55a33b6636e0..fd353afff7c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
@@ -27,6 +27,7 @@ import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
+import android.graphics.Matrix
import android.graphics.drawable.Animatable2
import android.graphics.drawable.AnimatedVectorDrawable
import android.graphics.drawable.Drawable
@@ -78,6 +79,8 @@ import com.android.systemui.media.controls.pipeline.EMPTY_SMARTSPACE_MEDIA_DATA
import com.android.systemui.media.controls.pipeline.MediaDataManager
import com.android.systemui.media.controls.util.MediaUiEventLogger
import com.android.systemui.media.dialog.MediaOutputDialogFactory
+import com.android.systemui.monet.ColorScheme
+import com.android.systemui.monet.Style
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.NotificationLockscreenUserManager
@@ -214,6 +217,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Mock private lateinit var recSubtitleMock2: TextView
@Mock private lateinit var recSubtitleMock3: TextView
@Mock private lateinit var coverItem: ImageView
+ @Mock private lateinit var matrix: Matrix
private lateinit var coverItem1: ImageView
private lateinit var coverItem2: ImageView
private lateinit var coverItem3: ImageView
@@ -700,6 +704,46 @@ public class MediaControlPanelTest : SysuiTestCase() {
}
@Test
+ fun addTwoPlayerGradients_differentStates() {
+ // Setup redArtwork and its color scheme.
+ val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+ val redCanvas = Canvas(redBmp)
+ redCanvas.drawColor(Color.RED)
+ val redArt = Icon.createWithBitmap(redBmp)
+ val redWallpaperColor = player.getWallpaperColor(redArt)
+ val redColorScheme = ColorScheme(redWallpaperColor, true, Style.CONTENT)
+
+ // Setup greenArt and its color scheme.
+ val greenBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+ val greenCanvas = Canvas(greenBmp)
+ greenCanvas.drawColor(Color.GREEN)
+ val greenArt = Icon.createWithBitmap(greenBmp)
+ val greenWallpaperColor = player.getWallpaperColor(greenArt)
+ val greenColorScheme = ColorScheme(greenWallpaperColor, true, Style.CONTENT)
+
+ // Add gradient to both icons.
+ val redArtwork = player.addGradientToPlayerAlbum(redArt, redColorScheme, 10, 10)
+ val greenArtwork = player.addGradientToPlayerAlbum(greenArt, greenColorScheme, 10, 10)
+
+ // They should have different constant states as they have different gradient color.
+ assertThat(redArtwork.getDrawable(1).constantState)
+ .isNotEqualTo(greenArtwork.getDrawable(1).constantState)
+ }
+
+ @Test
+ fun getWallpaperColor_recycledBitmap_notCrashing() {
+ // Setup redArt icon.
+ val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+ val redArt = Icon.createWithBitmap(redBmp)
+
+ // Recycle bitmap of redArt icon.
+ redArt.bitmap.recycle()
+
+ // get wallpaperColor without illegal exception.
+ player.getWallpaperColor(redArt)
+ }
+
+ @Test
fun bind_seekBarDisabled_hasActions_seekBarVisibilityIsSetToInvisible() {
useRealConstraintSets()
@@ -2092,6 +2136,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
.thenReturn(listOf(recProgressBar1, recProgressBar2, recProgressBar3))
whenever(recommendationViewHolder.mediaSubtitles)
.thenReturn(listOf(recSubtitleMock1, recSubtitleMock2, recSubtitleMock3))
+ whenever(coverItem.imageMatrix).thenReturn(matrix)
val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bmp)
@@ -2127,6 +2172,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
verify(recCardTitle).setTextColor(any<Int>())
verify(recAppIconItem, times(3)).setImageDrawable(any(Drawable::class.java))
verify(coverItem, times(3)).setImageDrawable(any(Drawable::class.java))
+ verify(coverItem, times(3)).imageMatrix = any()
}
@Test
@@ -2189,6 +2235,34 @@ public class MediaControlPanelTest : SysuiTestCase() {
}
@Test
+ fun addTwoRecommendationGradients_differentStates() {
+ // Setup redArtwork and its color scheme.
+ val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+ val redCanvas = Canvas(redBmp)
+ redCanvas.drawColor(Color.RED)
+ val redArt = Icon.createWithBitmap(redBmp)
+ val redWallpaperColor = player.getWallpaperColor(redArt)
+ val redColorScheme = ColorScheme(redWallpaperColor, true, Style.CONTENT)
+
+ // Setup greenArt and its color scheme.
+ val greenBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+ val greenCanvas = Canvas(greenBmp)
+ greenCanvas.drawColor(Color.GREEN)
+ val greenArt = Icon.createWithBitmap(greenBmp)
+ val greenWallpaperColor = player.getWallpaperColor(greenArt)
+ val greenColorScheme = ColorScheme(greenWallpaperColor, true, Style.CONTENT)
+
+ // Add gradient to both icons.
+ val redArtwork = player.addGradientToRecommendationAlbum(redArt, redColorScheme, 10, 10)
+ val greenArtwork =
+ player.addGradientToRecommendationAlbum(greenArt, greenColorScheme, 10, 10)
+
+ // They should have different constant states as they have different gradient color.
+ assertThat(redArtwork.getDrawable(1).constantState)
+ .isNotEqualTo(greenArtwork.getDrawable(1).constantState)
+ }
+
+ @Test
fun onButtonClick_touchRippleFlagEnabled_playsTouchRipple() {
fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, true)
val semanticActions =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt
index af91cdb1522c..0fac3db2dc1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt
@@ -16,9 +16,12 @@
package com.android.systemui.media.controls.ui
+import android.content.res.Configuration
+import android.content.res.Configuration.ORIENTATION_LANDSCAPE
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
+import androidx.constraintlayout.widget.ConstraintSet
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
@@ -58,6 +61,8 @@ class MediaViewControllerTest : SysuiTestCase() {
@Mock private lateinit var mediaSubTitleWidgetState: WidgetState
@Mock private lateinit var mediaContainerWidgetState: WidgetState
@Mock private lateinit var mediaFlags: MediaFlags
+ @Mock private lateinit var expandedLayout: ConstraintSet
+ @Mock private lateinit var collapsedLayout: ConstraintSet
val delta = 0.1F
@@ -77,6 +82,19 @@ class MediaViewControllerTest : SysuiTestCase() {
}
@Test
+ fun testOrientationChanged_layoutsAreLoaded() {
+ mediaViewController.expandedLayout = expandedLayout
+ mediaViewController.collapsedLayout = collapsedLayout
+
+ val newConfig = Configuration()
+ newConfig.orientation = ORIENTATION_LANDSCAPE
+ configurationController.onConfigurationChanged(newConfig)
+
+ verify(expandedLayout).load(context, R.xml.media_session_expanded)
+ verify(collapsedLayout).load(context, R.xml.media_session_collapsed)
+ }
+
+ @Test
fun testObtainViewState_applySquishFraction_toPlayerTransitionViewState_height() {
mediaViewController.attach(player, MediaViewController.TYPE.PLAYER)
player.measureState =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
index 4fc9ca71aeaa..85e8d072bd99 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
@@ -70,8 +70,7 @@ class MediaTttUtilsTest : SysuiTestCase() {
context,
appPackageName = null,
isReceiver = false,
- ) {
- }
+ ) {}
assertThat(iconInfo.isAppIcon).isFalse()
assertThat(iconInfo.contentDescription.loadContentDescription(context))
@@ -86,8 +85,7 @@ class MediaTttUtilsTest : SysuiTestCase() {
context,
appPackageName = null,
isReceiver = true,
- ) {
- }
+ ) {}
assertThat(iconInfo.isAppIcon).isFalse()
assertThat(iconInfo.contentDescription.loadContentDescription(context))
@@ -119,8 +117,7 @@ class MediaTttUtilsTest : SysuiTestCase() {
context,
appPackageName = "fakePackageName",
isReceiver = false,
- ) {
- }
+ ) {}
assertThat(iconInfo.isAppIcon).isFalse()
assertThat(iconInfo.contentDescription.loadContentDescription(context))
@@ -135,8 +132,7 @@ class MediaTttUtilsTest : SysuiTestCase() {
context,
appPackageName = "fakePackageName",
isReceiver = true,
- ) {
- }
+ ) {}
assertThat(iconInfo.isAppIcon).isFalse()
assertThat(iconInfo.contentDescription.loadContentDescription(context))
@@ -154,7 +150,9 @@ class MediaTttUtilsTest : SysuiTestCase() {
context,
appPackageName = "fakePackageName",
isReceiver = false
- ) { exceptionTriggered = true }
+ ) {
+ exceptionTriggered = true
+ }
assertThat(exceptionTriggered).isTrue()
}
@@ -167,7 +165,9 @@ class MediaTttUtilsTest : SysuiTestCase() {
context,
appPackageName = "fakePackageName",
isReceiver = true
- ) { exceptionTriggered = true }
+ ) {
+ exceptionTriggered = true
+ }
assertThat(exceptionTriggered).isTrue()
}
@@ -179,8 +179,7 @@ class MediaTttUtilsTest : SysuiTestCase() {
context,
PACKAGE_NAME,
isReceiver = false,
- ) {
- }
+ ) {}
assertThat(iconInfo.isAppIcon).isTrue()
assertThat(iconInfo.icon).isEqualTo(MediaTttIcon.Loaded(appIconFromPackageName))
@@ -194,8 +193,7 @@ class MediaTttUtilsTest : SysuiTestCase() {
context,
PACKAGE_NAME,
isReceiver = true,
- ) {
- }
+ ) {}
assertThat(iconInfo.isAppIcon).isTrue()
assertThat(iconInfo.icon).isEqualTo(MediaTttIcon.Loaded(appIconFromPackageName))
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 5058373e39b0..3d55c5131b40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -71,7 +71,7 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
@Mock
private QSPanel mQSPanel;
@Mock
- private QSTileHost mQSTileHost;
+ private QSHost mQSHost;
@Mock
private QSCustomizerController mQSCustomizerController;
@Mock
@@ -105,7 +105,7 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
/** Implementation needed to ensure we have a reflectively-available class name. */
private class TestableQSPanelControllerBase extends QSPanelControllerBase<QSPanel> {
- protected TestableQSPanelControllerBase(QSPanel view, QSTileHost host,
+ protected TestableQSPanelControllerBase(QSPanel view, QSHost host,
QSCustomizerController qsCustomizerController, MediaHost mediaHost,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
DumpManager dumpManager) {
@@ -130,8 +130,8 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
when(mQSPanel.getOrCreateTileLayout()).thenReturn(mPagedTileLayout);
when(mQSPanel.getTileLayout()).thenReturn(mPagedTileLayout);
when(mQSTile.getTileSpec()).thenReturn("dnd");
- when(mQSTileHost.getTiles()).thenReturn(Collections.singleton(mQSTile));
- when(mQSTileHost.createTileView(any(), eq(mQSTile), anyBoolean())).thenReturn(mQSTileView);
+ when(mQSHost.getTiles()).thenReturn(Collections.singleton(mQSTile));
+ when(mQSHost.createTileView(any(), eq(mQSTile), anyBoolean())).thenReturn(mQSTileView);
when(mQSTileRevealControllerFactory.create(any(), any()))
.thenReturn(mQSTileRevealController);
when(mMediaHost.getDisappearParameters()).thenReturn(new DisappearParameters());
@@ -142,7 +142,7 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
return null;
}).when(mQSPanel).setListening(anyBoolean());
- mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
+ mController = new TestableQSPanelControllerBase(mQSPanel, mQSHost,
mQSCustomizerController, mMediaHost,
mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
@@ -155,7 +155,7 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
mController.onViewDetached();
QSPanelControllerBase<QSPanel> controller = new TestableQSPanelControllerBase(mQSPanel,
- mQSTileHost, mQSCustomizerController, mMediaHost,
+ mQSHost, mQSCustomizerController, mMediaHost,
mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager) {
@Override
protected QSTileRevealController createTileRevealController() {
@@ -250,7 +250,7 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(false);
when(mQSPanel.getDumpableTag()).thenReturn("QSPanelLandscape");
- mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
+ mController = new TestableQSPanelControllerBase(mQSPanel, mQSHost,
mQSCustomizerController, mMediaHost,
mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
mController.init();
@@ -259,7 +259,7 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(true);
when(mQSPanel.getDumpableTag()).thenReturn("QSPanelPortrait");
- mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
+ mController = new TestableQSPanelControllerBase(mQSPanel, mQSHost,
mQSCustomizerController, mMediaHost,
mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
mController.init();
@@ -291,7 +291,7 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
@Test
public void testRefreshAllTilesDoesntRefreshListeningTiles() {
- when(mQSTileHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile));
+ when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile));
mController.setTiles();
when(mQSTile.isListening()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
index 5c5fbc91b030..a0d8f98a4ad1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
@@ -40,7 +40,7 @@ class QSPanelControllerTest : SysuiTestCase() {
@Mock private lateinit var qsPanel: QSPanel
@Mock private lateinit var tunerService: TunerService
- @Mock private lateinit var qsTileHost: QSTileHost
+ @Mock private lateinit var qsHost: QSHost
@Mock private lateinit var qsCustomizerController: QSCustomizerController
@Mock private lateinit var qsTileRevealControllerFactory: QSTileRevealController.Factory
@Mock private lateinit var dumpManager: DumpManager
@@ -79,7 +79,7 @@ class QSPanelControllerTest : SysuiTestCase() {
controller = QSPanelController(
qsPanel,
tunerService,
- qsTileHost,
+ qsHost,
qsCustomizerController,
/* usingMediaPlayer= */ true,
mediaHost,
@@ -109,7 +109,7 @@ class QSPanelControllerTest : SysuiTestCase() {
@Test
fun testSetListeningDoesntRefreshListeningTiles() {
- whenever(qsTileHost.getTiles()).thenReturn(listOf(tile, otherTile))
+ whenever(qsHost.getTiles()).thenReturn(listOf(tile, otherTile))
controller.setTiles()
whenever(tile.isListening()).thenReturn(false)
whenever(otherTile.isListening()).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index fb1a720b82f6..34d2b14d46a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -69,7 +69,6 @@ import com.android.systemui.settings.UserFileManager;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.CentralSurfaces;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.FakeSharedPreferences;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -100,11 +99,9 @@ public class QSTileHostTest extends SysuiTestCase {
private static ComponentName CUSTOM_TILE =
ComponentName.unflattenFromString("TEST_PKG/.TEST_CLS");
private static final String CUSTOM_TILE_SPEC = CustomTile.toSpec(CUSTOM_TILE);
- private static final String SETTING = QSTileHost.TILES_SETTING;
+ private static final String SETTING = QSHost.TILES_SETTING;
@Mock
- private StatusBarIconController mIconController;
- @Mock
private QSFactory mDefaultFactory;
@Mock
private PluginManager mPluginManager;
@@ -167,7 +164,7 @@ public class QSTileHostTest extends SysuiTestCase {
mSecureSettings = new FakeSettings();
saveSetting("");
- mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mMainExecutor,
+ mQSTileHost = new TestQSTileHost(mContext, mDefaultFactory, mMainExecutor,
mPluginManager, mTunerService, mAutoTiles, mDumpManager, mCentralSurfaces,
mQSLogger, mUiEventLogger, mUserTracker, mSecureSettings, mCustomTileStatePersister,
mTileServiceRequestControllerBuilder, mTileLifecycleManagerFactory,
@@ -248,44 +245,44 @@ public class QSTileHostTest extends SysuiTestCase {
public void testRemoveWifiAndCellularWithoutInternet() {
saveSetting("wifi, spec1, cell, spec2");
- assertEquals("internet", mQSTileHost.mTileSpecs.get(0));
- assertEquals("spec1", mQSTileHost.mTileSpecs.get(1));
- assertEquals("spec2", mQSTileHost.mTileSpecs.get(2));
+ assertEquals("internet", mQSTileHost.getSpecs().get(0));
+ assertEquals("spec1", mQSTileHost.getSpecs().get(1));
+ assertEquals("spec2", mQSTileHost.getSpecs().get(2));
}
@Test
public void testRemoveWifiAndCellularWithInternet() {
saveSetting("wifi, spec1, cell, spec2, internet");
- assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
- assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
- assertEquals("internet", mQSTileHost.mTileSpecs.get(2));
+ assertEquals("spec1", mQSTileHost.getSpecs().get(0));
+ assertEquals("spec2", mQSTileHost.getSpecs().get(1));
+ assertEquals("internet", mQSTileHost.getSpecs().get(2));
}
@Test
public void testRemoveWifiWithoutInternet() {
saveSetting("spec1, wifi, spec2");
- assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
- assertEquals("internet", mQSTileHost.mTileSpecs.get(1));
- assertEquals("spec2", mQSTileHost.mTileSpecs.get(2));
+ assertEquals("spec1", mQSTileHost.getSpecs().get(0));
+ assertEquals("internet", mQSTileHost.getSpecs().get(1));
+ assertEquals("spec2", mQSTileHost.getSpecs().get(2));
}
@Test
public void testRemoveCellWithInternet() {
saveSetting("spec1, spec2, cell, internet");
- assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
- assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
- assertEquals("internet", mQSTileHost.mTileSpecs.get(2));
+ assertEquals("spec1", mQSTileHost.getSpecs().get(0));
+ assertEquals("spec2", mQSTileHost.getSpecs().get(1));
+ assertEquals("internet", mQSTileHost.getSpecs().get(2));
}
@Test
public void testNoWifiNoCellularNoInternet() {
saveSetting("spec1,spec2");
- assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
- assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
+ assertEquals("spec1", mQSTileHost.getSpecs().get(0));
+ assertEquals("spec2", mQSTileHost.getSpecs().get(1));
}
@Test
@@ -332,9 +329,9 @@ public class QSTileHostTest extends SysuiTestCase {
mQSTileHost.addTile("spec1");
- assertEquals(2, mQSTileHost.mTileSpecs.size());
- assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
- assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
+ assertEquals(2, mQSTileHost.getSpecs().size());
+ assertEquals("spec1", mQSTileHost.getSpecs().get(0));
+ assertEquals("spec2", mQSTileHost.getSpecs().get(1));
}
@Test
@@ -346,10 +343,10 @@ public class QSTileHostTest extends SysuiTestCase {
mQSTileHost.addTile("spec2", 1);
mMainExecutor.runAllReady();
- assertEquals(3, mQSTileHost.mTileSpecs.size());
- assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
- assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
- assertEquals("spec3", mQSTileHost.mTileSpecs.get(2));
+ assertEquals(3, mQSTileHost.getSpecs().size());
+ assertEquals("spec1", mQSTileHost.getSpecs().get(0));
+ assertEquals("spec2", mQSTileHost.getSpecs().get(1));
+ assertEquals("spec3", mQSTileHost.getSpecs().get(2));
}
@Test
@@ -361,10 +358,10 @@ public class QSTileHostTest extends SysuiTestCase {
mQSTileHost.addTile("spec2", 100);
mMainExecutor.runAllReady();
- assertEquals(3, mQSTileHost.mTileSpecs.size());
- assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
- assertEquals("spec3", mQSTileHost.mTileSpecs.get(1));
- assertEquals("spec2", mQSTileHost.mTileSpecs.get(2));
+ assertEquals(3, mQSTileHost.getSpecs().size());
+ assertEquals("spec1", mQSTileHost.getSpecs().get(0));
+ assertEquals("spec3", mQSTileHost.getSpecs().get(1));
+ assertEquals("spec2", mQSTileHost.getSpecs().get(2));
}
@Test
@@ -376,10 +373,10 @@ public class QSTileHostTest extends SysuiTestCase {
mQSTileHost.addTile("spec2", QSTileHost.POSITION_AT_END);
mMainExecutor.runAllReady();
- assertEquals(3, mQSTileHost.mTileSpecs.size());
- assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
- assertEquals("spec3", mQSTileHost.mTileSpecs.get(1));
- assertEquals("spec2", mQSTileHost.mTileSpecs.get(2));
+ assertEquals(3, mQSTileHost.getSpecs().size());
+ assertEquals("spec1", mQSTileHost.getSpecs().get(0));
+ assertEquals("spec3", mQSTileHost.getSpecs().get(1));
+ assertEquals("spec2", mQSTileHost.getSpecs().get(2));
}
@Test
@@ -389,8 +386,8 @@ public class QSTileHostTest extends SysuiTestCase {
mQSTileHost.addTile(CUSTOM_TILE, /* end */ false);
mMainExecutor.runAllReady();
- assertEquals(1, mQSTileHost.mTileSpecs.size());
- assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0));
+ assertEquals(1, mQSTileHost.getSpecs().size());
+ assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.getSpecs().get(0));
}
@Test
@@ -400,8 +397,8 @@ public class QSTileHostTest extends SysuiTestCase {
mQSTileHost.addTile(CUSTOM_TILE);
mMainExecutor.runAllReady();
- assertEquals(2, mQSTileHost.mTileSpecs.size());
- assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0));
+ assertEquals(2, mQSTileHost.getSpecs().size());
+ assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.getSpecs().get(0));
}
@Test
@@ -411,8 +408,8 @@ public class QSTileHostTest extends SysuiTestCase {
mQSTileHost.addTile(CUSTOM_TILE, /* end */ false);
mMainExecutor.runAllReady();
- assertEquals(2, mQSTileHost.mTileSpecs.size());
- assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0));
+ assertEquals(2, mQSTileHost.getSpecs().size());
+ assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.getSpecs().get(0));
}
@Test
@@ -422,8 +419,8 @@ public class QSTileHostTest extends SysuiTestCase {
mQSTileHost.addTile(CUSTOM_TILE, /* end */ true);
mMainExecutor.runAllReady();
- assertEquals(2, mQSTileHost.mTileSpecs.size());
- assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(1));
+ assertEquals(2, mQSTileHost.getSpecs().size());
+ assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.getSpecs().get(1));
}
@Test
@@ -478,7 +475,7 @@ public class QSTileHostTest extends SysuiTestCase {
mQSTileHost.removeTiles(List.of("spec1", "spec2"));
mMainExecutor.runAllReady();
- assertEquals(List.of("spec3"), mQSTileHost.mTileSpecs);
+ assertEquals(List.of("spec3"), mQSTileHost.getSpecs());
}
@Test
@@ -488,7 +485,7 @@ public class QSTileHostTest extends SysuiTestCase {
mQSTileHost.removeTile("spec3");
mMainExecutor.runAllReady();
- assertEquals(List.of("spec2"), mQSTileHost.mTileSpecs);
+ assertEquals(List.of("spec2"), mQSTileHost.getSpecs());
assertEquals("spec2", getSetting());
}
@@ -497,10 +494,10 @@ public class QSTileHostTest extends SysuiTestCase {
saveSetting("spec1,spec2");
mQSTileHost.addTile("spec3");
- assertEquals(List.of("spec1", "spec2"), mQSTileHost.mTileSpecs);
+ assertEquals(List.of("spec1", "spec2"), mQSTileHost.getSpecs());
mMainExecutor.runAllReady();
- assertEquals(List.of("spec1", "spec2", "spec3"), mQSTileHost.mTileSpecs);
+ assertEquals(List.of("spec1", "spec2", "spec3"), mQSTileHost.getSpecs());
}
@Test
@@ -508,10 +505,10 @@ public class QSTileHostTest extends SysuiTestCase {
saveSetting("spec1,spec2");
mQSTileHost.removeTile("spec1");
- assertEquals(List.of("spec1", "spec2"), mQSTileHost.mTileSpecs);
+ assertEquals(List.of("spec1", "spec2"), mQSTileHost.getSpecs());
mMainExecutor.runAllReady();
- assertEquals(List.of("spec2"), mQSTileHost.mTileSpecs);
+ assertEquals(List.of("spec2"), mQSTileHost.getSpecs());
}
@Test
@@ -519,10 +516,10 @@ public class QSTileHostTest extends SysuiTestCase {
saveSetting("spec1,spec2,spec3");
mQSTileHost.removeTiles(List.of("spec3", "spec1"));
- assertEquals(List.of("spec1", "spec2", "spec3"), mQSTileHost.mTileSpecs);
+ assertEquals(List.of("spec1", "spec2", "spec3"), mQSTileHost.getSpecs());
mMainExecutor.runAllReady();
- assertEquals(List.of("spec2"), mQSTileHost.mTileSpecs);
+ assertEquals(List.of("spec2"), mQSTileHost.getSpecs());
}
@Test
@@ -530,17 +527,17 @@ public class QSTileHostTest extends SysuiTestCase {
saveSetting("spec1," + CUSTOM_TILE_SPEC);
mQSTileHost.removeTileByUser(CUSTOM_TILE);
- assertEquals(List.of("spec1", CUSTOM_TILE_SPEC), mQSTileHost.mTileSpecs);
+ assertEquals(List.of("spec1", CUSTOM_TILE_SPEC), mQSTileHost.getSpecs());
mMainExecutor.runAllReady();
- assertEquals(List.of("spec1"), mQSTileHost.mTileSpecs);
+ assertEquals(List.of("spec1"), mQSTileHost.getSpecs());
}
@Test
public void testNonValidTileNotStoredInSettings() {
saveSetting("spec1,not-valid");
- assertEquals(List.of("spec1"), mQSTileHost.mTileSpecs);
+ assertEquals(List.of("spec1"), mQSTileHost.getSpecs());
assertEquals("spec1", getSetting());
}
@@ -548,14 +545,14 @@ public class QSTileHostTest extends SysuiTestCase {
public void testNotAvailableTileNotStoredInSettings() {
saveSetting("spec1,na");
- assertEquals(List.of("spec1"), mQSTileHost.mTileSpecs);
+ assertEquals(List.of("spec1"), mQSTileHost.getSpecs());
assertEquals("spec1", getSetting());
}
@Test
public void testIsTileAdded_true() {
int user = mUserTracker.getUserId();
- getSharedPreferenecesForUser(user)
+ getSharedPreferencesForUser(user)
.edit()
.putBoolean(CUSTOM_TILE.flattenToString(), true)
.apply();
@@ -566,7 +563,7 @@ public class QSTileHostTest extends SysuiTestCase {
@Test
public void testIsTileAdded_false() {
int user = mUserTracker.getUserId();
- getSharedPreferenecesForUser(user)
+ getSharedPreferencesForUser(user)
.edit()
.putBoolean(CUSTOM_TILE.flattenToString(), false)
.apply();
@@ -597,7 +594,7 @@ public class QSTileHostTest extends SysuiTestCase {
int user = mUserTracker.getUserId();
mQSTileHost.setTileAdded(CUSTOM_TILE, user, true);
- assertTrue(getSharedPreferenecesForUser(user)
+ assertTrue(getSharedPreferencesForUser(user)
.getBoolean(CUSTOM_TILE.flattenToString(), false));
}
@@ -606,7 +603,7 @@ public class QSTileHostTest extends SysuiTestCase {
int user = mUserTracker.getUserId();
mQSTileHost.setTileAdded(CUSTOM_TILE, user, false);
- assertFalse(getSharedPreferenecesForUser(user)
+ assertFalse(getSharedPreferencesForUser(user)
.getBoolean(CUSTOM_TILE.flattenToString(), false));
}
@@ -615,7 +612,7 @@ public class QSTileHostTest extends SysuiTestCase {
int user = mUserTracker.getUserId();
mQSTileHost.setTileAdded(CUSTOM_TILE, user, true);
- assertFalse(getSharedPreferenecesForUser(user + 1)
+ assertFalse(getSharedPreferencesForUser(user + 1)
.getBoolean(CUSTOM_TILE.flattenToString(), false));
}
@@ -627,8 +624,8 @@ public class QSTileHostTest extends SysuiTestCase {
// This will be done by TileServiceManager
mQSTileHost.setTileAdded(CUSTOM_TILE, user, true);
- mQSTileHost.changeTilesByUser(mQSTileHost.mTileSpecs, List.of("spec1"));
- assertFalse(getSharedPreferenecesForUser(user)
+ mQSTileHost.changeTilesByUser(mQSTileHost.getSpecs(), List.of("spec1"));
+ assertFalse(getSharedPreferencesForUser(user)
.getBoolean(CUSTOM_TILE.flattenToString(), false));
}
@@ -642,7 +639,7 @@ public class QSTileHostTest extends SysuiTestCase {
mQSTileHost.removeTileByUser(CUSTOM_TILE);
mMainExecutor.runAllReady();
- assertFalse(getSharedPreferenecesForUser(user)
+ assertFalse(getSharedPreferencesForUser(user)
.getBoolean(CUSTOM_TILE.flattenToString(), false));
}
@@ -656,7 +653,7 @@ public class QSTileHostTest extends SysuiTestCase {
mQSTileHost.removeTile(CUSTOM_TILE_SPEC);
mMainExecutor.runAllReady();
- assertFalse(getSharedPreferenecesForUser(user)
+ assertFalse(getSharedPreferencesForUser(user)
.getBoolean(CUSTOM_TILE.flattenToString(), false));
}
@@ -681,12 +678,12 @@ public class QSTileHostTest extends SysuiTestCase {
assertEquals(CUSTOM_TILE.getClassName(), proto.tiles[1].getComponentName().className);
}
- private SharedPreferences getSharedPreferenecesForUser(int user) {
+ private SharedPreferences getSharedPreferencesForUser(int user) {
return mUserFileManager.getSharedPreferences(QSTileHost.TILES, 0, user);
}
private class TestQSTileHost extends QSTileHost {
- TestQSTileHost(Context context, StatusBarIconController iconController,
+ TestQSTileHost(Context context,
QSFactory defaultFactory, Executor mainExecutor,
PluginManager pluginManager, TunerService tunerService,
Provider<AutoTileManager> autoTiles, DumpManager dumpManager,
@@ -696,7 +693,7 @@ public class QSTileHostTest extends SysuiTestCase {
TileServiceRequestController.Builder tileServiceRequestControllerBuilder,
TileLifecycleManager.Factory tileLifecycleManagerFactory,
UserFileManager userFileManager) {
- super(context, iconController, defaultFactory, mainExecutor, pluginManager,
+ super(context, defaultFactory, mainExecutor, pluginManager,
tunerService, autoTiles, dumpManager, Optional.of(centralSurfaces), qsLogger,
uiEventLogger, userTracker, secureSettings, customTileStatePersister,
tileServiceRequestControllerBuilder, tileLifecycleManagerFactory,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index f53e997a331c..71ea831e0f92 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -50,7 +50,7 @@ import org.mockito.MockitoAnnotations
class QuickQSPanelControllerTest : SysuiTestCase() {
@Mock private lateinit var quickQSPanel: QuickQSPanel
- @Mock private lateinit var qsTileHost: QSTileHost
+ @Mock private lateinit var qsHost: QSHost
@Mock private lateinit var qsCustomizerController: QSCustomizerController
@Mock private lateinit var mediaHost: MediaHost
@Mock private lateinit var metricsLogger: MetricsLogger
@@ -75,12 +75,12 @@ class QuickQSPanelControllerTest : SysuiTestCase() {
whenever(quickQSPanel.isAttachedToWindow).thenReturn(true)
whenever(quickQSPanel.dumpableTag).thenReturn("")
whenever(quickQSPanel.resources).thenReturn(mContext.resources)
- whenever(qsTileHost.createTileView(any(), any(), anyBoolean())).thenReturn(tileView)
+ whenever(qsHost.createTileView(any(), any(), anyBoolean())).thenReturn(tileView)
controller =
TestQuickQSPanelController(
quickQSPanel,
- qsTileHost,
+ qsHost,
qsCustomizerController,
/* usingMediaPlayer = */ false,
mediaHost,
@@ -102,7 +102,7 @@ class QuickQSPanelControllerTest : SysuiTestCase() {
fun testTileSublistWithFewerTiles_noCrash() {
whenever(quickQSPanel.numQuickTiles).thenReturn(3)
- whenever(qsTileHost.tiles).thenReturn(listOf(tile, tile))
+ whenever(qsHost.tiles).thenReturn(listOf(tile, tile))
controller.setTiles()
}
@@ -111,7 +111,7 @@ class QuickQSPanelControllerTest : SysuiTestCase() {
fun testTileSublistWithTooManyTiles() {
val limit = 3
whenever(quickQSPanel.numQuickTiles).thenReturn(limit)
- whenever(qsTileHost.tiles).thenReturn(listOf(tile, tile, tile, tile))
+ whenever(qsHost.tiles).thenReturn(listOf(tile, tile, tile, tile))
controller.setTiles()
@@ -147,7 +147,7 @@ class QuickQSPanelControllerTest : SysuiTestCase() {
class TestQuickQSPanelController(
view: QuickQSPanel,
- qsTileHost: QSTileHost,
+ qsHost: QSHost,
qsCustomizerController: QSCustomizerController,
usingMediaPlayer: Boolean,
mediaHost: MediaHost,
@@ -159,7 +159,7 @@ class QuickQSPanelControllerTest : SysuiTestCase() {
) :
QuickQSPanelController(
view,
- qsTileHost,
+ qsHost,
qsCustomizerController,
usingMediaPlayer,
mediaHost,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
index d42cbe3b698a..c041cb6d0b1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
@@ -25,7 +25,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import org.junit.Before;
import org.junit.Test;
@@ -42,19 +42,19 @@ public class TileAdapterTest extends SysuiTestCase {
private TileAdapter mTileAdapter;
@Mock
- private QSTileHost mQSTileHost;
+ private QSHost mQSHost;
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
TestableLooper.get(this).runWithLooper(() -> mTileAdapter =
- new TileAdapter(mContext, mQSTileHost, new UiEventLoggerFake()));
+ new TileAdapter(mContext, mQSHost, new UiEventLoggerFake()));
}
@Test
public void testResetNotifiesHost() {
mTileAdapter.resetTileSpecs(Collections.emptyList());
- verify(mQSTileHost).changeTilesByUser(any(), any());
+ verify(mQSHost).changeTilesByUser(any(), any());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index 040af70f2077..78a02584c40a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -55,7 +55,7 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -102,7 +102,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
@Mock
private TileQueryHelper.TileStateListener mListener;
@Mock
- private QSTileHost mQSTileHost;
+ private QSHost mQSHost;
@Mock
private PackageManager mPackageManager;
@Mock
@@ -131,7 +131,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
return null;
}
}
- ).when(mQSTileHost).createTile(anyString());
+ ).when(mQSHost).createTile(anyString());
FakeSystemClock clock = new FakeSystemClock();
mMainExecutor = new FakeExecutor(clock);
mBgExecutor = new FakeExecutor(clock);
@@ -147,7 +147,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
@Test
public void testIsFinished_trueAfterQuerying() {
- mTileQueryHelper.queryTiles(mQSTileHost);
+ mTileQueryHelper.queryTiles(mQSHost);
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
@@ -156,7 +156,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
@Test
public void testQueryTiles_callsListenerTwice() {
- mTileQueryHelper.queryTiles(mQSTileHost);
+ mTileQueryHelper.queryTiles(mQSHost);
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
@@ -170,7 +170,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
return null;
}).when(mListener).onTilesChanged(any());
- mTileQueryHelper.queryTiles(mQSTileHost);
+ mTileQueryHelper.queryTiles(mQSHost);
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
@@ -184,7 +184,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
mContext.getOrCreateTestableResources().addOverride(R.string.quick_settings_tiles_stock,
STOCK_TILES);
- mTileQueryHelper.queryTiles(mQSTileHost);
+ mTileQueryHelper.queryTiles(mQSHost);
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
@@ -204,7 +204,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
mContext.getOrCreateTestableResources().addOverride(R.string.quick_settings_tiles_stock,
STOCK_TILES);
- mTileQueryHelper.queryTiles(mQSTileHost);
+ mTileQueryHelper.queryTiles(mQSHost);
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
@@ -224,7 +224,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
mContext.getOrCreateTestableResources().addOverride(R.string.quick_settings_tiles_stock,
STOCK_TILES);
- mTileQueryHelper.queryTiles(mQSTileHost);
+ mTileQueryHelper.queryTiles(mQSHost);
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
@@ -240,9 +240,9 @@ public class TileQueryHelperTest extends SysuiTestCase {
public void testCustomTileNotCreated() {
Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.QS_TILES,
CUSTOM_TILE);
- mTileQueryHelper.queryTiles(mQSTileHost);
+ mTileQueryHelper.queryTiles(mQSHost);
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
- verify(mQSTileHost, never()).createTile(CUSTOM_TILE);
+ verify(mQSHost, never()).createTile(CUSTOM_TILE);
}
@Test
@@ -264,7 +264,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
mContext.getOrCreateTestableResources().addOverride(R.string.quick_settings_tiles_stock,
"");
- mTileQueryHelper.queryTiles(mQSTileHost);
+ mTileQueryHelper.queryTiles(mQSHost);
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
verify(mListener, atLeastOnce()).onTilesChanged(mCaptor.capture());
@@ -278,7 +278,7 @@ public class TileQueryHelperTest extends SysuiTestCase {
Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.QS_TILES, null);
mContext.getOrCreateTestableResources().addOverride(R.string.quick_settings_tiles_stock,
STOCK_TILES);
- mTileQueryHelper.queryTiles(mQSTileHost);
+ mTileQueryHelper.queryTiles(mQSHost);
}
@Test
@@ -286,12 +286,12 @@ public class TileQueryHelperTest extends SysuiTestCase {
Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.QS_TILES, null);
QSTile t = mock(QSTile.class);
- when(mQSTileHost.createTile("hotspot")).thenReturn(t);
+ when(mQSHost.createTile("hotspot")).thenReturn(t);
mContext.getOrCreateTestableResources().addOverride(R.string.quick_settings_tiles_stock,
"hotspot");
- mTileQueryHelper.queryTiles(mQSTileHost);
+ mTileQueryHelper.queryTiles(mQSHost);
FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
InOrder verifier = inOrder(t);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
index 8644b5ea18ae..5be95d6f6255 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
@@ -57,6 +57,7 @@ import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
@@ -351,4 +352,44 @@ class CustomTileTest : SysuiTestCase() {
.startPendingIntentDismissingKeyguard(
eq(pi), nullable(), nullable<ActivityLaunchAnimator.Controller>())
}
+
+ @Test
+ fun testActiveTileListensOnceAfterCreated() {
+ `when`(tileServiceManager.isActiveTile).thenReturn(true)
+
+ val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
+ tile.initialize()
+ tile.postStale()
+ testableLooper.processAllMessages()
+
+ verify(tileServiceManager).setBindRequested(true)
+ verify(tileService).onStartListening()
+ }
+
+ @Test
+ fun testActiveTileDoesntListenAfterFirstTime() {
+ `when`(tileServiceManager.isActiveTile).thenReturn(true)
+
+ val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
+ tile.initialize()
+ // Make sure we have an icon in the tile because we don't have a default icon
+ // This should not be overridden by the retrieved tile that has null icon.
+ tile.qsTile.icon = mock(Icon::class.java)
+ `when`(tile.qsTile.icon.loadDrawable(any(Context::class.java)))
+ .thenReturn(mock(Drawable::class.java))
+
+ tile.postStale()
+ testableLooper.processAllMessages()
+
+ // postStale will set it to not listening after it's done
+ verify(tileService).onStopListening()
+
+ clearInvocations(tileServiceManager, tileService)
+
+ tile.setListening(Any(), true)
+ testableLooper.processAllMessages()
+
+ verify(tileServiceManager, never()).setBindRequested(true)
+ verify(tileService, never()).onStartListening()
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
index 8aa625a7ea20..46af89e00db4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
@@ -39,7 +39,7 @@ import android.test.suitebuilder.annotation.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.settings.UserTracker;
import org.junit.After;
@@ -61,7 +61,7 @@ public class TileServiceManagerTest extends SysuiTestCase {
@Mock
private UserTracker mUserTracker;
@Mock
- private QSTileHost mQSTileHost;
+ private QSHost mQSHost;
@Mock
private Context mMockContext;
@@ -80,7 +80,7 @@ public class TileServiceManagerTest extends SysuiTestCase {
when(mUserTracker.getUserHandle()).thenReturn(UserHandle.SYSTEM);
when(mTileServices.getContext()).thenReturn(mMockContext);
- when(mTileServices.getHost()).thenReturn(mQSTileHost);
+ when(mTileServices.getHost()).thenReturn(mQSHost);
when(mTileLifecycle.getUserId()).thenAnswer(invocation -> mUserTracker.getUserId());
when(mTileLifecycle.isActiveTile()).thenReturn(false);
@@ -98,28 +98,28 @@ public class TileServiceManagerTest extends SysuiTestCase {
@Test
public void testSetTileAddedIfNotAdded() {
- when(mQSTileHost.isTileAdded(eq(mComponentName), anyInt())).thenReturn(false);
+ when(mQSHost.isTileAdded(eq(mComponentName), anyInt())).thenReturn(false);
mTileServiceManager.startLifecycleManagerAndAddTile();
- verify(mQSTileHost).setTileAdded(mComponentName, mUserTracker.getUserId(), true);
+ verify(mQSHost).setTileAdded(mComponentName, mUserTracker.getUserId(), true);
}
@Test
public void testNotSetTileAddedIfAdded() {
- when(mQSTileHost.isTileAdded(eq(mComponentName), anyInt())).thenReturn(true);
+ when(mQSHost.isTileAdded(eq(mComponentName), anyInt())).thenReturn(true);
mTileServiceManager.startLifecycleManagerAndAddTile();
- verify(mQSTileHost, never()).setTileAdded(eq(mComponentName), anyInt(), eq(true));
+ verify(mQSHost, never()).setTileAdded(eq(mComponentName), anyInt(), eq(true));
}
@Test
public void testSetTileAddedCorrectUser() {
int user = 10;
when(mUserTracker.getUserId()).thenReturn(user);
- when(mQSTileHost.isTileAdded(eq(mComponentName), anyInt())).thenReturn(false);
+ when(mQSHost.isTileAdded(eq(mComponentName), anyInt())).thenReturn(false);
mTileServiceManager.startLifecycleManagerAndAddTile();
- verify(mQSTileHost).setTileAdded(mComponentName, user, true);
+ verify(mQSHost).setTileAdded(mComponentName, user, true);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceRequestControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceRequestControllerTest.kt
index bdfbca47e569..ccfb5cf8959a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceRequestControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceRequestControllerTest.kt
@@ -27,27 +27,27 @@ import com.android.internal.logging.InstanceId
import com.android.internal.statusbar.IAddTileResultCallback
import com.android.systemui.InstanceIdSequenceFake
import com.android.systemui.SysuiTestCase
-import com.android.systemui.qs.QSTileHost
+import com.android.systemui.qs.QSHost
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.google.common.truth.Truth.assertThat
+import java.util.function.Consumer
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.anyString
import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
-import java.util.function.Consumer
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -62,7 +62,7 @@ class TileServiceRequestControllerTest : SysuiTestCase() {
@Mock
private lateinit var tileRequestDialog: TileRequestDialog
@Mock
- private lateinit var qsTileHost: QSTileHost
+ private lateinit var qsHost: QSHost
@Mock
private lateinit var commandRegistry: CommandRegistry
@Mock
@@ -82,10 +82,10 @@ class TileServiceRequestControllerTest : SysuiTestCase() {
`when`(logger.newInstanceId()).thenReturn(instanceIdSequence.newInstanceId())
// Tile not present by default
- `when`(qsTileHost.indexOf(anyString())).thenReturn(-1)
+ `when`(qsHost.indexOf(anyString())).thenReturn(-1)
controller = TileServiceRequestController(
- qsTileHost,
+ qsHost,
commandQueue,
commandRegistry,
logger
@@ -107,18 +107,18 @@ class TileServiceRequestControllerTest : SysuiTestCase() {
@Test
fun tileAlreadyAdded_correctResult() {
- `when`(qsTileHost.indexOf(CustomTile.toSpec(TEST_COMPONENT))).thenReturn(2)
+ `when`(qsHost.indexOf(CustomTile.toSpec(TEST_COMPONENT))).thenReturn(2)
val callback = Callback()
controller.requestTileAdd(TEST_COMPONENT, TEST_APP_NAME, TEST_LABEL, icon, callback)
assertThat(callback.lastAccepted).isEqualTo(TileServiceRequestController.TILE_ALREADY_ADDED)
- verify(qsTileHost, never()).addTile(any(ComponentName::class.java), anyBoolean())
+ verify(qsHost, never()).addTile(any(ComponentName::class.java), anyBoolean())
}
@Test
fun tileAlreadyAdded_logged() {
- `when`(qsTileHost.indexOf(CustomTile.toSpec(TEST_COMPONENT))).thenReturn(2)
+ `when`(qsHost.indexOf(CustomTile.toSpec(TEST_COMPONENT))).thenReturn(2)
controller.requestTileAdd(TEST_COMPONENT, TEST_APP_NAME, TEST_LABEL, icon) {}
@@ -157,7 +157,7 @@ class TileServiceRequestControllerTest : SysuiTestCase() {
cancelListenerCaptor.value.onCancel(tileRequestDialog)
assertThat(callback.lastAccepted).isEqualTo(TileServiceRequestController.DISMISSED)
- verify(qsTileHost, never()).addTile(any(ComponentName::class.java), anyBoolean())
+ verify(qsHost, never()).addTile(any(ComponentName::class.java), anyBoolean())
}
@Test
@@ -191,7 +191,7 @@ class TileServiceRequestControllerTest : SysuiTestCase() {
clickListenerCaptor.value.onClick(tileRequestDialog, DialogInterface.BUTTON_POSITIVE)
assertThat(callback.lastAccepted).isEqualTo(TileServiceRequestController.ADD_TILE)
- verify(qsTileHost).addTile(TEST_COMPONENT, /* end */ true)
+ verify(qsHost).addTile(TEST_COMPONENT, /* end */ true)
}
@Test
@@ -225,7 +225,7 @@ class TileServiceRequestControllerTest : SysuiTestCase() {
clickListenerCaptor.value.onClick(tileRequestDialog, DialogInterface.BUTTON_NEGATIVE)
assertThat(callback.lastAccepted).isEqualTo(TileServiceRequestController.DONT_ADD_TILE)
- verify(qsTileHost, never()).addTile(any(ComponentName::class.java), anyBoolean())
+ verify(qsHost, never()).addTile(any(ComponentName::class.java), anyBoolean())
}
@Test
@@ -266,7 +266,7 @@ class TileServiceRequestControllerTest : SysuiTestCase() {
@Test
fun commandQueueCallback_callbackCalled() {
- `when`(qsTileHost.indexOf(CustomTile.toSpec(TEST_COMPONENT))).thenReturn(2)
+ `when`(qsHost.indexOf(CustomTile.toSpec(TEST_COMPONENT))).thenReturn(2)
val captor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
verify(commandQueue, atLeastOnce()).addCallback(capture(captor))
val c = Callback()
@@ -365,4 +365,4 @@ class TileServiceRequestControllerTest : SysuiTestCase() {
accept(r)
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 172c87f0c50b..64e9a3e58bd6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -30,7 +30,6 @@ import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.quicksettings.IQSTileService;
@@ -39,24 +38,13 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
-import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.plugins.PluginManager;
-import com.android.systemui.qs.QSTileHost;
-import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.qs.tileimpl.QSFactoryImpl;
-import com.android.systemui.settings.UserFileManager;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.AutoTileManager;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.util.settings.SecureSettings;
import org.junit.After;
import org.junit.Assert;
@@ -68,8 +56,6 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
-import java.util.Optional;
-import java.util.concurrent.Executor;
import javax.inject.Provider;
@@ -92,26 +78,8 @@ public class TileServicesTest extends SysuiTestCase {
@Mock
private StatusBarIconController mStatusBarIconController;
@Mock
- private QSFactoryImpl mQSFactory;
- @Mock
- private PluginManager mPluginManager;
- @Mock
- private TunerService mTunerService;
- @Mock
- private AutoTileManager mAutoTileManager;
- @Mock
- private DumpManager mDumpManager;
- @Mock
- private CentralSurfaces mCentralSurfaces;
- @Mock
- private QSLogger mQSLogger;
- @Mock
- private UiEventLogger mUiEventLogger;
- @Mock
private UserTracker mUserTracker;
@Mock
- private SecureSettings mSecureSettings;
- @Mock
private TileServiceRequestController.Builder mTileServiceRequestControllerBuilder;
@Mock
private TileServiceRequestController mTileServiceRequestController;
@@ -122,12 +90,11 @@ public class TileServicesTest extends SysuiTestCase {
@Mock
private TileLifecycleManager mTileLifecycleManager;
@Mock
- private UserFileManager mUserFileManager;
+ private QSHost mQSHost;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mDependency.injectMockDependency(BluetoothController.class);
mManagers = new ArrayList<>();
mTestableLooper = TestableLooper.get(this);
@@ -135,34 +102,16 @@ public class TileServicesTest extends SysuiTestCase {
.thenReturn(mTileServiceRequestController);
when(mTileLifecycleManagerFactory.create(any(Intent.class), any(UserHandle.class)))
.thenReturn(mTileLifecycleManager);
+ when(mQSHost.getContext()).thenReturn(mContext);
Provider<Handler> provider = () -> new Handler(mTestableLooper.getLooper());
- Executor executor = new HandlerExecutor(provider.get());
-
- QSTileHost host = new QSTileHost(mContext,
- mStatusBarIconController,
- mQSFactory,
- executor,
- mPluginManager,
- mTunerService,
- () -> mAutoTileManager,
- mDumpManager,
- Optional.of(mCentralSurfaces),
- mQSLogger,
- mUiEventLogger,
- mUserTracker,
- mSecureSettings,
- mock(CustomTileStatePersister.class),
- mTileServiceRequestControllerBuilder,
- mTileLifecycleManagerFactory,
- mUserFileManager);
- mTileService = new TestTileServices(host, provider, mBroadcastDispatcher,
- mUserTracker, mKeyguardStateController, mCommandQueue);
+
+ mTileService = new TestTileServices(mQSHost, provider, mBroadcastDispatcher,
+ mUserTracker, mKeyguardStateController, mCommandQueue, mStatusBarIconController);
}
@After
public void tearDown() throws Exception {
- mTileService.getHost().destroy();
mTileService.destroy();
TestableLooper.get(this).processAllMessages();
}
@@ -274,11 +223,12 @@ public class TileServicesTest extends SysuiTestCase {
}
private class TestTileServices extends TileServices {
- TestTileServices(QSTileHost host, Provider<Handler> handlerProvider,
+ TestTileServices(QSHost host, Provider<Handler> handlerProvider,
BroadcastDispatcher broadcastDispatcher, UserTracker userTracker,
- KeyguardStateController keyguardStateController, CommandQueue commandQueue) {
+ KeyguardStateController keyguardStateController, CommandQueue commandQueue,
+ StatusBarIconController statusBarIconController) {
super(host, handlerProvider, broadcastDispatcher, userTracker, keyguardStateController,
- commandQueue);
+ commandQueue, statusBarIconController);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index ba49f3fa66ee..36549fb826ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -69,7 +69,6 @@ import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSEvent;
import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.statusbar.StatusBarState;
@@ -97,7 +96,7 @@ public class QSTileImplTest extends SysuiTestCase {
private TestableLooper mTestableLooper;
private TileImpl mTile;
@Mock
- private QSTileHost mHost;
+ private QSHost mHost;
@Mock
private MetricsLogger mMetricsLogger;
private final FalsingManagerFake mFalsingManager = new FalsingManagerFake();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt
index 030c59faa696..5e0190b65a12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt
@@ -38,6 +38,7 @@ import com.android.systemui.settings.UserTracker
import com.android.systemui.util.settings.GlobalSettings
import com.google.common.truth.Truth.assertThat
import dagger.Lazy
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -94,6 +95,12 @@ class AirplaneModeTileTest : SysuiTestCase() {
mUserTracker)
}
+ @After
+ fun tearDown() {
+ mTile.destroy()
+ mTestableLooper.processAllMessages()
+ }
+
@Test
fun testIcon_whenDisabled_showsOffState() {
val state = QSTile.BooleanState()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt
index b4a662974d22..f1e3e8a71398 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt
@@ -21,6 +21,7 @@ import com.android.systemui.statusbar.policy.NextAlarmController
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -88,6 +89,12 @@ class AlarmTileTest : SysuiTestCase() {
testableLooper.processAllMessages()
}
+ @After
+ fun tearDown() {
+ tile.destroy()
+ testableLooper.processAllMessages()
+ }
+
@Test
fun testAvailable() {
assertThat(tile.isAvailable).isTrue()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
index 95e7ad9fad4d..a5c0004afe02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
@@ -37,6 +37,7 @@ import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.util.settings.SecureSettings
import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
@@ -103,6 +104,12 @@ class BatterySaverTileTest : SysuiTestCase() {
testableLooper.processAllMessages()
}
+ @After
+ fun tearDown() {
+ tile.destroy()
+ testableLooper.processAllMessages()
+ }
+
@Test
fun testSettingWithCorrectUser() {
assertEquals(USER, tile.mSetting.currentUser)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
index d65901777a73..75fd0000e0e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
@@ -17,11 +17,12 @@ import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.qs.QSTileHost
+import com.android.systemui.qs.QSHost
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.statusbar.policy.BluetoothController
import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -40,7 +41,7 @@ class BluetoothTileTest : SysuiTestCase() {
@Mock
private lateinit var qsLogger: QSLogger
@Mock
- private lateinit var qsHost: QSTileHost
+ private lateinit var qsHost: QSHost
@Mock
private lateinit var metricsLogger: MetricsLogger
private val falsingManager = FalsingManagerFake()
@@ -79,6 +80,12 @@ class BluetoothTileTest : SysuiTestCase() {
testableLooper.processAllMessages()
}
+ @After
+ fun tearDown() {
+ tile.destroy()
+ testableLooper.processAllMessages()
+ }
+
@Test
fun testRestrictionChecked() {
tile.refreshState()
@@ -135,7 +142,7 @@ class BluetoothTileTest : SysuiTestCase() {
}
private class FakeBluetoothTile(
- qsTileHost: QSTileHost,
+ qsHost: QSHost,
backgroundLooper: Looper,
mainHandler: Handler,
falsingManager: FalsingManager,
@@ -145,7 +152,7 @@ class BluetoothTileTest : SysuiTestCase() {
qsLogger: QSLogger,
bluetoothController: BluetoothController
) : BluetoothTile(
- qsTileHost,
+ qsHost,
backgroundLooper,
mainHandler,
falsingManager,
@@ -187,4 +194,4 @@ class BluetoothTileTest : SysuiTestCase() {
`when`(bluetoothController.isBluetoothConnected).thenReturn(false)
`when`(bluetoothController.isBluetoothConnecting).thenReturn(true)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt
index cfbb82f5f338..41938541124a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt
@@ -35,6 +35,7 @@ import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -90,6 +91,12 @@ class CameraToggleTileTest : SysuiTestCase() {
keyguardStateController)
}
+ @After
+ fun tearDown() {
+ tile.destroy()
+ testableLooper.processAllMessages()
+ }
+
@Test
fun testIcon_whenCameraAccessEnabled_isOnState() {
val state = QSTile.BooleanState()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
index b40a20c27820..64fd09d5f5d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -42,7 +42,7 @@ import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.statusbar.connectivity.IconState;
import com.android.systemui.statusbar.connectivity.NetworkController;
@@ -53,6 +53,7 @@ import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -78,7 +79,7 @@ public class CastTileTest extends SysuiTestCase {
@Mock
private NetworkController mNetworkController;
@Mock
- private QSTileHost mHost;
+ private QSHost mHost;
@Mock
SignalCallback mSignalCallback;
@Mock
@@ -141,6 +142,12 @@ public class CastTileTest extends SysuiTestCase {
mHotspotCallback = hotspotCallbackArgumentCaptor.getValue();
}
+ @After
+ public void tearDown() {
+ mCastTile.destroy();
+ mTestableLooper.processAllMessages();
+ }
+
// -------------------------------------------------
// All these tests for enabled/disabled wifi have hotspot not enabled
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java
index debe41c756bd..13c30e9ea9ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java
@@ -37,12 +37,13 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.util.settings.SecureSettings;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -56,7 +57,7 @@ import org.mockito.MockitoAnnotations;
public class ColorCorrectionTileTest extends SysuiTestCase {
@Mock
- private QSTileHost mHost;
+ private QSHost mHost;
@Mock
private MetricsLogger mMetricsLogger;
@Mock
@@ -101,6 +102,12 @@ public class ColorCorrectionTileTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
}
+ @After
+ public void tearDown() {
+ mTile.destroy();
+ mTestableLooper.processAllMessages();
+ }
+
@Test
public void longClick_expectedAction() {
final ArgumentCaptor<Intent> IntentCaptor = ArgumentCaptor.forClass(Intent.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
index 3fd25019e2a5..ff27e0255aa3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
@@ -39,13 +39,14 @@ import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.util.settings.SecureSettings;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -61,7 +62,7 @@ public class ColorInversionTileTest extends SysuiTestCase {
private static final Integer COLOR_INVERSION_ENABLED = 1;
@Mock
- private QSTileHost mHost;
+ private QSHost mHost;
@Mock
private MetricsLogger mMetricsLogger;
@Mock
@@ -106,6 +107,12 @@ public class ColorInversionTileTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
}
+ @After
+ public void tearDown() {
+ mTile.destroy();
+ mTestableLooper.processAllMessages();
+ }
+
@Test
public void longClick_expectedAction() {
final ArgumentCaptor<Intent> IntentCaptor = ArgumentCaptor.forClass(Intent.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt
index ce62f2d1cf36..b048643aba84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt
@@ -34,6 +34,7 @@ import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.statusbar.policy.DataSaverController
import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -84,6 +85,12 @@ class DataSaverTileTest : SysuiTestCase() {
)
}
+ @After
+ fun tearDown() {
+ tile.destroy()
+ testableLooper.processAllMessages()
+ }
+
@Test
fun testIcon_whenDataSaverEnabled_isOnState() {
val state = QSTile.BooleanState()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
index e0b3125fd62a..b51c378f6b6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
@@ -67,6 +67,7 @@ import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
import java.util.Optional
+import org.junit.After
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -129,6 +130,12 @@ class DeviceControlsTileTest : SysuiTestCase() {
tile = createTile()
}
+ @After
+ fun tearDown() {
+ tile.destroy()
+ testableLooper.processAllMessages()
+ }
+
private fun setupControlsComponent() {
`when`(controlsComponent.getControlsController()).thenAnswer {
if (featureEnabled) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt
index ce5edb147d87..6c0904eb9bfd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt
@@ -136,7 +136,8 @@ class DndTileTest : SysuiTestCase() {
@After
fun tearDown() {
- tile.handleSetListening(false)
+ tile.destroy()
+ testableLooper.processAllMessages()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java
index a13bece4b489..13e4702d9db2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java
@@ -47,13 +47,14 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.util.settings.SecureSettings;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -69,7 +70,7 @@ public class DreamTileTest extends SysuiTestCase {
@Mock
private ActivityStarter mActivityStarter;
@Mock
- private QSTileHost mHost;
+ private QSHost mHost;
@Mock
private MetricsLogger mMetricsLogger;
@Mock
@@ -112,6 +113,12 @@ public class DreamTileTest extends SysuiTestCase {
mTile.initialize();
}
+ @After
+ public void tearDown() {
+ mTile.destroy();
+ mTestableLooper.processAllMessages();
+ }
+
@Test
public void testNotAvailable() throws RemoteException {
// Should not be available if screensaver is disabled
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt
index d0f851bded75..692a64422a7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt
@@ -13,11 +13,12 @@ import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.qs.QSTileHost
+import com.android.systemui.qs.QSHost
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.statusbar.policy.FlashlightController
import com.google.common.truth.Truth
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -34,7 +35,7 @@ class FlashlightTileTest : SysuiTestCase() {
@Mock private lateinit var qsLogger: QSLogger
- @Mock private lateinit var qsHost: QSTileHost
+ @Mock private lateinit var qsHost: QSHost
@Mock private lateinit var metricsLogger: MetricsLogger
@@ -71,6 +72,12 @@ class FlashlightTileTest : SysuiTestCase() {
)
}
+ @After
+ fun tearDown() {
+ tile.destroy()
+ testableLooper.processAllMessages()
+ }
+
@Test
fun testIcon_whenFlashlightEnabled_isOnState() {
Mockito.`when`(flashlightController.isAvailable).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
index 257d42a83ba4..1dd05c7b137b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
@@ -36,6 +36,7 @@ import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.settings.FakeSettings
import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -87,6 +88,12 @@ class FontScalingTileTest : SysuiTestCase() {
testableLooper.processAllMessages()
}
+ @After
+ fun tearDown() {
+ fontScalingTile.destroy()
+ testableLooper.processAllMessages()
+ }
+
@Test
fun isAvailable_whenFlagIsFalse_returnsFalse() {
featureFlags.set(Flags.ENABLE_FONT_SCALING_TILE, false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java
index 451e9119f297..959e750ac5f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java
@@ -37,12 +37,13 @@ import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.HotspotController;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -60,7 +61,7 @@ public class HotspotTileTest extends SysuiTestCase {
@Rule
public MockitoRule mRule = MockitoJUnit.rule();
@Mock
- private QSTileHost mHost;
+ private QSHost mHost;
@Mock
private HotspotController mHotspotController;
@Mock
@@ -94,6 +95,12 @@ public class HotspotTileTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
}
+ @After
+ public void tearDown() {
+ mTile.destroy();
+ mTestableLooper.processAllMessages();
+ }
+
@Test
public void handleUpdateState_wifiTetheringIsAllowed_stateIsNotUnavailable() {
MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java
index addca9d28d1a..adfd7f71e8f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java
@@ -21,7 +21,6 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-
import android.os.Handler;
import android.service.quicksettings.Tile;
import android.testing.AndroidTestingRunner;
@@ -35,7 +34,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
@@ -44,6 +43,7 @@ import com.android.systemui.statusbar.connectivity.IconState;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.connectivity.WifiIndicators;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -56,7 +56,7 @@ import org.mockito.MockitoAnnotations;
public class InternetTileTest extends SysuiTestCase {
@Mock
- private QSTileHost mHost;
+ private QSHost mHost;
@Mock
private NetworkController mNetworkController;
@Mock
@@ -92,6 +92,12 @@ public class InternetTileTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
}
+ @After
+ public void tearDown() {
+ mTile.destroy();
+ mTestableLooper.processAllMessages();
+ }
+
@Test
public void setConnectivityStatus_defaultNetworkNotExists_updateTile() {
mTile.mSignalCallback.setConnectivityStatus(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt
index d2bbc8cfac39..33921c7c84b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt
@@ -29,12 +29,13 @@ import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.qs.QSTileHost
+import com.android.systemui.qs.QSHost
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.statusbar.policy.LocationController
import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -52,7 +53,7 @@ class LocationTileTest : SysuiTestCase() {
@Mock
private lateinit var qsLogger: QSLogger
@Mock
- private lateinit var qsHost: QSTileHost
+ private lateinit var qsHost: QSHost
@Mock
private lateinit var metricsLogger: MetricsLogger
private val falsingManager = FalsingManagerFake()
@@ -88,6 +89,12 @@ class LocationTileTest : SysuiTestCase() {
keyguardStateController)
}
+ @After
+ fun tearDown() {
+ tile.destroy()
+ testableLooper.processAllMessages()
+ }
+
@Test
fun testIcon_whenDisabled_isOffState() {
val state = QSTile.BooleanState()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt
index 1ab601ce3ebe..e2f64b2cc226 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt
@@ -35,6 +35,7 @@ import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -90,6 +91,12 @@ class MicrophoneToggleTileTest : SysuiTestCase() {
keyguardStateController)
}
+ @After
+ fun tearDown() {
+ tile.destroy()
+ testableLooper.processAllMessages()
+ }
+
@Test
fun testIcon_whenMicrophoneAccessEnabled_isOnState() {
val state = QSTile.BooleanState()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java
index cfd37358dcff..c7dae83e2056 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java
@@ -36,9 +36,10 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -60,7 +61,7 @@ public class NfcTileTest extends SysuiTestCase {
@Mock
private ActivityStarter mActivityStarter;
@Mock
- private QSTileHost mHost;
+ private QSHost mHost;
@Mock
private MetricsLogger mMetricsLogger;
@Mock
@@ -97,6 +98,12 @@ public class NfcTileTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
}
+ @After
+ public void tearDown() {
+ mNfcTile.destroy();
+ mTestableLooper.processAllMessages();
+ }
+
@Test
public void testIsAvailable_stockWithoutNfc_returnsFalse() {
when(mMockContext.getString(R.string.quick_settings_tiles_stock)).thenReturn(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt
index 188c3a3d9e42..04af69c84cf8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt
@@ -37,6 +37,7 @@ import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.statusbar.policy.LocationController
import com.google.common.truth.Truth
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -49,32 +50,23 @@ import org.mockito.MockitoAnnotations
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
class NightDisplayTileTest : SysuiTestCase() {
- @Mock
- private lateinit var mHost: QSHost
+ @Mock private lateinit var mHost: QSHost
- @Mock
- private lateinit var mMetricsLogger: MetricsLogger
+ @Mock private lateinit var mMetricsLogger: MetricsLogger
- @Mock
- private lateinit var mStatusBarStateController: StatusBarStateController
+ @Mock private lateinit var mStatusBarStateController: StatusBarStateController
- @Mock
- private lateinit var mActivityStarter: ActivityStarter
+ @Mock private lateinit var mActivityStarter: ActivityStarter
- @Mock
- private lateinit var mQsLogger: QSLogger
+ @Mock private lateinit var mQsLogger: QSLogger
- @Mock
- private lateinit var mLocationController: LocationController
+ @Mock private lateinit var mLocationController: LocationController
- @Mock
- private lateinit var mColorDisplayManager: ColorDisplayManager
+ @Mock private lateinit var mColorDisplayManager: ColorDisplayManager
- @Mock
- private lateinit var mNightDisplayListenerBuilder: NightDisplayListenerModule.Builder
+ @Mock private lateinit var mNightDisplayListenerBuilder: NightDisplayListenerModule.Builder
- @Mock
- private lateinit var mNightDisplayListener: NightDisplayListener
+ @Mock private lateinit var mNightDisplayListener: NightDisplayListener
private lateinit var mTestableLooper: TestableLooper
private lateinit var mTile: NightDisplayTile
@@ -88,24 +80,30 @@ class NightDisplayTileTest : SysuiTestCase() {
whenever(mHost.context).thenReturn(mContext)
whenever(mHost.uiEventLogger).thenReturn(mUiEventLogger)
whenever(mHost.userContext).thenReturn(mContext)
- whenever(mNightDisplayListenerBuilder.setUser(anyInt())).thenReturn(
- mNightDisplayListenerBuilder
- )
+ whenever(mNightDisplayListenerBuilder.setUser(anyInt()))
+ .thenReturn(mNightDisplayListenerBuilder)
whenever(mNightDisplayListenerBuilder.build()).thenReturn(mNightDisplayListener)
- mTile = NightDisplayTile(
- mHost,
- mTestableLooper.looper,
- Handler(mTestableLooper.looper),
- FalsingManagerFake(),
- mMetricsLogger,
- mStatusBarStateController,
- mActivityStarter,
- mQsLogger,
- mLocationController,
- mColorDisplayManager,
- mNightDisplayListenerBuilder
- )
+ mTile =
+ NightDisplayTile(
+ mHost,
+ mTestableLooper.looper,
+ Handler(mTestableLooper.looper),
+ FalsingManagerFake(),
+ mMetricsLogger,
+ mStatusBarStateController,
+ mActivityStarter,
+ mQsLogger,
+ mLocationController,
+ mColorDisplayManager,
+ mNightDisplayListenerBuilder
+ )
+ }
+
+ @After
+ fun tearDown() {
+ mTile.destroy()
+ mTestableLooper.processAllMessages()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/OneHandedModeTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/OneHandedModeTileTest.java
index 803187545a18..652c138f6478 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/OneHandedModeTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/OneHandedModeTileTest.java
@@ -32,11 +32,12 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.settings.SecureSettings;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,7 +54,7 @@ public class OneHandedModeTileTest extends SysuiTestCase {
@Mock
private ActivityStarter mActivityStarter;
@Mock
- private QSTileHost mHost;
+ private QSHost mHost;
@Mock
private MetricsLogger mMetricsLogger;
@Mock
@@ -91,6 +92,12 @@ public class OneHandedModeTileTest extends SysuiTestCase {
mTile.initialize();
}
+ @After
+ public void tearDown() {
+ mTile.destroy();
+ mTestableLooper.processAllMessages();
+ }
+
@Test
public void testIsAvailable_unsupportOneHandedProperty_shouldReturnsFalse() {
when(mTile.isSupportOneHandedMode()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
index a1be2f3ac8de..3125d455acfb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
@@ -39,10 +39,11 @@ import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -54,7 +55,7 @@ import org.mockito.MockitoAnnotations;
@SmallTest
public class QRCodeScannerTileTest extends SysuiTestCase {
@Mock
- private QSTileHost mHost;
+ private QSHost mHost;
@Mock
private MetricsLogger mMetricsLogger;
@Mock
@@ -91,6 +92,12 @@ public class QRCodeScannerTileTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
}
+ @After
+ public void tearDown() {
+ mTile.destroy();
+ mTestableLooper.processAllMessages();
+ }
+
@Test
public void testNewTile() {
assertFalse(mTile.newTileState().handlesLongClick);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
index 4f6475f0148b..596df7856ee1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
@@ -66,13 +66,14 @@ import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.wallet.controller.QuickAccessWalletController;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -99,7 +100,7 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
.setComponent(new ComponentName(mContext.getPackageName(), "WalletActivity"));
@Mock
- private QSTileHost mHost;
+ private QSHost mHost;
@Mock
private MetricsLogger mMetricsLogger;
@Mock
@@ -161,6 +162,12 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
}
+ @After
+ public void tearDown() {
+ mTile.destroy();
+ mTestableLooper.processAllMessages();
+ }
+
@Test
public void testNewTile() {
assertFalse(mTile.newTileState().handlesLongClick);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
index 04b372c4a361..7913628c5693 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
@@ -38,14 +38,14 @@ import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.ReduceBrightColorsController;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.settings.UserTracker;
+import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -54,10 +54,9 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
-@Ignore("b/269171747")
public class ReduceBrightColorsTileTest extends SysuiTestCase {
@Mock
- private QSTileHost mHost;
+ private QSHost mHost;
@Mock
private MetricsLogger mMetricsLogger;
@Mock
@@ -99,6 +98,12 @@ public class ReduceBrightColorsTileTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
}
+ @After
+ public void tearDown() {
+ mTile.destroy();
+ mTestableLooper.processAllMessages();
+ }
+
@Test
public void testNotActive() {
when(mReduceBrightColorsController.isReduceBrightColorsActivated()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
index e9dfd3ed182b..5b94cfedaedf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
@@ -38,7 +38,7 @@ import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -48,6 +48,7 @@ import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.util.wrapper.RotationPolicyWrapper;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -71,7 +72,7 @@ public class RotationLockTileTest extends SysuiTestCase {
@Mock
private ActivityStarter mActivityStarter;
@Mock
- private QSTileHost mHost;
+ private QSHost mHost;
@Mock
private MetricsLogger mMetricsLogger;
@Mock
@@ -139,6 +140,12 @@ public class RotationLockTileTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
}
+ @After
+ public void tearDown() {
+ mLockTile.destroy();
+ mTestableLooper.processAllMessages();
+ }
+
@Test
public void testSecondaryString_cameraRotateOn_returnsFaceBased() {
assertEquals(mContext.getString(R.string.rotation_lock_camera_rotation_on),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
index 30debdf4b744..5aef75832fac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -43,13 +43,14 @@ import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -65,7 +66,7 @@ public class ScreenRecordTileTest extends SysuiTestCase {
@Mock
private RecordingController mController;
@Mock
- private QSTileHost mHost;
+ private QSHost mHost;
@Mock
private KeyguardDismissUtil mKeyguardDismissUtil;
@Mock
@@ -114,6 +115,12 @@ public class ScreenRecordTileTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
}
+ @After
+ public void tearDown() {
+ mTile.destroy();
+ mTestableLooper.processAllMessages();
+ }
+
// Test that the tile is inactive and labeled correctly when the controller is neither starting
// or recording, and that clicking on the tile in this state brings up the record prompt
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt
index 0c070da1fcb9..b55657163382 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt
@@ -32,13 +32,14 @@ import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.qs.QSTileHost
+import com.android.systemui.qs.QSHost
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.LocationController
import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -55,7 +56,7 @@ class UiModeNightTileTest : SysuiTestCase() {
@Mock private lateinit var uiModeManager: UiModeManager
@Mock private lateinit var resources: Resources
@Mock private lateinit var qsLogger: QSLogger
- @Mock private lateinit var qsHost: QSTileHost
+ @Mock private lateinit var qsHost: QSHost
@Mock private lateinit var metricsLogger: MetricsLogger
@Mock private lateinit var statusBarStateController: StatusBarStateController
@Mock private lateinit var activityStarter: ActivityStarter
@@ -98,6 +99,12 @@ class UiModeNightTileTest : SysuiTestCase() {
)
}
+ @After
+ fun tearDown() {
+ tile.destroy()
+ testableLooper.processAllMessages()
+ }
+
@Test
fun testIcon_whenNightModeOn_isOnState() {
val state = QSTile.BooleanState()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
new file mode 100644
index 000000000000..4f469f753bdf
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -0,0 +1,754 @@
+/*
+ * 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.shade;
+
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+
+import static com.android.keyguard.KeyguardClockSwitch.LARGE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+
+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.atLeast;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.IdRes;
+import android.content.ContentResolver;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.UserManager;
+import android.util.DisplayMetrics;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.ViewPropertyAnimator;
+import android.view.ViewStub;
+import android.view.ViewTreeObserver;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.constraintlayout.widget.ConstraintSet;
+
+import com.android.internal.jank.InteractionJankMonitor;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.testing.UiEventLoggerFake;
+import com.android.internal.util.LatencyTracker;
+import com.android.keyguard.KeyguardClockSwitch;
+import com.android.keyguard.KeyguardClockSwitchController;
+import com.android.keyguard.KeyguardStatusView;
+import com.android.keyguard.KeyguardStatusViewController;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.LockIconViewController;
+import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent;
+import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
+import com.android.keyguard.dagger.KeyguardStatusViewComponent;
+import com.android.keyguard.dagger.KeyguardUserSwitcherComponent;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.classifier.FalsingCollectorFake;
+import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.common.ui.view.LongPressHandlingView;
+import com.android.systemui.doze.DozeLog;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.fragments.FragmentService;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel;
+import com.android.systemui.media.controls.pipeline.MediaDataManager;
+import com.android.systemui.media.controls.ui.KeyguardMediaController;
+import com.android.systemui.media.controls.ui.MediaHierarchyManager;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.navigationbar.NavigationBarController;
+import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.qs.QSFragment;
+import com.android.systemui.screenrecord.RecordingController;
+import com.android.systemui.shade.transition.ShadeTransitionController;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.NotificationShelfController;
+import com.android.systemui.statusbar.PulseExpansionHandler;
+import com.android.systemui.statusbar.QsFrameTranslateController;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.ConversationNotificationManager;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinatorLogger;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.stack.AmbientState;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
+import com.android.systemui.statusbar.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;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
+import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController;
+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.phone.TapAgainViewController;
+import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController;
+import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView;
+import com.android.systemui.statusbar.window.StatusBarWindowStateController;
+import com.android.systemui.unfold.SysUIUnfoldComponent;
+import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.util.time.SystemClock;
+import com.android.wm.shell.animation.FlingAnimationUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+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 {
+
+ protected static final int SPLIT_SHADE_FULL_TRANSITION_DISTANCE = 400;
+ protected static final int NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE = 50;
+ protected static final int PANEL_WIDTH = 500; // Random value just for the test.
+
+ @Mock protected CentralSurfaces mCentralSurfaces;
+ @Mock protected NotificationStackScrollLayout mNotificationStackScrollLayout;
+ @Mock protected KeyguardBottomAreaView mKeyguardBottomArea;
+ @Mock protected KeyguardBottomAreaViewController mKeyguardBottomAreaViewController;
+ @Mock protected KeyguardBottomAreaView mQsFrame;
+ @Mock protected HeadsUpManagerPhone mHeadsUpManager;
+ @Mock protected NotificationShelfController mNotificationShelfController;
+ @Mock protected NotificationGutsManager mGutsManager;
+ @Mock protected KeyguardStatusBarView mKeyguardStatusBar;
+ @Mock protected KeyguardUserSwitcherView mUserSwitcherView;
+ @Mock protected ViewStub mUserSwitcherStubView;
+ @Mock protected HeadsUpTouchHelper.Callback mHeadsUpCallback;
+ @Mock protected KeyguardUpdateMonitor mUpdateMonitor;
+ @Mock protected KeyguardBypassController mKeyguardBypassController;
+ @Mock protected DozeParameters mDozeParameters;
+ @Mock protected ScreenOffAnimationController mScreenOffAnimationController;
+ @Mock protected NotificationPanelView mView;
+ @Mock protected LayoutInflater mLayoutInflater;
+ @Mock protected FeatureFlags mFeatureFlags;
+ @Mock protected DynamicPrivacyController mDynamicPrivacyController;
+ @Mock protected StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+ @Mock protected KeyguardStateController mKeyguardStateController;
+ @Mock protected DozeLog mDozeLog;
+ @Mock protected ShadeLogger mShadeLog;
+ @Mock protected ShadeHeightLogger mShadeHeightLogger;
+ @Mock protected CommandQueue mCommandQueue;
+ @Mock protected VibratorHelper mVibratorHelper;
+ @Mock protected LatencyTracker mLatencyTracker;
+ @Mock protected PowerManager mPowerManager;
+ @Mock protected AccessibilityManager mAccessibilityManager;
+ @Mock protected MetricsLogger mMetricsLogger;
+ @Mock protected Resources mResources;
+ @Mock protected Configuration mConfiguration;
+ @Mock protected KeyguardClockSwitch mKeyguardClockSwitch;
+ @Mock protected MediaHierarchyManager mMediaHierarchyManager;
+ @Mock protected ConversationNotificationManager mConversationNotificationManager;
+ @Mock protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ @Mock protected KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
+ @Mock protected KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory;
+ @Mock protected KeyguardQsUserSwitchComponent mKeyguardQsUserSwitchComponent;
+ @Mock protected KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
+ @Mock protected KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
+ @Mock protected KeyguardUserSwitcherComponent mKeyguardUserSwitcherComponent;
+ @Mock protected KeyguardUserSwitcherController mKeyguardUserSwitcherController;
+ @Mock protected KeyguardStatusViewComponent mKeyguardStatusViewComponent;
+ @Mock protected KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
+ @Mock protected KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent;
+ @Mock protected KeyguardClockSwitchController mKeyguardClockSwitchController;
+ @Mock protected KeyguardStatusViewController mKeyguardStatusViewController;
+ @Mock protected KeyguardStatusBarViewController mKeyguardStatusBarViewController;
+ @Mock protected NotificationStackScrollLayoutController
+ mNotificationStackScrollLayoutController;
+ @Mock protected NotificationShadeDepthController mNotificationShadeDepthController;
+ @Mock protected LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ @Mock protected AuthController mAuthController;
+ @Mock protected ScrimController mScrimController;
+ @Mock protected MediaDataManager mMediaDataManager;
+ @Mock protected AmbientState mAmbientState;
+ @Mock protected UserManager mUserManager;
+ @Mock protected UiEventLogger mUiEventLogger;
+ @Mock protected LockIconViewController mLockIconViewController;
+ @Mock protected KeyguardMediaController mKeyguardMediaController;
+ @Mock protected NavigationModeController mNavigationModeController;
+ @Mock protected NavigationBarController mNavigationBarController;
+ @Mock protected QuickSettingsController mQsController;
+ @Mock protected ShadeHeaderController mShadeHeaderController;
+ @Mock protected ContentResolver mContentResolver;
+ @Mock protected TapAgainViewController mTapAgainViewController;
+ @Mock protected KeyguardIndicationController mKeyguardIndicationController;
+ @Mock protected FragmentService mFragmentService;
+ @Mock protected FragmentHostManager mFragmentHostManager;
+ @Mock protected NotificationRemoteInputManager mNotificationRemoteInputManager;
+ @Mock protected RecordingController mRecordingController;
+ @Mock protected LockscreenGestureLogger mLockscreenGestureLogger;
+ @Mock protected DumpManager mDumpManager;
+ @Mock protected InteractionJankMonitor mInteractionJankMonitor;
+ @Mock protected NotificationsQSContainerController mNotificationsQSContainerController;
+ @Mock protected QsFrameTranslateController mQsFrameTranslateController;
+ @Mock protected StatusBarWindowStateController mStatusBarWindowStateController;
+ @Mock protected KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ @Mock protected NotificationShadeWindowController mNotificationShadeWindowController;
+ @Mock protected SysUiState mSysUiState;
+ @Mock protected NotificationListContainer mNotificationListContainer;
+ @Mock protected NotificationStackSizeCalculator mNotificationStackSizeCalculator;
+ @Mock protected UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+ @Mock protected ShadeTransitionController mShadeTransitionController;
+ @Mock protected QS mQs;
+ @Mock protected QSFragment mQSFragment;
+ @Mock protected ViewGroup mQsHeader;
+ @Mock protected ViewParent mViewParent;
+ @Mock protected ViewTreeObserver mViewTreeObserver;
+ @Mock protected KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
+ @Mock protected DreamingToLockscreenTransitionViewModel
+ mDreamingToLockscreenTransitionViewModel;
+ @Mock protected OccludedToLockscreenTransitionViewModel
+ mOccludedToLockscreenTransitionViewModel;
+ @Mock protected LockscreenToDreamingTransitionViewModel
+ mLockscreenToDreamingTransitionViewModel;
+ @Mock protected LockscreenToOccludedTransitionViewModel
+ mLockscreenToOccludedTransitionViewModel;
+ @Mock protected GoneToDreamingTransitionViewModel mGoneToDreamingTransitionViewModel;
+
+ @Mock protected KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ @Mock protected KeyguardLongPressViewModel mKeyuardLongPressViewModel;
+ @Mock protected AlternateBouncerInteractor mAlternateBouncerInteractor;
+ @Mock protected MotionEvent mDownMotionEvent;
+ @Mock protected CoroutineDispatcher mMainDispatcher;
+ @Captor
+ protected ArgumentCaptor<NotificationStackScrollLayout.OnEmptySpaceClickListener>
+ mEmptySpaceClickListenerCaptor;
+
+ protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
+ protected KeyguardInteractor mKeyguardInteractor;
+ protected NotificationPanelViewController.TouchHandler mTouchHandler;
+ protected ConfigurationController mConfigurationController;
+ protected SysuiStatusBarStateController mStatusBarStateController;
+ protected NotificationPanelViewController mNotificationPanelViewController;
+ protected View.AccessibilityDelegate mAccessibilityDelegate;
+ protected NotificationsQuickSettingsContainer mNotificationContainerParent;
+ protected List<View.OnAttachStateChangeListener> mOnAttachStateChangeListeners;
+ protected Handler mMainHandler;
+ protected View.OnLayoutChangeListener mLayoutChangeListener;
+
+ protected final FalsingManagerFake mFalsingManager = new FalsingManagerFake();
+ protected final Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
+ protected final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+ protected final ShadeExpansionStateManager mShadeExpansionStateManager =
+ new ShadeExpansionStateManager();
+
+ protected QuickSettingsController mQuickSettingsController;
+ @Mock protected Lazy<NotificationPanelViewController> mNotificationPanelViewControllerLazy;
+
+ protected FragmentHostManager.FragmentListener mFragmentListener;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mMainDispatcher = getMainDispatcher();
+ mKeyguardBottomAreaInteractor = new KeyguardBottomAreaInteractor(
+ new FakeKeyguardRepository());
+ mKeyguardInteractor = new KeyguardInteractor(new FakeKeyguardRepository(), mCommandQueue,
+ mFeatureFlags, new FakeKeyguardBouncerRepository());
+ SystemClock systemClock = new FakeSystemClock();
+ mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager,
+ mInteractionJankMonitor, mShadeExpansionStateManager);
+
+ KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
+ keyguardStatusView.setId(R.id.keyguard_status_view);
+
+ when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
+ when(mHeadsUpCallback.getContext()).thenReturn(mContext);
+ when(mView.getResources()).thenReturn(mResources);
+ when(mView.getWidth()).thenReturn(PANEL_WIDTH);
+ when(mResources.getConfiguration()).thenReturn(mConfiguration);
+ mConfiguration.orientation = ORIENTATION_PORTRAIT;
+ when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
+ mDisplayMetrics.density = 100;
+ when(mResources.getBoolean(R.bool.config_enableNotificationShadeDrag)).thenReturn(true);
+ when(mResources.getDimensionPixelSize(R.dimen.notifications_top_padding_split_shade))
+ .thenReturn(NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE);
+ when(mResources.getDimensionPixelSize(R.dimen.notification_panel_margin_horizontal))
+ .thenReturn(10);
+ when(mResources.getDimensionPixelSize(R.dimen.split_shade_full_transition_distance))
+ .thenReturn(SPLIT_SHADE_FULL_TRANSITION_DISTANCE);
+ when(mView.getContext()).thenReturn(getContext());
+ when(mView.findViewById(R.id.keyguard_header)).thenReturn(mKeyguardStatusBar);
+ when(mView.findViewById(R.id.keyguard_user_switcher_view)).thenReturn(mUserSwitcherView);
+ when(mView.findViewById(R.id.keyguard_user_switcher_stub)).thenReturn(
+ mUserSwitcherStubView);
+ when(mView.findViewById(R.id.keyguard_clock_container)).thenReturn(mKeyguardClockSwitch);
+ when(mView.findViewById(R.id.notification_stack_scroller))
+ .thenReturn(mNotificationStackScrollLayout);
+ when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(1000);
+ when(mNotificationStackScrollLayoutController.getHeadsUpCallback())
+ .thenReturn(mHeadsUpCallback);
+ when(mKeyguardBottomAreaViewController.getView()).thenReturn(mKeyguardBottomArea);
+ when(mView.findViewById(R.id.keyguard_bottom_area)).thenReturn(mKeyguardBottomArea);
+ when(mKeyguardBottomArea.animate()).thenReturn(mock(ViewPropertyAnimator.class));
+ when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame);
+ when(mView.findViewById(R.id.keyguard_status_view))
+ .thenReturn(mock(KeyguardStatusView.class));
+ mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
+ mNotificationContainerParent.addView(keyguardStatusView);
+ mNotificationContainerParent.onFinishInflate();
+ when(mView.findViewById(R.id.notification_container_parent))
+ .thenReturn(mNotificationContainerParent);
+ when(mFragmentService.getFragmentHostManager(mView)).thenReturn(mFragmentHostManager);
+ FlingAnimationUtils.Builder flingAnimationUtilsBuilder = new FlingAnimationUtils.Builder(
+ mDisplayMetrics);
+ when(mKeyguardQsUserSwitchComponentFactory.build(any()))
+ .thenReturn(mKeyguardQsUserSwitchComponent);
+ when(mKeyguardQsUserSwitchComponent.getKeyguardQsUserSwitchController())
+ .thenReturn(mKeyguardQsUserSwitchController);
+ when(mKeyguardUserSwitcherComponentFactory.build(any()))
+ .thenReturn(mKeyguardUserSwitcherComponent);
+ when(mKeyguardUserSwitcherComponent.getKeyguardUserSwitcherController())
+ .thenReturn(mKeyguardUserSwitcherController);
+ when(mScreenOffAnimationController.shouldAnimateClockChange()).thenReturn(true);
+ when(mQs.getView()).thenReturn(mView);
+ when(mQSFragment.getView()).thenReturn(mView);
+ doAnswer(invocation -> {
+ mFragmentListener = invocation.getArgument(1);
+ return null;
+ }).when(mFragmentHostManager).addTagListener(eq(QS.TAG), any());
+ doAnswer((Answer<Void>) invocation -> {
+ mTouchHandler = invocation.getArgument(0);
+ return null;
+ }).when(mView).setOnTouchListener(any(NotificationPanelViewController.TouchHandler.class));
+
+ // Dreaming->Lockscreen
+ when(mKeyguardTransitionInteractor.getDreamingToLockscreenTransition())
+ .thenReturn(emptyFlow());
+ when(mDreamingToLockscreenTransitionViewModel.getLockscreenAlpha())
+ .thenReturn(emptyFlow());
+ when(mDreamingToLockscreenTransitionViewModel.lockscreenTranslationY(anyInt()))
+ .thenReturn(emptyFlow());
+
+ // Occluded->Lockscreen
+ when(mKeyguardTransitionInteractor.getOccludedToLockscreenTransition())
+ .thenReturn(emptyFlow());
+ when(mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha())
+ .thenReturn(emptyFlow());
+ when(mOccludedToLockscreenTransitionViewModel.lockscreenTranslationY(anyInt()))
+ .thenReturn(emptyFlow());
+
+ // Lockscreen->Dreaming
+ when(mKeyguardTransitionInteractor.getLockscreenToDreamingTransition())
+ .thenReturn(emptyFlow());
+ when(mLockscreenToDreamingTransitionViewModel.getLockscreenAlpha())
+ .thenReturn(emptyFlow());
+ when(mLockscreenToDreamingTransitionViewModel.lockscreenTranslationY(anyInt()))
+ .thenReturn(emptyFlow());
+
+ // Gone->Dreaming
+ when(mKeyguardTransitionInteractor.getGoneToDreamingTransition())
+ .thenReturn(emptyFlow());
+ when(mGoneToDreamingTransitionViewModel.getLockscreenAlpha())
+ .thenReturn(emptyFlow());
+ when(mGoneToDreamingTransitionViewModel.lockscreenTranslationY(anyInt()))
+ .thenReturn(emptyFlow());
+
+ // Lockscreen->Occluded
+ when(mKeyguardTransitionInteractor.getLockscreenToOccludedTransition())
+ .thenReturn(emptyFlow());
+ when(mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha())
+ .thenReturn(emptyFlow());
+ when(mLockscreenToOccludedTransitionViewModel.lockscreenTranslationY(anyInt()))
+ .thenReturn(emptyFlow());
+
+ NotificationWakeUpCoordinator coordinator =
+ new NotificationWakeUpCoordinator(
+ mDumpManager,
+ mock(HeadsUpManagerPhone.class),
+ new StatusBarStateControllerImpl(new UiEventLoggerFake(), mDumpManager,
+ mInteractionJankMonitor, mShadeExpansionStateManager),
+ mKeyguardBypassController,
+ mDozeParameters,
+ mScreenOffAnimationController,
+ mock(NotificationWakeUpCoordinatorLogger.class));
+ mConfigurationController = new ConfigurationControllerImpl(mContext);
+ PulseExpansionHandler expansionHandler = new PulseExpansionHandler(
+ mContext,
+ coordinator,
+ mKeyguardBypassController, mHeadsUpManager,
+ mock(NotificationRoundnessManager.class),
+ mConfigurationController,
+ mStatusBarStateController,
+ mFalsingManager,
+ mShadeExpansionStateManager,
+ mLockscreenShadeTransitionController,
+ new FalsingCollectorFake(),
+ mDumpManager);
+ when(mKeyguardStatusViewComponentFactory.build(any()))
+ .thenReturn(mKeyguardStatusViewComponent);
+ when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
+ .thenReturn(mKeyguardClockSwitchController);
+ when(mKeyguardStatusViewComponent.getKeyguardStatusViewController())
+ .thenReturn(mKeyguardStatusViewController);
+ when(mKeyguardStatusBarViewComponentFactory.build(any(), any()))
+ .thenReturn(mKeyguardStatusBarViewComponent);
+ when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
+ .thenReturn(mKeyguardStatusBarViewController);
+ when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean()))
+ .thenReturn(keyguardStatusView);
+ when(mLayoutInflater.inflate(eq(R.layout.keyguard_user_switcher), any(), anyBoolean()))
+ .thenReturn(mUserSwitcherView);
+ when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean()))
+ .thenReturn(mKeyguardBottomArea);
+ when(mNotificationRemoteInputManager.isRemoteInputActive())
+ .thenReturn(false);
+ when(mInteractionJankMonitor.begin(any(), anyInt()))
+ .thenReturn(true);
+ when(mInteractionJankMonitor.end(anyInt()))
+ .thenReturn(true);
+ doAnswer(invocation -> {
+ ((Runnable) invocation.getArgument(0)).run();
+ return null;
+ }).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
+ doAnswer(invocation -> {
+ mLayoutChangeListener = invocation.getArgument(0);
+ return null;
+ }).when(mView).addOnLayoutChangeListener(any());
+
+ when(mView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
+ when(mView.getParent()).thenReturn(mViewParent);
+ when(mQs.getHeader()).thenReturn(mQsHeader);
+ when(mDownMotionEvent.getAction()).thenReturn(MotionEvent.ACTION_DOWN);
+ when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState);
+
+ mMainHandler = new Handler(Looper.getMainLooper());
+
+ when(mView.requireViewById(R.id.keyguard_long_press))
+ .thenReturn(mock(LongPressHandlingView.class));
+
+ mNotificationPanelViewController = new NotificationPanelViewController(
+ mView,
+ mMainHandler,
+ mLayoutInflater,
+ mFeatureFlags,
+ coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
+ mFalsingManager, new FalsingCollectorFake(),
+ mKeyguardStateController,
+ mStatusBarStateController,
+ mStatusBarWindowStateController,
+ mNotificationShadeWindowController,
+ mDozeLog, mDozeParameters, mCommandQueue, mVibratorHelper,
+ mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
+ mMetricsLogger,
+ mShadeLog,
+ mShadeHeightLogger,
+ mConfigurationController,
+ () -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
+ mConversationNotificationManager, mMediaHierarchyManager,
+ mStatusBarKeyguardViewManager,
+ mGutsManager,
+ mNotificationsQSContainerController,
+ mNotificationStackScrollLayoutController,
+ mKeyguardStatusViewComponentFactory,
+ mKeyguardQsUserSwitchComponentFactory,
+ mKeyguardUserSwitcherComponentFactory,
+ mKeyguardStatusBarViewComponentFactory,
+ mLockscreenShadeTransitionController,
+ mAuthController,
+ mScrimController,
+ mUserManager,
+ mMediaDataManager,
+ mNotificationShadeDepthController,
+ mAmbientState,
+ mLockIconViewController,
+ mKeyguardMediaController,
+ mTapAgainViewController,
+ mNavigationModeController,
+ mNavigationBarController,
+ mQsController,
+ mFragmentService,
+ mContentResolver,
+ mRecordingController,
+ mShadeHeaderController,
+ mScreenOffAnimationController,
+ mLockscreenGestureLogger,
+ mShadeExpansionStateManager,
+ mNotificationRemoteInputManager,
+ mSysUIUnfoldComponent,
+ mSysUiState,
+ () -> mKeyguardBottomAreaViewController,
+ mKeyguardUnlockAnimationController,
+ mKeyguardIndicationController,
+ mNotificationListContainer,
+ mNotificationStackSizeCalculator,
+ mUnlockedScreenOffAnimationController,
+ mShadeTransitionController,
+ mInteractionJankMonitor,
+ systemClock,
+ mKeyguardBottomAreaViewModel,
+ mKeyguardBottomAreaInteractor,
+ mAlternateBouncerInteractor,
+ mDreamingToLockscreenTransitionViewModel,
+ mOccludedToLockscreenTransitionViewModel,
+ mLockscreenToDreamingTransitionViewModel,
+ mGoneToDreamingTransitionViewModel,
+ mLockscreenToOccludedTransitionViewModel,
+ mMainDispatcher,
+ mKeyguardTransitionInteractor,
+ mDumpManager,
+ mKeyuardLongPressViewModel,
+ mKeyguardInteractor);
+ mNotificationPanelViewController.initDependencies(
+ mCentralSurfaces,
+ null,
+ () -> {},
+ mNotificationShelfController);
+ mNotificationPanelViewController.setTrackingStartedListener(() -> {});
+ mNotificationPanelViewController.setOpenCloseListener(
+ new NotificationPanelViewController.OpenCloseListener() {
+ @Override
+ public void onClosingFinished() {}
+
+ @Override
+ public void onOpenStarted() {}
+ });
+ mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
+ ArgumentCaptor<View.OnAttachStateChangeListener> onAttachStateChangeListenerArgumentCaptor =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+ verify(mView, atLeast(1)).addOnAttachStateChangeListener(
+ onAttachStateChangeListenerArgumentCaptor.capture());
+ mOnAttachStateChangeListeners = onAttachStateChangeListenerArgumentCaptor.getAllValues();
+
+ ArgumentCaptor<View.AccessibilityDelegate> accessibilityDelegateArgumentCaptor =
+ ArgumentCaptor.forClass(View.AccessibilityDelegate.class);
+ verify(mView).setAccessibilityDelegate(accessibilityDelegateArgumentCaptor.capture());
+ mAccessibilityDelegate = accessibilityDelegateArgumentCaptor.getValue();
+ mNotificationPanelViewController.getStatusBarStateController()
+ .addCallback(mNotificationPanelViewController.getStatusBarStateListener());
+ mNotificationPanelViewController
+ .setHeadsUpAppearanceController(mock(HeadsUpAppearanceController.class));
+ verify(mNotificationStackScrollLayoutController)
+ .setOnEmptySpaceClickListener(mEmptySpaceClickListenerCaptor.capture());
+ verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ true);
+ reset(mKeyguardStatusViewController);
+
+ when(mNotificationPanelViewControllerLazy.get())
+ .thenReturn(mNotificationPanelViewController);
+ mQuickSettingsController = new QuickSettingsController(
+ mNotificationPanelViewControllerLazy,
+ mView,
+ mQsFrameTranslateController,
+ mShadeTransitionController,
+ expansionHandler,
+ mNotificationRemoteInputManager,
+ mShadeExpansionStateManager,
+ mStatusBarKeyguardViewManager,
+ mNotificationStackScrollLayoutController,
+ mLockscreenShadeTransitionController,
+ mNotificationShadeDepthController,
+ mShadeHeaderController,
+ mStatusBarTouchableRegionManager,
+ mKeyguardStateController,
+ mKeyguardBypassController,
+ mUpdateMonitor,
+ mScrimController,
+ mMediaDataManager,
+ mMediaHierarchyManager,
+ mAmbientState,
+ mRecordingController,
+ mFalsingManager,
+ new FalsingCollectorFake(),
+ mAccessibilityManager,
+ mLockscreenGestureLogger,
+ mMetricsLogger,
+ mFeatureFlags,
+ mInteractionJankMonitor,
+ mShadeLog
+ );
+ }
+
+ @After
+ public void tearDown() {
+ mNotificationPanelViewController.mBottomAreaShadeAlphaAnimator.cancel();
+ mNotificationPanelViewController.cancelHeightAnimator();
+ mMainHandler.removeCallbacksAndMessages(null);
+ }
+
+ protected void setBottomPadding(int stackBottom, int lockIconPadding, int indicationPadding,
+ int ambientPadding) {
+
+ when(mNotificationStackScrollLayoutController.getTop()).thenReturn(0);
+ when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(stackBottom);
+ when(mNotificationStackScrollLayoutController.getBottom()).thenReturn(stackBottom);
+ when(mLockIconViewController.getTop()).thenReturn((float) (stackBottom - lockIconPadding));
+
+ when(mResources.getDimensionPixelSize(R.dimen.keyguard_indication_bottom_padding))
+ .thenReturn(indicationPadding);
+ mNotificationPanelViewController.loadDimens();
+
+ mNotificationPanelViewController.setAmbientIndicationTop(
+ /* ambientIndicationTop= */ stackBottom - ambientPadding,
+ /* ambientTextVisible= */ true);
+ }
+
+ protected void triggerPositionClockAndNotifications() {
+ mNotificationPanelViewController.onQsSetExpansionHeightCalled(false);
+ }
+
+ protected FalsingManager.FalsingTapListener getFalsingTapListener() {
+ for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
+ listener.onViewAttachedToWindow(mView);
+ }
+ assertThat(mFalsingManager.getTapListeners().size()).isEqualTo(1);
+ return mFalsingManager.getTapListeners().get(0);
+ }
+
+ protected void givenViewAttached() {
+ for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
+ listener.onViewAttachedToWindow(mView);
+ }
+ }
+
+ protected ConstraintSet.Layout getConstraintSetLayout(@IdRes int id) {
+ ConstraintSet constraintSet = new ConstraintSet();
+ constraintSet.clone(mNotificationContainerParent);
+ return constraintSet.getConstraint(id).layout;
+ }
+
+ protected void enableSplitShade(boolean enabled) {
+ when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(enabled);
+ mNotificationPanelViewController.updateResources();
+ }
+
+ protected void updateMultiUserSetting(boolean enabled) {
+ when(mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user)).thenReturn(false);
+ when(mUserManager.isUserSwitcherEnabled(false)).thenReturn(enabled);
+ final ArgumentCaptor<ContentObserver> observerCaptor =
+ ArgumentCaptor.forClass(ContentObserver.class);
+ verify(mContentResolver)
+ .registerContentObserver(any(), anyBoolean(), observerCaptor.capture());
+ observerCaptor.getValue().onChange(/* selfChange */ false);
+ }
+
+ protected void updateSmallestScreenWidth(int smallestScreenWidthDp) {
+ Configuration configuration = new Configuration();
+ configuration.smallestScreenWidthDp = smallestScreenWidthDp;
+ mConfigurationController.onConfigurationChanged(configuration);
+ }
+
+ protected void onTouchEvent(MotionEvent ev) {
+ mTouchHandler.onTouch(mView, ev);
+ }
+
+ protected void setDozing(boolean dozing, boolean dozingAlwaysOn) {
+ when(mDozeParameters.getAlwaysOn()).thenReturn(dozingAlwaysOn);
+ mNotificationPanelViewController.setDozing(
+ /* dozing= */ dozing,
+ /* animate= */ false
+ );
+ }
+
+ protected void assertKeyguardStatusViewCentered() {
+ mNotificationPanelViewController.updateResources();
+ assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd).isAnyOf(
+ ConstraintSet.PARENT_ID, ConstraintSet.UNSET);
+ }
+
+ protected void assertKeyguardStatusViewNotCentered() {
+ mNotificationPanelViewController.updateResources();
+ assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd).isEqualTo(
+ R.id.qs_edge_guideline);
+ }
+
+ protected void setIsFullWidth(boolean fullWidth) {
+ float nsslWidth = fullWidth ? PANEL_WIDTH : PANEL_WIDTH / 2f;
+ when(mNotificationStackScrollLayoutController.getWidth()).thenReturn(nsslWidth);
+ triggerLayoutChange();
+ }
+
+ protected void triggerLayoutChange() {
+ mLayoutChangeListener.onLayoutChange(
+ mView,
+ /* left= */ 0,
+ /* top= */ 0,
+ /* right= */ 0,
+ /* bottom= */ 0,
+ /* oldLeft= */ 0,
+ /* oldTop= */ 0,
+ /* oldRight= */ 0,
+ /* oldBottom= */ 0
+ );
+ }
+
+ protected CoroutineDispatcher getMainDispatcher() {
+ return mMainDispatcher;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index a27d4031ddde..abcde3dca4e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -16,8 +16,6 @@
package com.android.systemui.shade;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-
import static com.android.keyguard.FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
@@ -31,592 +29,53 @@ import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.annotation.IdRes;
-import android.content.ContentResolver;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.PowerManager;
-import android.os.UserManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.util.DisplayMetrics;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.ViewPropertyAnimator;
-import android.view.ViewStub;
-import android.view.ViewTreeObserver;
-import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.test.filters.SmallTest;
-import com.android.internal.jank.InteractionJankMonitor;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.testing.UiEventLoggerFake;
-import com.android.internal.util.CollectionUtils;
-import com.android.internal.util.LatencyTracker;
import com.android.keyguard.FaceAuthApiRequestReason;
-import com.android.keyguard.KeyguardClockSwitch;
-import com.android.keyguard.KeyguardClockSwitchController;
-import com.android.keyguard.KeyguardStatusView;
-import com.android.keyguard.KeyguardStatusViewController;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.LockIconViewController;
-import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent;
-import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
-import com.android.keyguard.dagger.KeyguardStatusViewComponent;
-import com.android.keyguard.dagger.KeyguardUserSwitcherComponent;
import com.android.systemui.DejankUtils;
import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.biometrics.AuthController;
-import com.android.systemui.classifier.FalsingCollectorFake;
-import com.android.systemui.classifier.FalsingManagerFake;
-import com.android.systemui.common.ui.view.LongPressHandlingView;
-import com.android.systemui.doze.DozeLog;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.fragments.FragmentHostManager;
-import com.android.systemui.fragments.FragmentService;
-import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
-import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
-import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
-import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel;
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel;
-import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel;
-import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel;
-import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel;
-import com.android.systemui.media.controls.pipeline.MediaDataManager;
-import com.android.systemui.media.controls.ui.KeyguardMediaController;
-import com.android.systemui.media.controls.ui.MediaHierarchyManager;
-import com.android.systemui.model.SysUiState;
-import com.android.systemui.navigationbar.NavigationBarController;
-import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSFragment;
-import com.android.systemui.screenrecord.RecordingController;
-import com.android.systemui.shade.transition.ShadeTransitionController;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.KeyguardIndicationController;
-import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.NotificationShadeDepthController;
-import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.NotificationShelfController;
-import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.QsFrameTranslateController;
-import com.android.systemui.statusbar.StatusBarStateControllerImpl;
-import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.notification.ConversationNotificationManager;
-import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinatorLogger;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.AmbientState;
-import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
-import com.android.systemui.statusbar.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;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
-import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController;
-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.phone.TapAgainViewController;
-import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController;
-import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView;
-import com.android.systemui.statusbar.window.StatusBarWindowStateController;
-import com.android.systemui.unfold.SysUIUnfoldComponent;
-import com.android.systemui.util.time.FakeSystemClock;
-import com.android.systemui.util.time.SystemClock;
-import com.android.wm.shell.animation.FlingAnimationUtils;
-
-import org.junit.After;
+
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.stubbing.Answer;
import java.util.List;
-import java.util.Optional;
-
-import dagger.Lazy;
-import kotlinx.coroutines.CoroutineDispatcher;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class NotificationPanelViewControllerTest extends SysuiTestCase {
-
- private static final int SPLIT_SHADE_FULL_TRANSITION_DISTANCE = 400;
- private static final int NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE = 50;
- private static final int PANEL_WIDTH = 500; // Random value just for the test.
-
- @Mock private CentralSurfaces mCentralSurfaces;
- @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
- @Mock private KeyguardBottomAreaView mKeyguardBottomArea;
- @Mock private KeyguardBottomAreaViewController mKeyguardBottomAreaViewController;
- @Mock private KeyguardBottomAreaView mQsFrame;
- @Mock private HeadsUpManagerPhone mHeadsUpManager;
- @Mock private NotificationShelfController mNotificationShelfController;
- @Mock private NotificationGutsManager mGutsManager;
- @Mock private KeyguardStatusBarView mKeyguardStatusBar;
- @Mock private KeyguardUserSwitcherView mUserSwitcherView;
- @Mock private ViewStub mUserSwitcherStubView;
- @Mock private HeadsUpTouchHelper.Callback mHeadsUpCallback;
- @Mock private KeyguardUpdateMonitor mUpdateMonitor;
- @Mock private KeyguardBypassController mKeyguardBypassController;
- @Mock private DozeParameters mDozeParameters;
- @Mock private ScreenOffAnimationController mScreenOffAnimationController;
- @Mock private NotificationPanelView mView;
- @Mock private LayoutInflater mLayoutInflater;
- @Mock private FeatureFlags mFeatureFlags;
- @Mock private DynamicPrivacyController mDynamicPrivacyController;
- @Mock private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
- @Mock private KeyguardStateController mKeyguardStateController;
- @Mock private DozeLog mDozeLog;
- @Mock private ShadeLogger mShadeLog;
- @Mock private ShadeHeightLogger mShadeHeightLogger;
- @Mock private CommandQueue mCommandQueue;
- @Mock private VibratorHelper mVibratorHelper;
- @Mock private LatencyTracker mLatencyTracker;
- @Mock private PowerManager mPowerManager;
- @Mock private AccessibilityManager mAccessibilityManager;
- @Mock private MetricsLogger mMetricsLogger;
- @Mock private Resources mResources;
- @Mock private Configuration mConfiguration;
- @Mock private KeyguardClockSwitch mKeyguardClockSwitch;
- @Mock private MediaHierarchyManager mMediaHierarchyManager;
- @Mock private ConversationNotificationManager mConversationNotificationManager;
- @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- @Mock private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
- @Mock private KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory;
- @Mock private KeyguardQsUserSwitchComponent mKeyguardQsUserSwitchComponent;
- @Mock private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
- @Mock private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
- @Mock private KeyguardUserSwitcherComponent mKeyguardUserSwitcherComponent;
- @Mock private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
- @Mock private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
- @Mock private KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
- @Mock private KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent;
- @Mock private KeyguardClockSwitchController mKeyguardClockSwitchController;
- @Mock private KeyguardStatusViewController mKeyguardStatusViewController;
- @Mock private KeyguardStatusBarViewController mKeyguardStatusBarViewController;
- @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
- @Mock private NotificationShadeDepthController mNotificationShadeDepthController;
- @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
- @Mock private AuthController mAuthController;
- @Mock private ScrimController mScrimController;
- @Mock private MediaDataManager mMediaDataManager;
- @Mock private AmbientState mAmbientState;
- @Mock private UserManager mUserManager;
- @Mock private UiEventLogger mUiEventLogger;
- @Mock private LockIconViewController mLockIconViewController;
- @Mock private KeyguardMediaController mKeyguardMediaController;
- @Mock private NavigationModeController mNavigationModeController;
- @Mock private NavigationBarController mNavigationBarController;
- @Mock private QuickSettingsController mQsController;
- @Mock private ShadeHeaderController mShadeHeaderController;
- @Mock private ContentResolver mContentResolver;
- @Mock private TapAgainViewController mTapAgainViewController;
- @Mock private KeyguardIndicationController mKeyguardIndicationController;
- @Mock private FragmentService mFragmentService;
- @Mock private FragmentHostManager mFragmentHostManager;
- @Mock private NotificationRemoteInputManager mNotificationRemoteInputManager;
- @Mock private RecordingController mRecordingController;
- @Mock private LockscreenGestureLogger mLockscreenGestureLogger;
- @Mock private DumpManager mDumpManager;
- @Mock private InteractionJankMonitor mInteractionJankMonitor;
- @Mock private NotificationsQSContainerController mNotificationsQSContainerController;
- @Mock private QsFrameTranslateController mQsFrameTranslateController;
- @Mock private StatusBarWindowStateController mStatusBarWindowStateController;
- @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
- @Mock private NotificationShadeWindowController mNotificationShadeWindowController;
- @Mock private SysUiState mSysUiState;
- @Mock private NotificationListContainer mNotificationListContainer;
- @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
- @Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
- @Mock private ShadeTransitionController mShadeTransitionController;
- @Mock private QS mQs;
- @Mock private QSFragment mQSFragment;
- @Mock private ViewGroup mQsHeader;
- @Mock private ViewParent mViewParent;
- @Mock private ViewTreeObserver mViewTreeObserver;
- @Mock private KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
- @Mock private KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
- @Mock private DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel;
- @Mock private OccludedToLockscreenTransitionViewModel mOccludedToLockscreenTransitionViewModel;
- @Mock private LockscreenToDreamingTransitionViewModel mLockscreenToDreamingTransitionViewModel;
- @Mock private LockscreenToOccludedTransitionViewModel mLockscreenToOccludedTransitionViewModel;
- @Mock private GoneToDreamingTransitionViewModel mGoneToDreamingTransitionViewModel;
-
- @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
- @Mock private KeyguardInteractor mKeyguardInteractor;
- @Mock private KeyguardLongPressViewModel mKeyuardLongPressViewModel;
- @Mock private CoroutineDispatcher mMainDispatcher;
- @Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
- @Mock private MotionEvent mDownMotionEvent;
- @Captor
- private ArgumentCaptor<NotificationStackScrollLayout.OnEmptySpaceClickListener>
- mEmptySpaceClickListenerCaptor;
-
- private NotificationPanelViewController.TouchHandler mTouchHandler;
- private ConfigurationController mConfigurationController;
- private SysuiStatusBarStateController mStatusBarStateController;
- private NotificationPanelViewController mNotificationPanelViewController;
- private View.AccessibilityDelegate mAccessibilityDelegate;
- private NotificationsQuickSettingsContainer mNotificationContainerParent;
- private List<View.OnAttachStateChangeListener> mOnAttachStateChangeListeners;
- private Handler mMainHandler;
- private View.OnLayoutChangeListener mLayoutChangeListener;
-
- private final FalsingManagerFake mFalsingManager = new FalsingManagerFake();
- private final Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
- private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
- private final ShadeExpansionStateManager mShadeExpansionStateManager =
- new ShadeExpansionStateManager();
-
- private QuickSettingsController mQuickSettingsController;
- @Mock private Lazy<NotificationPanelViewController> mNotificationPanelViewControllerLazy;
-
- private FragmentHostManager.FragmentListener mFragmentListener;
+public class NotificationPanelViewControllerTest extends NotificationPanelViewControllerBaseTest {
@Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- SystemClock systemClock = new FakeSystemClock();
- mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager,
- mInteractionJankMonitor, mShadeExpansionStateManager);
-
- KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
- keyguardStatusView.setId(R.id.keyguard_status_view);
+ public void before() {
DejankUtils.setImmediate(true);
-
- when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
- when(mHeadsUpCallback.getContext()).thenReturn(mContext);
- when(mView.getResources()).thenReturn(mResources);
- when(mView.getWidth()).thenReturn(PANEL_WIDTH);
- when(mResources.getConfiguration()).thenReturn(mConfiguration);
- mConfiguration.orientation = ORIENTATION_PORTRAIT;
- when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
- mDisplayMetrics.density = 100;
- when(mResources.getBoolean(R.bool.config_enableNotificationShadeDrag)).thenReturn(true);
- when(mResources.getDimensionPixelSize(R.dimen.notifications_top_padding_split_shade))
- .thenReturn(NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE);
- when(mResources.getDimensionPixelSize(R.dimen.notification_panel_margin_horizontal))
- .thenReturn(10);
- when(mResources.getDimensionPixelSize(R.dimen.split_shade_full_transition_distance))
- .thenReturn(SPLIT_SHADE_FULL_TRANSITION_DISTANCE);
- when(mView.getContext()).thenReturn(getContext());
- when(mView.findViewById(R.id.keyguard_header)).thenReturn(mKeyguardStatusBar);
- when(mView.findViewById(R.id.keyguard_user_switcher_view)).thenReturn(mUserSwitcherView);
- when(mView.findViewById(R.id.keyguard_user_switcher_stub)).thenReturn(
- mUserSwitcherStubView);
- when(mView.findViewById(R.id.keyguard_clock_container)).thenReturn(mKeyguardClockSwitch);
- when(mView.findViewById(R.id.notification_stack_scroller))
- .thenReturn(mNotificationStackScrollLayout);
- when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(1000);
- when(mNotificationStackScrollLayoutController.getHeadsUpCallback())
- .thenReturn(mHeadsUpCallback);
- when(mKeyguardBottomAreaViewController.getView()).thenReturn(mKeyguardBottomArea);
- when(mView.findViewById(R.id.keyguard_bottom_area)).thenReturn(mKeyguardBottomArea);
- when(mKeyguardBottomArea.animate()).thenReturn(mock(ViewPropertyAnimator.class));
- when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame);
- when(mView.findViewById(R.id.keyguard_status_view))
- .thenReturn(mock(KeyguardStatusView.class));
- mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
- mNotificationContainerParent.addView(keyguardStatusView);
- mNotificationContainerParent.onFinishInflate();
- when(mView.findViewById(R.id.notification_container_parent))
- .thenReturn(mNotificationContainerParent);
- when(mFragmentService.getFragmentHostManager(mView)).thenReturn(mFragmentHostManager);
- FlingAnimationUtils.Builder flingAnimationUtilsBuilder = new FlingAnimationUtils.Builder(
- mDisplayMetrics);
- when(mKeyguardQsUserSwitchComponentFactory.build(any()))
- .thenReturn(mKeyguardQsUserSwitchComponent);
- when(mKeyguardQsUserSwitchComponent.getKeyguardQsUserSwitchController())
- .thenReturn(mKeyguardQsUserSwitchController);
- when(mKeyguardUserSwitcherComponentFactory.build(any()))
- .thenReturn(mKeyguardUserSwitcherComponent);
- when(mKeyguardUserSwitcherComponent.getKeyguardUserSwitcherController())
- .thenReturn(mKeyguardUserSwitcherController);
- when(mScreenOffAnimationController.shouldAnimateClockChange()).thenReturn(true);
- when(mQs.getView()).thenReturn(mView);
- when(mQSFragment.getView()).thenReturn(mView);
- doAnswer(invocation -> {
- mFragmentListener = invocation.getArgument(1);
- return null;
- }).when(mFragmentHostManager).addTagListener(eq(QS.TAG), any());
- doAnswer((Answer<Void>) invocation -> {
- mTouchHandler = invocation.getArgument(0);
- return null;
- }).when(mView).setOnTouchListener(any(NotificationPanelViewController.TouchHandler.class));
-
- NotificationWakeUpCoordinator coordinator =
- new NotificationWakeUpCoordinator(
- mDumpManager,
- mock(HeadsUpManagerPhone.class),
- new StatusBarStateControllerImpl(new UiEventLoggerFake(), mDumpManager,
- mInteractionJankMonitor, mShadeExpansionStateManager),
- mKeyguardBypassController,
- mDozeParameters,
- mScreenOffAnimationController,
- mock(NotificationWakeUpCoordinatorLogger.class));
- mConfigurationController = new ConfigurationControllerImpl(mContext);
- PulseExpansionHandler expansionHandler = new PulseExpansionHandler(
- mContext,
- coordinator,
- mKeyguardBypassController, mHeadsUpManager,
- mock(NotificationRoundnessManager.class),
- mConfigurationController,
- mStatusBarStateController,
- mFalsingManager,
- mShadeExpansionStateManager,
- mLockscreenShadeTransitionController,
- new FalsingCollectorFake(),
- mDumpManager);
- when(mKeyguardStatusViewComponentFactory.build(any()))
- .thenReturn(mKeyguardStatusViewComponent);
- when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
- .thenReturn(mKeyguardClockSwitchController);
- when(mKeyguardStatusViewComponent.getKeyguardStatusViewController())
- .thenReturn(mKeyguardStatusViewController);
- when(mKeyguardStatusBarViewComponentFactory.build(any(), any()))
- .thenReturn(mKeyguardStatusBarViewComponent);
- when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
- .thenReturn(mKeyguardStatusBarViewController);
- when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean()))
- .thenReturn(keyguardStatusView);
- when(mLayoutInflater.inflate(eq(R.layout.keyguard_user_switcher), any(), anyBoolean()))
- .thenReturn(mUserSwitcherView);
- when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean()))
- .thenReturn(mKeyguardBottomArea);
- when(mNotificationRemoteInputManager.isRemoteInputActive())
- .thenReturn(false);
- when(mInteractionJankMonitor.begin(any(), anyInt()))
- .thenReturn(true);
- when(mInteractionJankMonitor.end(anyInt()))
- .thenReturn(true);
- doAnswer(invocation -> {
- ((Runnable) invocation.getArgument(0)).run();
- return null;
- }).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
- doAnswer(invocation -> {
- mLayoutChangeListener = invocation.getArgument(0);
- return null;
- }).when(mView).addOnLayoutChangeListener(any());
-
- when(mView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
- when(mView.getParent()).thenReturn(mViewParent);
- when(mQs.getHeader()).thenReturn(mQsHeader);
- when(mDownMotionEvent.getAction()).thenReturn(MotionEvent.ACTION_DOWN);
- when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState);
-
- mMainHandler = new Handler(Looper.getMainLooper());
-
- when(mView.requireViewById(R.id.keyguard_long_press))
- .thenReturn(mock(LongPressHandlingView.class));
-
- mNotificationPanelViewController = new NotificationPanelViewController(
- mView,
- mMainHandler,
- mLayoutInflater,
- mFeatureFlags,
- coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
- mFalsingManager, new FalsingCollectorFake(),
- mKeyguardStateController,
- mStatusBarStateController,
- mStatusBarWindowStateController,
- mNotificationShadeWindowController,
- mDozeLog, mDozeParameters, mCommandQueue, mVibratorHelper,
- mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
- mMetricsLogger,
- mShadeLog,
- mShadeHeightLogger,
- mConfigurationController,
- () -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
- mConversationNotificationManager, mMediaHierarchyManager,
- mStatusBarKeyguardViewManager,
- mGutsManager,
- mNotificationsQSContainerController,
- mNotificationStackScrollLayoutController,
- mKeyguardStatusViewComponentFactory,
- mKeyguardQsUserSwitchComponentFactory,
- mKeyguardUserSwitcherComponentFactory,
- mKeyguardStatusBarViewComponentFactory,
- mLockscreenShadeTransitionController,
- mAuthController,
- mScrimController,
- mUserManager,
- mMediaDataManager,
- mNotificationShadeDepthController,
- mAmbientState,
- mLockIconViewController,
- mKeyguardMediaController,
- mTapAgainViewController,
- mNavigationModeController,
- mNavigationBarController,
- mQsController,
- mFragmentService,
- mContentResolver,
- mRecordingController,
- mShadeHeaderController,
- mScreenOffAnimationController,
- mLockscreenGestureLogger,
- mShadeExpansionStateManager,
- mNotificationRemoteInputManager,
- mSysUIUnfoldComponent,
- mSysUiState,
- () -> mKeyguardBottomAreaViewController,
- mKeyguardUnlockAnimationController,
- mKeyguardIndicationController,
- mNotificationListContainer,
- mNotificationStackSizeCalculator,
- mUnlockedScreenOffAnimationController,
- mShadeTransitionController,
- systemClock,
- mKeyguardBottomAreaViewModel,
- mKeyguardBottomAreaInteractor,
- mAlternateBouncerInteractor,
- mDreamingToLockscreenTransitionViewModel,
- mOccludedToLockscreenTransitionViewModel,
- mLockscreenToDreamingTransitionViewModel,
- mGoneToDreamingTransitionViewModel,
- mLockscreenToOccludedTransitionViewModel,
- mMainDispatcher,
- mKeyguardTransitionInteractor,
- mDumpManager,
- mKeyuardLongPressViewModel,
- mKeyguardInteractor);
- mNotificationPanelViewController.initDependencies(
- mCentralSurfaces,
- null,
- () -> {},
- mNotificationShelfController);
- mNotificationPanelViewController.setTrackingStartedListener(() -> {});
- mNotificationPanelViewController.setOpenCloseListener(
- new NotificationPanelViewController.OpenCloseListener() {
- @Override
- public void onClosingFinished() {}
-
- @Override
- public void onOpenStarted() {}
- });
- mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
- ArgumentCaptor<View.OnAttachStateChangeListener> onAttachStateChangeListenerArgumentCaptor =
- ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
- verify(mView, atLeast(1)).addOnAttachStateChangeListener(
- onAttachStateChangeListenerArgumentCaptor.capture());
- mOnAttachStateChangeListeners = onAttachStateChangeListenerArgumentCaptor.getAllValues();
-
- ArgumentCaptor<View.AccessibilityDelegate> accessibilityDelegateArgumentCaptor =
- ArgumentCaptor.forClass(View.AccessibilityDelegate.class);
- verify(mView).setAccessibilityDelegate(accessibilityDelegateArgumentCaptor.capture());
- mAccessibilityDelegate = accessibilityDelegateArgumentCaptor.getValue();
- mNotificationPanelViewController.getStatusBarStateController()
- .addCallback(mNotificationPanelViewController.getStatusBarStateListener());
- mNotificationPanelViewController
- .setHeadsUpAppearanceController(mock(HeadsUpAppearanceController.class));
- verify(mNotificationStackScrollLayoutController)
- .setOnEmptySpaceClickListener(mEmptySpaceClickListenerCaptor.capture());
- verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ true);
- reset(mKeyguardStatusViewController);
-
- when(mNotificationPanelViewControllerLazy.get())
- .thenReturn(mNotificationPanelViewController);
- mQuickSettingsController = new QuickSettingsController(
- mNotificationPanelViewControllerLazy,
- mView,
- mQsFrameTranslateController,
- mShadeTransitionController,
- expansionHandler,
- mNotificationRemoteInputManager,
- mShadeExpansionStateManager,
- mStatusBarKeyguardViewManager,
- mNotificationStackScrollLayoutController,
- mLockscreenShadeTransitionController,
- mNotificationShadeDepthController,
- mShadeHeaderController,
- mStatusBarTouchableRegionManager,
- mKeyguardStateController,
- mKeyguardBypassController,
- mUpdateMonitor,
- mScrimController,
- mMediaDataManager,
- mMediaHierarchyManager,
- mAmbientState,
- mRecordingController,
- mFalsingManager,
- new FalsingCollectorFake(),
- mAccessibilityManager,
- mLockscreenGestureLogger,
- mMetricsLogger,
- mFeatureFlags,
- mInteractionJankMonitor,
- mShadeLog
- );
- }
-
- @After
- public void tearDown() {
- mNotificationPanelViewController.cancelHeightAnimator();
- mMainHandler.removeCallbacksAndMessages(null);
}
@Test
@@ -671,23 +130,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
.isNotEqualTo(-1);
}
- private void setBottomPadding(int stackBottom, int lockIconPadding, int indicationPadding,
- int ambientPadding) {
-
- when(mNotificationStackScrollLayoutController.getTop()).thenReturn(0);
- when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(stackBottom);
- when(mNotificationStackScrollLayoutController.getBottom()).thenReturn(stackBottom);
- when(mLockIconViewController.getTop()).thenReturn((float) (stackBottom - lockIconPadding));
-
- when(mResources.getDimensionPixelSize(R.dimen.keyguard_indication_bottom_padding))
- .thenReturn(indicationPadding);
- mNotificationPanelViewController.loadDimens();
-
- mNotificationPanelViewController.setAmbientIndicationTop(
- /* ambientIndicationTop= */ stackBottom - ambientPadding,
- /* ambientTextVisible= */ true);
- }
-
@Test
@Ignore("b/261472011 - Test appears inconsistent across environments")
public void getVerticalSpaceForLockscreenNotifications_useLockIconBottomPadding_returnsSpaceAvailable() {
@@ -992,68 +434,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
}
@Test
- public void testDisableUserSwitcherAfterEnabling_returnsViewStubToTheViewHierarchy() {
- givenViewAttached();
- when(mResources.getBoolean(
- com.android.internal.R.bool.config_keyguardUserSwitcher)).thenReturn(true);
- updateMultiUserSetting(true);
- clearInvocations(mView);
-
- updateMultiUserSetting(false);
-
- ArgumentCaptor<View> captor = ArgumentCaptor.forClass(View.class);
- verify(mView, atLeastOnce()).addView(captor.capture(), anyInt());
- final View userSwitcherStub = CollectionUtils.find(captor.getAllValues(),
- view -> view.getId() == R.id.keyguard_user_switcher_stub);
- assertThat(userSwitcherStub).isNotNull();
- assertThat(userSwitcherStub).isInstanceOf(ViewStub.class);
- }
-
- @Test
- public void testChangeSmallestScreenWidthAndUserSwitchEnabled_inflatesUserSwitchView() {
- givenViewAttached();
- when(mView.findViewById(R.id.keyguard_user_switcher_view)).thenReturn(null);
- updateSmallestScreenWidth(300);
- when(mResources.getBoolean(
- com.android.internal.R.bool.config_keyguardUserSwitcher)).thenReturn(true);
- when(mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user)).thenReturn(false);
- when(mUserManager.isUserSwitcherEnabled(false)).thenReturn(true);
-
- updateSmallestScreenWidth(800);
-
- verify(mUserSwitcherStubView).inflate();
- }
-
- @Test
- public void testFinishInflate_userSwitcherDisabled_doNotInflateUserSwitchView_initClock() {
- givenViewAttached();
- when(mResources.getBoolean(
- com.android.internal.R.bool.config_keyguardUserSwitcher)).thenReturn(true);
- when(mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user)).thenReturn(false);
- when(mUserManager.isUserSwitcherEnabled(false /* showEvenIfNotActionable */))
- .thenReturn(false);
-
- mNotificationPanelViewController.onFinishInflate();
-
- verify(mUserSwitcherStubView, never()).inflate();
- verify(mKeyguardStatusViewController, times(3)).displayClock(LARGE, /* animate */ true);
- }
-
- @Test
- public void testReInflateViews_userSwitcherDisabled_doNotInflateUserSwitchView() {
- givenViewAttached();
- when(mResources.getBoolean(
- com.android.internal.R.bool.config_keyguardUserSwitcher)).thenReturn(true);
- when(mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user)).thenReturn(false);
- when(mUserManager.isUserSwitcherEnabled(false /* showEvenIfNotActionable */))
- .thenReturn(false);
-
- mNotificationPanelViewController.reInflateViews();
-
- verify(mUserSwitcherStubView, never()).inflate();
- }
-
- @Test
public void testCanCollapsePanelOnTouch_trueForKeyGuard() {
mStatusBarStateController.setState(KEYGUARD);
@@ -1129,26 +509,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
}
@Test
- public void testDoubleTapRequired_Keyguard() {
- FalsingManager.FalsingTapListener listener = getFalsingTapListener();
- mStatusBarStateController.setState(KEYGUARD);
-
- listener.onAdditionalTapRequired();
-
- verify(mKeyguardIndicationController).showTransientIndication(anyInt());
- }
-
- @Test
- public void testDoubleTapRequired_ShadeLocked() {
- FalsingManager.FalsingTapListener listener = getFalsingTapListener();
- mStatusBarStateController.setState(SHADE_LOCKED);
-
- listener.onAdditionalTapRequired();
-
- verify(mTapAgainViewController).show();
- }
-
- @Test
public void testRotatingToSplitShadeWithQsExpanded_transitionsToShadeLocked() {
mStatusBarStateController.setState(KEYGUARD);
when(mQsController.getExpanded()).thenReturn(true);
@@ -1423,19 +783,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
}
@Test
- public void testOnAttachRefreshStatusBarState() {
- mStatusBarStateController.setState(KEYGUARD);
- when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(false);
- for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
- listener.onViewAttachedToWindow(mView);
- }
- verify(mKeyguardStatusViewController).setKeyguardStatusViewVisibility(
- KEYGUARD/*statusBarState*/,
- false/*keyguardFadingAway*/,
- false/*goingToFullShade*/, SHADE/*oldStatusBarState*/);
- }
-
- @Test
public void getMaxPanelTransitionDistance_expanding_inSplitShade_returnsSplitShadeFullTransitionDistance() {
enableSplitShade(true);
mNotificationPanelViewController.expandWithQs();
@@ -1635,98 +982,4 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mStatusBarStateController.setState(SHADE_LOCKED);
assertThat(mNotificationPanelViewController.isShadeFullyOpen()).isTrue();
}
-
- private static MotionEvent createMotionEvent(int x, int y, int action) {
- return MotionEvent.obtain(
- /* downTime= */ 0, /* eventTime= */ 0, action, x, y, /* metaState= */ 0);
- }
-
- private void triggerPositionClockAndNotifications() {
- mNotificationPanelViewController.onQsSetExpansionHeightCalled(false);
- }
-
- private FalsingManager.FalsingTapListener getFalsingTapListener() {
- for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
- listener.onViewAttachedToWindow(mView);
- }
- assertThat(mFalsingManager.getTapListeners().size()).isEqualTo(1);
- return mFalsingManager.getTapListeners().get(0);
- }
-
- private void givenViewAttached() {
- for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
- listener.onViewAttachedToWindow(mView);
- }
- }
-
- private ConstraintSet.Layout getConstraintSetLayout(@IdRes int id) {
- ConstraintSet constraintSet = new ConstraintSet();
- constraintSet.clone(mNotificationContainerParent);
- return constraintSet.getConstraint(id).layout;
- }
-
- private void enableSplitShade(boolean enabled) {
- when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(enabled);
- mNotificationPanelViewController.updateResources();
- }
-
- private void updateMultiUserSetting(boolean enabled) {
- when(mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user)).thenReturn(false);
- when(mUserManager.isUserSwitcherEnabled(false)).thenReturn(enabled);
- final ArgumentCaptor<ContentObserver> observerCaptor =
- ArgumentCaptor.forClass(ContentObserver.class);
- verify(mContentResolver)
- .registerContentObserver(any(), anyBoolean(), observerCaptor.capture());
- observerCaptor.getValue().onChange(/* selfChange */ false);
- }
-
- private void updateSmallestScreenWidth(int smallestScreenWidthDp) {
- Configuration configuration = new Configuration();
- configuration.smallestScreenWidthDp = smallestScreenWidthDp;
- mConfigurationController.onConfigurationChanged(configuration);
- }
-
- private void onTouchEvent(MotionEvent ev) {
- mTouchHandler.onTouch(mView, ev);
- }
-
- private void setDozing(boolean dozing, boolean dozingAlwaysOn) {
- when(mDozeParameters.getAlwaysOn()).thenReturn(dozingAlwaysOn);
- mNotificationPanelViewController.setDozing(
- /* dozing= */ dozing,
- /* animate= */ false
- );
- }
-
- private void assertKeyguardStatusViewCentered() {
- mNotificationPanelViewController.updateResources();
- assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd).isAnyOf(
- ConstraintSet.PARENT_ID, ConstraintSet.UNSET);
- }
-
- private void assertKeyguardStatusViewNotCentered() {
- mNotificationPanelViewController.updateResources();
- assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd).isEqualTo(
- R.id.qs_edge_guideline);
- }
-
- private void setIsFullWidth(boolean fullWidth) {
- float nsslWidth = fullWidth ? PANEL_WIDTH : PANEL_WIDTH / 2f;
- when(mNotificationStackScrollLayoutController.getWidth()).thenReturn(nsslWidth);
- triggerLayoutChange();
- }
-
- private void triggerLayoutChange() {
- mLayoutChangeListener.onLayoutChange(
- mView,
- /* left= */ 0,
- /* top= */ 0,
- /* right= */ 0,
- /* bottom= */ 0,
- /* oldLeft= */ 0,
- /* oldTop= */ 0,
- /* oldRight= */ 0,
- /* oldBottom= */ 0
- );
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
new file mode 100644
index 000000000000..0c046e93ee20
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
@@ -0,0 +1,179 @@
+/*
+ * 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.shade
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import android.view.ViewStub
+import androidx.test.filters.SmallTest
+import com.android.internal.util.CollectionUtils
+import com.android.keyguard.KeyguardClockSwitch.LARGE
+import com.android.systemui.R
+import com.android.systemui.statusbar.StatusBarState.KEYGUARD
+import com.android.systemui.statusbar.StatusBarState.SHADE
+import com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.cancelChildren
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.advanceUntilIdle
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Captor
+import org.mockito.Mockito.atLeastOnce
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class NotificationPanelViewControllerWithCoroutinesTest :
+ NotificationPanelViewControllerBaseTest() {
+
+ @Captor private lateinit var viewCaptor: ArgumentCaptor<View>
+
+ override fun getMainDispatcher() = Dispatchers.Main.immediate
+
+ @Test
+ fun testDisableUserSwitcherAfterEnabling_returnsViewStubToTheViewHierarchy() = runTest {
+ launch(Dispatchers.Main.immediate) { givenViewAttached() }
+ advanceUntilIdle()
+
+ whenever(mResources.getBoolean(com.android.internal.R.bool.config_keyguardUserSwitcher))
+ .thenReturn(true)
+ updateMultiUserSetting(true)
+ clearInvocations(mView)
+
+ updateMultiUserSetting(false)
+
+ verify(mView, atLeastOnce()).addView(viewCaptor.capture(), anyInt())
+ val userSwitcherStub =
+ CollectionUtils.find(
+ viewCaptor.getAllValues(),
+ { view -> view.getId() == R.id.keyguard_user_switcher_stub }
+ )
+ assertThat(userSwitcherStub).isNotNull()
+ assertThat(userSwitcherStub).isInstanceOf(ViewStub::class.java)
+ }
+
+ @Test
+ fun testChangeSmallestScreenWidthAndUserSwitchEnabled_inflatesUserSwitchView() = runTest {
+ launch(Dispatchers.Main.immediate) { givenViewAttached() }
+ advanceUntilIdle()
+
+ whenever(mView.findViewById<View>(R.id.keyguard_user_switcher_view)).thenReturn(null)
+ updateSmallestScreenWidth(300)
+ whenever(mResources.getBoolean(com.android.internal.R.bool.config_keyguardUserSwitcher))
+ .thenReturn(true)
+ whenever(mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user))
+ .thenReturn(false)
+ whenever(mUserManager.isUserSwitcherEnabled(false)).thenReturn(true)
+
+ updateSmallestScreenWidth(800)
+
+ verify(mUserSwitcherStubView).inflate()
+ }
+
+ @Test
+ fun testFinishInflate_userSwitcherDisabled_doNotInflateUserSwitchView_initClock() = runTest {
+ launch(Dispatchers.Main.immediate) { givenViewAttached() }
+ advanceUntilIdle()
+
+ whenever(mResources.getBoolean(com.android.internal.R.bool.config_keyguardUserSwitcher))
+ .thenReturn(true)
+ whenever(mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user))
+ .thenReturn(false)
+ whenever(mUserManager.isUserSwitcherEnabled(false /* showEvenIfNotActionable */))
+ .thenReturn(false)
+
+ mNotificationPanelViewController.onFinishInflate()
+
+ verify(mUserSwitcherStubView, never()).inflate()
+ verify(mKeyguardStatusViewController, times(3)).displayClock(LARGE, /* animate */ true)
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun testReInflateViews_userSwitcherDisabled_doNotInflateUserSwitchView() = runTest {
+ launch(Dispatchers.Main.immediate) { givenViewAttached() }
+ advanceUntilIdle()
+
+ whenever(mResources.getBoolean(com.android.internal.R.bool.config_keyguardUserSwitcher))
+ .thenReturn(true)
+ whenever(mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user))
+ .thenReturn(false)
+ whenever(mUserManager.isUserSwitcherEnabled(false /* showEvenIfNotActionable */))
+ .thenReturn(false)
+
+ mNotificationPanelViewController.reInflateViews()
+
+ verify(mUserSwitcherStubView, never()).inflate()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun testDoubleTapRequired_Keyguard() = runTest {
+ launch(Dispatchers.Main.immediate) {
+ val listener = getFalsingTapListener()
+ mStatusBarStateController.setState(KEYGUARD)
+
+ listener.onAdditionalTapRequired()
+
+ verify(mKeyguardIndicationController).showTransientIndication(anyInt())
+ }
+ advanceUntilIdle()
+ }
+
+ @Test
+ fun testDoubleTapRequired_ShadeLocked() = runTest {
+ launch(Dispatchers.Main.immediate) {
+ val listener = getFalsingTapListener()
+ mStatusBarStateController.setState(SHADE_LOCKED)
+
+ listener.onAdditionalTapRequired()
+
+ verify(mTapAgainViewController).show()
+ }
+ advanceUntilIdle()
+ }
+
+ @Test
+ fun testOnAttachRefreshStatusBarState() = runTest {
+ launch(Dispatchers.Main.immediate) {
+ mStatusBarStateController.setState(KEYGUARD)
+ whenever(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(false)
+ mOnAttachStateChangeListeners.forEach { it.onViewAttachedToWindow(mView) }
+ verify(mKeyguardStatusViewController)
+ .setKeyguardStatusViewVisibility(
+ KEYGUARD /*statusBarState*/,
+ false /*keyguardFadingAway*/,
+ false /*goingToFullShade*/,
+ SHADE /*oldStatusBarState*/
+ )
+ }
+ advanceUntilIdle()
+ }
+}
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 d229a08ad7c4..82a57438052f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -28,11 +28,12 @@ import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.dock.DockManager
-import com.android.systemui.flags.FeatureFlags
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationInsetsController
@@ -47,6 +48,7 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.window.StatusBarWindowStateController
import com.android.systemui.util.mockito.any
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.emptyFlow
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -64,50 +66,32 @@ import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@RunWithLooper(setAsMainLooper = true)
class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
- @Mock
- private lateinit var view: NotificationShadeWindowView
- @Mock
- private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
- @Mock
- private lateinit var centralSurfaces: CentralSurfaces
- @Mock
- private lateinit var dockManager: DockManager
- @Mock
- private lateinit var notificationPanelViewController: NotificationPanelViewController
- @Mock
- private lateinit var notificationShadeDepthController: NotificationShadeDepthController
- @Mock
- private lateinit var notificationShadeWindowController: NotificationShadeWindowController
- @Mock
- private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
- @Mock
- private lateinit var featureFlags: FeatureFlags
- @Mock
- private lateinit var ambientState: AmbientState
- @Mock
- private lateinit var keyguardBouncerViewModel: KeyguardBouncerViewModel
- @Mock
- private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController
- @Mock
- private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
- @Mock
- private lateinit var statusBarWindowStateController: StatusBarWindowStateController
+ @Mock private lateinit var view: NotificationShadeWindowView
+ @Mock private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
+ @Mock private lateinit var centralSurfaces: CentralSurfaces
+ @Mock private lateinit var dockManager: DockManager
+ @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController
+ @Mock private lateinit var notificationShadeDepthController: NotificationShadeDepthController
+ @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
+ @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
+ @Mock private lateinit var ambientState: AmbientState
+ @Mock private lateinit var keyguardBouncerViewModel: KeyguardBouncerViewModel
+ @Mock private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController
+ @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
+ @Mock private lateinit var statusBarWindowStateController: StatusBarWindowStateController
@Mock
private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
- @Mock
- private lateinit var lockIconViewController: LockIconViewController
- @Mock
- private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController
- @Mock
- private lateinit var pulsingGestureListener: PulsingGestureListener
- @Mock
- private lateinit var notificationInsetsController: NotificationInsetsController
- @Mock
- private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+ @Mock private lateinit var lockIconViewController: LockIconViewController
+ @Mock private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController
+ @Mock private lateinit var pulsingGestureListener: PulsingGestureListener
+ @Mock private lateinit var notificationInsetsController: NotificationInsetsController
+ @Mock private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
@Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
+ @Mock
+ lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel
private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
private lateinit var interactionEventHandler: InteractionEventHandler
@@ -119,42 +103,44 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
whenever(view.bottom).thenReturn(VIEW_BOTTOM)
whenever(view.findViewById<ViewGroup>(R.id.keyguard_bouncer_container))
- .thenReturn(mock(ViewGroup::class.java))
+ .thenReturn(mock(ViewGroup::class.java))
whenever(keyguardBouncerComponentFactory.create(any(ViewGroup::class.java)))
- .thenReturn(keyguardBouncerComponent)
+ .thenReturn(keyguardBouncerComponent)
whenever(keyguardBouncerComponent.securityContainerController)
- .thenReturn(keyguardSecurityContainerController)
- underTest = NotificationShadeWindowViewController(
- lockscreenShadeTransitionController,
- FalsingCollectorFake(),
- sysuiStatusBarStateController,
- dockManager,
- notificationShadeDepthController,
- view,
- notificationPanelViewController,
- ShadeExpansionStateManager(),
- stackScrollLayoutController,
- statusBarKeyguardViewManager,
- statusBarWindowStateController,
- lockIconViewController,
- centralSurfaces,
- notificationShadeWindowController,
- keyguardUnlockAnimationController,
- notificationInsetsController,
- ambientState,
- pulsingGestureListener,
- featureFlags,
- keyguardBouncerViewModel,
- keyguardBouncerComponentFactory,
- alternateBouncerInteractor,
- keyguardTransitionInteractor,
- )
+ .thenReturn(keyguardSecurityContainerController)
+ whenever(keyguardTransitionInteractor.lockscreenToDreamingTransition)
+ .thenReturn(emptyFlow<TransitionStep>())
+ underTest =
+ NotificationShadeWindowViewController(
+ lockscreenShadeTransitionController,
+ FalsingCollectorFake(),
+ sysuiStatusBarStateController,
+ dockManager,
+ notificationShadeDepthController,
+ view,
+ notificationPanelViewController,
+ ShadeExpansionStateManager(),
+ stackScrollLayoutController,
+ statusBarKeyguardViewManager,
+ statusBarWindowStateController,
+ lockIconViewController,
+ centralSurfaces,
+ notificationShadeWindowController,
+ keyguardUnlockAnimationController,
+ notificationInsetsController,
+ ambientState,
+ pulsingGestureListener,
+ keyguardBouncerViewModel,
+ keyguardBouncerComponentFactory,
+ alternateBouncerInteractor,
+ keyguardTransitionInteractor,
+ primaryBouncerToGoneTransitionViewModel,
+ )
underTest.setupExpandedStatusBar()
- interactionEventHandlerCaptor =
- ArgumentCaptor.forClass(InteractionEventHandler::class.java)
+ interactionEventHandlerCaptor = ArgumentCaptor.forClass(InteractionEventHandler::class.java)
verify(view).setInteractionEventHandler(interactionEventHandlerCaptor.capture())
- interactionEventHandler = interactionEventHandlerCaptor.value
+ interactionEventHandler = interactionEventHandlerCaptor.value
}
// Note: So far, these tests only cover interactions with the status bar view controller. More
@@ -184,14 +170,11 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
@Test
fun handleDispatchTouchEvent_downTouchBelowViewThenAnotherTouch_sendsTouchToSb() {
underTest.setStatusBarViewController(phoneStatusBarViewController)
- val downEvBelow = MotionEvent.obtain(
- 0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0
- )
+ val downEvBelow =
+ MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0)
interactionEventHandler.handleDispatchTouchEvent(downEvBelow)
- val nextEvent = MotionEvent.obtain(
- 0L, 0L, MotionEvent.ACTION_MOVE, 0f, VIEW_BOTTOM + 5f, 0
- )
+ val nextEvent = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, VIEW_BOTTOM + 5f, 0)
whenever(phoneStatusBarViewController.sendTouchToView(nextEvent)).thenReturn(true)
val returnVal = interactionEventHandler.handleDispatchTouchEvent(nextEvent)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
index 5e9c2199897d..faa6221b675c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
@@ -25,6 +25,8 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+
import android.os.SystemClock;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -40,11 +42,11 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.dock.DockManager;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationInsetsController;
@@ -93,7 +95,6 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
@Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock private AmbientState mAmbientState;
@Mock private PulsingGestureListener mPulsingGestureListener;
- @Mock private FeatureFlags mFeatureFlags;
@Mock private KeyguardBouncerViewModel mKeyguardBouncerViewModel;
@Mock private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
@Mock private KeyguardBouncerComponent mKeyguardBouncerComponent;
@@ -101,6 +102,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
@Mock private NotificationInsetsController mNotificationInsetsController;
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
@Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler>
mInteractionEventHandlerCaptor;
@@ -125,6 +127,9 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
when(mDockManager.isDocked()).thenReturn(false);
+ when(mKeyguardTransitionInteractor.getLockscreenToDreamingTransition())
+ .thenReturn(emptyFlow());
+
mController = new NotificationShadeWindowViewController(
mLockscreenShadeTransitionController,
new FalsingCollectorFake(),
@@ -144,11 +149,11 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
mNotificationInsetsController,
mAmbientState,
mPulsingGestureListener,
- mFeatureFlags,
mKeyguardBouncerViewModel,
mKeyguardBouncerComponentFactory,
mAlternateBouncerInteractor,
- mKeyguardTransitionInteractor
+ mKeyguardTransitionInteractor,
+ mPrimaryBouncerToGoneTransitionViewModel
);
mController.setupExpandedStatusBar();
mController.setDragDownHelper(mDragDownHelper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
index 7a74b1229c5c..56fc0c74dafa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
@@ -36,21 +36,26 @@ class UnfoldConstantTranslateAnimatorTest : SysuiTestCase() {
private val progressProvider = TestUnfoldTransitionProvider()
- @Mock private lateinit var parent: ViewGroup
+ @Mock
+ private lateinit var parent: ViewGroup
+
+ @Mock
+ private lateinit var shouldBeAnimated: () -> Boolean
private lateinit var animator: UnfoldConstantTranslateAnimator
- private val viewsIdToRegister =
- setOf(
- ViewIdToTranslate(START_VIEW_ID, Direction.START),
- ViewIdToTranslate(END_VIEW_ID, Direction.END))
+ private val viewsIdToRegister
+ get() =
+ setOf(
+ ViewIdToTranslate(START_VIEW_ID, Direction.START, shouldBeAnimated),
+ ViewIdToTranslate(END_VIEW_ID, Direction.END, shouldBeAnimated)
+ )
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
-
- animator =
- UnfoldConstantTranslateAnimator(viewsIdToRegister, progressProvider)
+ whenever(shouldBeAnimated.invoke()).thenReturn(true)
+ animator = UnfoldConstantTranslateAnimator(viewsIdToRegister, progressProvider)
animator.init(parent, MAX_TRANSLATION)
}
@@ -96,6 +101,20 @@ class UnfoldConstantTranslateAnimatorTest : SysuiTestCase() {
moveAndValidate(listOf(leftView to START, rightView to END), View.LAYOUT_DIRECTION_LTR)
}
+ @Test
+ fun onTransition_completeStartedTranslation() {
+ // GIVEN
+ val leftView = View(context)
+ whenever(parent.findViewById<View>(START_VIEW_ID)).thenReturn(leftView)
+ // To start animation, shouldBeAnimated should return true.
+ // There is a possibility for shouldBeAnimated to return false during the animation.
+ whenever(shouldBeAnimated.invoke()).thenReturn(true).thenReturn(false)
+
+ // shouldBeAnimated state may change during the animation.
+ // However, started animation should be completed.
+ moveAndValidate(listOf(leftView to START), View.LAYOUT_DIRECTION_LTR)
+ }
+
private fun moveAndValidate(list: List<Pair<View, Int>>, layoutDirection: Int) {
// Compare values as ints because -0f != 0f
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 26eff61066ee..1fdb3647fcb2 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
@@ -35,7 +35,6 @@ import junit.framework.Assert.fail
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
-import org.json.JSONException
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -271,10 +270,14 @@ class ClockRegistryTest : SysuiTestCase() {
@Test
fun jsonDeserialization_gotExpectedObject() {
- val expected = ClockSettings("ID", null).apply { _applied_timestamp = 500 }
+ val expected = ClockSettings("ID", null).apply {
+ metadata.put("appliedTimestamp", 500)
+ }
val actual = ClockSettings.deserialize("""{
"clockId":"ID",
- "_applied_timestamp":500
+ "metadata": {
+ "appliedTimestamp":500
+ }
}""")
assertEquals(expected, actual)
}
@@ -291,29 +294,32 @@ class ClockRegistryTest : SysuiTestCase() {
val expected = ClockSettings("ID", null)
val actual = ClockSettings.deserialize("""{
"clockId":"ID",
- "_applied_timestamp":null
+ "metadata":null
}""")
assertEquals(expected, actual)
}
- @Test(expected = JSONException::class)
- fun jsonDeserialization_noId_threwException() {
- val expected = ClockSettings(null, null).apply { _applied_timestamp = 500 }
- val actual = ClockSettings.deserialize("{\"_applied_timestamp\":500}")
+ @Test
+ fun jsonDeserialization_noId_deserializedEmpty() {
+ val expected = ClockSettings(null, null).apply {
+ metadata.put("appliedTimestamp", 500)
+ }
+ val actual = ClockSettings.deserialize("{\"metadata\":{\"appliedTimestamp\":500}}")
assertEquals(expected, actual)
}
@Test
fun jsonSerialization_gotExpectedString() {
- val expected = "{\"clockId\":\"ID\",\"_applied_timestamp\":500}"
- val actual = ClockSettings.serialize(ClockSettings("ID", null)
- .apply { _applied_timestamp = 500 })
+ val expected = "{\"clockId\":\"ID\",\"metadata\":{\"appliedTimestamp\":500}}"
+ val actual = ClockSettings.serialize(ClockSettings("ID", null).apply {
+ metadata.put("appliedTimestamp", 500)
+ })
assertEquals(expected, actual)
}
@Test
fun jsonSerialization_noTimestamp_gotExpectedString() {
- val expected = "{\"clockId\":\"ID\"}"
+ val expected = "{\"clockId\":\"ID\",\"metadata\":{}}"
val actual = ClockSettings.serialize(ClockSettings("ID", null))
assertEquals(expected, actual)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
index cd2efc061b72..7fa27f34cd9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
@@ -26,6 +26,7 @@ import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.ClockSettings
import com.android.systemui.shared.clocks.DefaultClockController.Companion.DOZE_COLOR
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
@@ -40,7 +41,6 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyFloat
-import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.notNull
import org.mockito.Mock
import org.mockito.Mockito.never
@@ -97,13 +97,14 @@ class DefaultClockProviderTest : SysuiTestCase() {
@Test
fun defaultClock_initialize() {
val clock = provider.createClock(DEFAULT_CLOCK_ID)
- verify(mockSmallClockView).setColors(Color.MAGENTA, Color.MAGENTA)
- verify(mockLargeClockView).setColors(Color.MAGENTA, Color.MAGENTA)
+ verify(mockSmallClockView).setColors(DOZE_COLOR, Color.MAGENTA)
+ verify(mockLargeClockView).setColors(DOZE_COLOR, Color.MAGENTA)
clock.initialize(resources, 0f, 0f)
- verify(mockSmallClockView).setColors(eq(DOZE_COLOR), anyInt())
- verify(mockLargeClockView).setColors(eq(DOZE_COLOR), anyInt())
+ val expectedColor = 0
+ verify(mockSmallClockView).setColors(DOZE_COLOR, expectedColor)
+ verify(mockLargeClockView).setColors(DOZE_COLOR, expectedColor)
verify(mockSmallClockView).onTimeZoneChanged(notNull())
verify(mockLargeClockView).onTimeZoneChanged(notNull())
verify(mockSmallClockView).refreshTime()
@@ -159,15 +160,31 @@ class DefaultClockProviderTest : SysuiTestCase() {
@Test
fun defaultClock_events_onColorPaletteChanged() {
+ val expectedColor = 0
val clock = provider.createClock(DEFAULT_CLOCK_ID)
- verify(mockSmallClockView).setColors(Color.MAGENTA, Color.MAGENTA)
- verify(mockLargeClockView).setColors(Color.MAGENTA, Color.MAGENTA)
+ verify(mockSmallClockView).setColors(DOZE_COLOR, Color.MAGENTA)
+ verify(mockLargeClockView).setColors(DOZE_COLOR, Color.MAGENTA)
clock.events.onColorPaletteChanged(resources)
- verify(mockSmallClockView).setColors(eq(DOZE_COLOR), anyInt())
- verify(mockLargeClockView).setColors(eq(DOZE_COLOR), anyInt())
+ verify(mockSmallClockView).setColors(DOZE_COLOR, expectedColor)
+ verify(mockLargeClockView).setColors(DOZE_COLOR, expectedColor)
+ }
+
+ @Test
+ fun defaultClock_events_onSeedColorChanged() {
+ val initSeedColor = 10
+ val newSeedColor = 20
+ val clock = provider.createClock(ClockSettings(DEFAULT_CLOCK_ID, initSeedColor))
+
+ verify(mockSmallClockView).setColors(DOZE_COLOR, initSeedColor)
+ verify(mockLargeClockView).setColors(DOZE_COLOR, initSeedColor)
+
+ clock.events.onSeedColorChanged(newSeedColor)
+
+ verify(mockSmallClockView).setColors(DOZE_COLOR, newSeedColor)
+ verify(mockLargeClockView).setColors(DOZE_COLOR, newSeedColor)
}
@Test
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 d99cdd514f37..ab615f99ebad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -211,16 +211,6 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
}
@Test
- fun testTriggeringBouncerWhenPrivateNotificationsArentAllowed() {
- whenever(lockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt())).thenReturn(
- false)
- transitionController.goToLockedShade(null)
- verify(statusbarStateController, never()).setState(anyInt())
- verify(statusbarStateController).setLeaveOpenOnKeyguardHide(true)
- verify(mCentralSurfaces).showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject())
- }
-
- @Test
fun testTriggeringBouncerNoNotificationsOnLockscreen() {
whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false)
transitionController.goToLockedShade(null)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index 452606dfcca4..8ee1ea8a9916 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -44,6 +44,7 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
+import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -354,7 +355,8 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
mDeviceProvisionedController,
mKeyguardStateController,
mSettings,
- mock(DumpManager.class));
+ mock(DumpManager.class),
+ mock(LockPatternUtils.class));
}
public BroadcastReceiver getBaseBroadcastReceiverForTest() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
new file mode 100644
index 000000000000..7a6779684fc5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
@@ -0,0 +1,111 @@
+/*
+ * 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
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.android.systemui.statusbar.StatusBarState
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class NotificationWakeUpCoordinatorLoggerTest : SysuiTestCase() {
+
+ private val logBufferCounter = LogBufferCounter()
+ private lateinit var logger: NotificationWakeUpCoordinatorLogger
+
+ private fun verifyDidLog(times: Int) {
+ logBufferCounter.verifyDidLog(times)
+ }
+
+ @Before
+ fun setup() {
+ logger = NotificationWakeUpCoordinatorLogger(logBufferCounter.logBuffer)
+ }
+
+ @Test
+ fun setDozeAmountWillThrottleFractionalUpdates() {
+ logger.logSetDozeAmount(0f, 0f, "source1", StatusBarState.SHADE, changed = false)
+ verifyDidLog(1)
+ logger.logSetDozeAmount(0.1f, 0.1f, "source1", StatusBarState.SHADE, changed = true)
+ verifyDidLog(1)
+ logger.logSetDozeAmount(0.2f, 0.2f, "source1", StatusBarState.SHADE, changed = true)
+ logger.logSetDozeAmount(0.3f, 0.3f, "source1", StatusBarState.SHADE, changed = true)
+ logger.logSetDozeAmount(0.4f, 0.4f, "source1", StatusBarState.SHADE, changed = true)
+ logger.logSetDozeAmount(0.5f, 0.5f, "source1", StatusBarState.SHADE, changed = true)
+ verifyDidLog(0)
+ logger.logSetDozeAmount(1f, 1f, "source1", StatusBarState.SHADE, changed = true)
+ verifyDidLog(1)
+ }
+
+ @Test
+ fun setDozeAmountWillIncludeFractionalUpdatesWhenStateChanges() {
+ logger.logSetDozeAmount(0f, 0f, "source1", StatusBarState.SHADE, changed = false)
+ verifyDidLog(1)
+ logger.logSetDozeAmount(0.1f, 0.1f, "source1", StatusBarState.SHADE, changed = true)
+ verifyDidLog(1)
+ logger.logSetDozeAmount(0.2f, 0.2f, "source1", StatusBarState.SHADE, changed = true)
+ logger.logSetDozeAmount(0.3f, 0.3f, "source1", StatusBarState.SHADE, changed = true)
+ logger.logSetDozeAmount(0.4f, 0.4f, "source1", StatusBarState.SHADE, changed = true)
+ logger.logSetDozeAmount(0.5f, 0.5f, "source1", StatusBarState.SHADE, changed = true)
+ verifyDidLog(0)
+ logger.logSetDozeAmount(0.5f, 0.5f, "source1", StatusBarState.KEYGUARD, changed = false)
+ verifyDidLog(1)
+ }
+
+ @Test
+ fun setDozeAmountWillIncludeFractionalUpdatesWhenSourceChanges() {
+ logger.logSetDozeAmount(0f, 0f, "source1", StatusBarState.SHADE, changed = false)
+ verifyDidLog(1)
+ logger.logSetDozeAmount(0.1f, 0.1f, "source1", StatusBarState.SHADE, changed = true)
+ verifyDidLog(1)
+ logger.logSetDozeAmount(0.2f, 0.2f, "source1", StatusBarState.SHADE, changed = true)
+ logger.logSetDozeAmount(0.3f, 0.3f, "source1", StatusBarState.SHADE, changed = true)
+ logger.logSetDozeAmount(0.4f, 0.4f, "source1", StatusBarState.SHADE, changed = true)
+ logger.logSetDozeAmount(0.5f, 0.5f, "source1", StatusBarState.SHADE, changed = true)
+ verifyDidLog(0)
+ logger.logSetDozeAmount(0.5f, 0.5f, "source2", StatusBarState.SHADE, changed = false)
+ verifyDidLog(1)
+ }
+
+ class LogBufferCounter {
+ val recentLogs = mutableListOf<Pair<String, LogLevel>>()
+ val tracker =
+ object : LogcatEchoTracker {
+ override val logInBackgroundThread: Boolean = false
+ override fun isBufferLoggable(bufferName: String, level: LogLevel): Boolean = false
+ override fun isTagLoggable(tagName: String, level: LogLevel): Boolean {
+ recentLogs.add(tagName to level)
+ return true
+ }
+ }
+ val logBuffer =
+ LogBuffer(name = "test", maxSize = 1, logcatEchoTracker = tracker, systrace = false)
+
+ fun verifyDidLog(times: Int) {
+ assertThat(recentLogs).hasSize(times)
+ recentLogs.clear()
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
new file mode 100644
index 000000000000..95591a4b321c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
@@ -0,0 +1,163 @@
+/*
+ * 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
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.anyFloat
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.verify
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class NotificationWakeUpCoordinatorTest : SysuiTestCase() {
+
+ private val dumpManager: DumpManager = mock()
+ private val headsUpManager: HeadsUpManager = mock()
+ private val statusBarStateController: StatusBarStateController = mock()
+ private val bypassController: KeyguardBypassController = mock()
+ private val dozeParameters: DozeParameters = mock()
+ private val screenOffAnimationController: ScreenOffAnimationController = mock()
+ private val logger: NotificationWakeUpCoordinatorLogger = mock()
+ private val stackScrollerController: NotificationStackScrollLayoutController = mock()
+
+ private lateinit var notificationWakeUpCoordinator: NotificationWakeUpCoordinator
+ private lateinit var statusBarStateCallback: StatusBarStateController.StateListener
+ private lateinit var bypassChangeCallback: KeyguardBypassController.OnBypassStateChangedListener
+
+ private var bypassEnabled: Boolean = false
+ private var statusBarState: Int = StatusBarState.KEYGUARD
+ private var dozeAmount: Float = 0f
+
+ private fun setBypassEnabled(enabled: Boolean) {
+ bypassEnabled = enabled
+ bypassChangeCallback.onBypassStateChanged(enabled)
+ }
+
+ private fun setStatusBarState(state: Int) {
+ statusBarState = state
+ statusBarStateCallback.onStateChanged(state)
+ }
+
+ private fun setDozeAmount(dozeAmount: Float) {
+ this.dozeAmount = dozeAmount
+ statusBarStateCallback.onDozeAmountChanged(dozeAmount, dozeAmount)
+ }
+
+ @Before
+ fun setup() {
+ whenever(bypassController.bypassEnabled).then { bypassEnabled }
+ whenever(statusBarStateController.state).then { statusBarState }
+ notificationWakeUpCoordinator =
+ NotificationWakeUpCoordinator(
+ dumpManager,
+ headsUpManager,
+ statusBarStateController,
+ bypassController,
+ dozeParameters,
+ screenOffAnimationController,
+ logger,
+ )
+ statusBarStateCallback = withArgCaptor {
+ verify(statusBarStateController).addCallback(capture())
+ }
+ bypassChangeCallback = withArgCaptor {
+ verify(bypassController).registerOnBypassStateChangedListener(capture())
+ }
+ notificationWakeUpCoordinator.setStackScroller(stackScrollerController)
+ }
+
+ @Test
+ fun setDozeToOneWillFullyHideNotifications() {
+ setDozeAmount(1f)
+ verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f)
+ assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
+ }
+
+ @Test
+ fun setDozeToZeroWillFullyShowNotifications() {
+ setDozeAmount(0f)
+ verifyStackScrollerDozeAndHideAmount(dozeAmount = 0f, hideAmount = 0f)
+ assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
+ }
+
+ @Test
+ fun setDozeToOneThenZeroWillFullyShowNotifications() {
+ setDozeToOneWillFullyHideNotifications()
+ clearInvocations(stackScrollerController)
+ setDozeToZeroWillFullyShowNotifications()
+ }
+
+ @Test
+ fun setDozeToHalfWillHalfShowNotifications() {
+ setDozeAmount(0.5f)
+ verifyStackScrollerDozeAndHideAmount(dozeAmount = 0.5f, hideAmount = 0.5f)
+ assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
+ }
+
+ @Test
+ fun setDozeToZeroWithBypassWillFullyHideNotifications() {
+ bypassEnabled = true
+ setDozeAmount(0f)
+ verifyStackScrollerDozeAndHideAmount(dozeAmount = 01f, hideAmount = 1f)
+ assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
+ }
+
+ @Test
+ fun disablingBypassWillShowNotifications() {
+ setDozeToZeroWithBypassWillFullyHideNotifications()
+ clearInvocations(stackScrollerController)
+ setBypassEnabled(false)
+ verifyStackScrollerDozeAndHideAmount(dozeAmount = 0f, hideAmount = 0f)
+ assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
+ }
+
+ @Test
+ fun switchingToShadeWithBypassEnabledWillShowNotifications() {
+ setDozeToZeroWithBypassWillFullyHideNotifications()
+ clearInvocations(stackScrollerController)
+ setStatusBarState(StatusBarState.SHADE)
+ verifyStackScrollerDozeAndHideAmount(dozeAmount = 0f, hideAmount = 0f)
+ assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
+ assertThat(notificationWakeUpCoordinator.statusBarState).isEqualTo(StatusBarState.SHADE)
+ }
+
+ private fun verifyStackScrollerDozeAndHideAmount(dozeAmount: Float, hideAmount: Float) {
+ // First verify that we did in-fact receive the correct values
+ verify(stackScrollerController).setDozeAmount(dozeAmount)
+ verify(stackScrollerController).setHideAmount(hideAmount, hideAmount)
+ // Now verify that there was just this ONE call to each of these methods
+ verify(stackScrollerController).setDozeAmount(anyFloat())
+ verify(stackScrollerController).setHideAmount(anyFloat(), anyFloat())
+ }
+}
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 9f6f082d07c4..ff26a43c0006 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
@@ -413,6 +413,37 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
verify(mNotificationStackScrollLayout).updateEmptyShadeView(anyBoolean(), anyBoolean());
}
+ @Test
+ public void testAttach_updatesViewStatusBarState() {
+ // GIVEN: Controller is attached
+ mController.attach(mNotificationStackScrollLayout);
+ ArgumentCaptor<StatusBarStateController.StateListener> captor =
+ ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
+ verify(mSysuiStatusBarStateController).addCallback(captor.capture(), anyInt());
+ StatusBarStateController.StateListener stateListener = captor.getValue();
+
+ // WHEN: StatusBarState changes to SHADE
+ when(mSysuiStatusBarStateController.getState()).thenReturn(SHADE);
+ stateListener.onStateChanged(SHADE);
+
+ // THEN: NSSL is updated with the current state
+ verify(mNotificationStackScrollLayout).setStatusBarState(SHADE);
+
+ // WHEN: Controller is detached
+ mController.mOnAttachStateChangeListener
+ .onViewDetachedFromWindow(mNotificationStackScrollLayout);
+
+ // WHEN: StatusBarState changes to KEYGUARD
+ when(mSysuiStatusBarStateController.getState()).thenReturn(KEYGUARD);
+
+ // WHEN: Controller is re-attached
+ mController.mOnAttachStateChangeListener
+ .onViewAttachedToWindow(mNotificationStackScrollLayout);
+
+ // THEN: NSSL is updated with the current state
+ verify(mNotificationStackScrollLayout).setStatusBarState(KEYGUARD);
+ }
+
private LogMaker logMatcher(int category, int type) {
return argThat(new LogMatcher(category, type));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index dd7143ae7e16..cbf841b5a1f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.stack;
import static android.view.View.GONE;
+import static android.view.WindowInsets.Type.ime;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
@@ -46,6 +47,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -54,6 +56,8 @@ import android.util.MathUtils;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.view.WindowInsetsAnimation;
import android.widget.TextView;
import androidx.test.annotation.UiThreadTest;
@@ -91,6 +95,8 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
+import java.util.ArrayList;
+
/**
* Tests for {@link NotificationStackScrollLayout}.
*/
@@ -843,6 +849,19 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
verify(mEmptyShadeView).setFooterText(not(0));
}
+ @Test
+ public void testWindowInsetAnimationProgress_updatesBottomInset() {
+ int bottomImeInset = 100;
+ mStackScrollerInternal.setAnimatedInsetsEnabled(true);
+ WindowInsets windowInsets = new WindowInsets.Builder()
+ .setInsets(ime(), Insets.of(0, 0, 0, bottomImeInset)).build();
+ ArrayList<WindowInsetsAnimation> windowInsetsAnimations = new ArrayList<>();
+ mStackScrollerInternal
+ .dispatchWindowInsetsAnimationProgress(windowInsets, windowInsetsAnimations);
+
+ assertEquals(bottomImeInset, mStackScrollerInternal.mBottomInset);
+ }
+
private void setBarStateForTest(int state) {
// Can't inject this through the listener or we end up on the actual implementation
// rather than the mock because the spy just coppied the anonymous inner /shruggie.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index 680a32375988..78da78269ac4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -20,6 +20,7 @@ import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -227,14 +228,154 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
}
@Test
- public void testHandleUpEvent_menuRow() {
- when(mSwipeHelper.getCurrentMenuRow()).thenReturn(mMenuRow);
- doNothing().when(mSwipeHelper).handleMenuRowSwipe(mEvent, mView, 0, mMenuRow);
+ public void testHandleUpEvent_menuRowWithoutMenu_dismiss() {
+ doNothing().when(mSwipeHelper).dismiss(any(), anyFloat());
+ doReturn(true).when(mSwipeHelper).isDismissGesture(any());
+ doReturn(true).when(mSwipeHelper).swipedFarEnough();
+ when(mMenuRow.shouldShowMenu()).thenReturn(true);
+ mSwipeHelper.setCurrentMenuRow(mMenuRow);
+
+ assertTrue("Menu row exists",
+ mSwipeHelper.handleUpEvent(mEvent, mView, 0, 0));
+ verify(mMenuRow, times(1)).onTouchEnd();
+ verify(mSwipeHelper, times(1)).isDismissGesture(mEvent);
+ verify(mSwipeHelper, times(1)).dismiss(mView, 0);
+ verify(mSwipeHelper, never()).isFalseGesture();
+ }
+
+ @Test
+ public void testHandleUpEvent_menuRowWithoutMenu_snapback() {
+ doNothing().when(mSwipeHelper).snapChild(any(), anyInt(), anyFloat());
+ doReturn(false).when(mSwipeHelper).isDismissGesture(any());
+ doReturn(true).when(mSwipeHelper).swipedFarEnough();
+ when(mMenuRow.shouldShowMenu()).thenReturn(true);
+ mSwipeHelper.setCurrentMenuRow(mMenuRow);
+
+ assertTrue("Menu row exists",
+ mSwipeHelper.handleUpEvent(mEvent, mView, 0, 0));
+ verify(mMenuRow, times(1)).onTouchEnd();
+ verify(mSwipeHelper, times(1)).isDismissGesture(mEvent);
+ verify(mSwipeHelper, times(1)).snapClosed(mView, 0);
+ verify(mMenuRow, times(1)).onSnapClosed();
+ verify(mSwipeHelper, never()).isFalseGesture();
+ }
+
+ @Test
+ public void testHandleUpEvent_menuRowWithOpenMenu_dismissed() {
+ doNothing().when(mSwipeHelper).dismiss(any(), anyFloat());
+ doReturn(true).when(mSwipeHelper).isDismissGesture(any());
+ doReturn(true).when(mSwipeHelper).swipedFarEnough();
+ when(mMenuRow.shouldShowMenu()).thenReturn(true);
+ when(mMenuRow.isSnappedAndOnSameSide()).thenReturn(true);
+ mSwipeHelper.setCurrentMenuRow(mMenuRow);
+
+ assertTrue("Menu row exists",
+ mSwipeHelper.handleUpEvent(mEvent, mView, 0, 0));
+ verify(mMenuRow, times(1)).onTouchEnd();
+ verify(mSwipeHelper, times(1)).isDismissGesture(mEvent);
+ verify(mSwipeHelper, times(1)).dismiss(mView, 0);
+ verify(mSwipeHelper, never()).isFalseGesture();
+ }
+
+ @Test
+ public void testHandleUpEvent_menuRowWithOpenMenu_snapback() {
+ doNothing().when(mSwipeHelper).snapChild(any(), anyInt(), anyFloat());
+ doReturn(false).when(mSwipeHelper).isDismissGesture(any());
+ doReturn(true).when(mSwipeHelper).swipedFarEnough();
+ when(mMenuRow.shouldShowMenu()).thenReturn(true);
+ when(mMenuRow.isSnappedAndOnSameSide()).thenReturn(true);
+ mSwipeHelper.setCurrentMenuRow(mMenuRow);
+
+ assertTrue("Menu row exists",
+ mSwipeHelper.handleUpEvent(mEvent, mView, 0, 0));
+ verify(mMenuRow, times(1)).onTouchEnd();
+ verify(mSwipeHelper, times(1)).isDismissGesture(mEvent);
+ verify(mSwipeHelper, times(1)).snapClosed(mView, 0);
+ verify(mMenuRow, times(1)).onSnapClosed();
+ verify(mSwipeHelper, never()).isFalseGesture();
+ }
+
+ @Test
+ public void testHandleUpEvent_menuRowWithClosedMenu_dismissed() {
+ doNothing().when(mSwipeHelper).dismiss(any(), anyFloat());
+ doReturn(true).when(mSwipeHelper).isDismissGesture(any());
+ doReturn(true).when(mSwipeHelper).swipedFarEnough();
+ when(mMenuRow.shouldShowMenu()).thenReturn(true);
+ when(mMenuRow.isSnappedAndOnSameSide()).thenReturn(false);
+ mSwipeHelper.setCurrentMenuRow(mMenuRow);
assertTrue("Menu row exists",
mSwipeHelper.handleUpEvent(mEvent, mView, 0, 0));
verify(mMenuRow, times(1)).onTouchEnd();
- verify(mSwipeHelper, times(1)).handleMenuRowSwipe(mEvent, mView, 0, mMenuRow);
+ verify(mSwipeHelper, times(1)).isDismissGesture(mEvent);
+ verify(mSwipeHelper, times(1)).dismiss(mView, 0);
+ verify(mSwipeHelper, never()).isFalseGesture();
+ }
+
+ @Test
+ public void testHandleUpEvent_menuRowWithClosedMenu_snapback() {
+ doNothing().when(mSwipeHelper).snapChild(any(), anyInt(), anyFloat());
+ doReturn(false).when(mSwipeHelper).isDismissGesture(any());
+ doReturn(true).when(mSwipeHelper).swipedFarEnough();
+ when(mMenuRow.shouldShowMenu()).thenReturn(true);
+ when(mMenuRow.isSnappedAndOnSameSide()).thenReturn(false);
+ mSwipeHelper.setCurrentMenuRow(mMenuRow);
+
+ assertTrue("Menu row exists",
+ mSwipeHelper.handleUpEvent(mEvent, mView, 0, 0));
+ verify(mMenuRow, times(1)).onTouchEnd();
+ verify(mSwipeHelper, times(1)).isDismissGesture(mEvent);
+ verify(mSwipeHelper, times(1)).snapClosed(mView, 0);
+ verify(mMenuRow, times(1)).onSnapClosed();
+ verify(mSwipeHelper, never()).isFalseGesture();
+ }
+
+ @Test
+ public void testIsDismissGesture() {
+ doReturn(false).when(mSwipeHelper).isFalseGesture();
+ doReturn(true).when(mSwipeHelper).swipedFarEnough();
+ doReturn(true).when(mSwipeHelper).swipedFastEnough();
+ when(mCallback.canChildBeDismissedInDirection(any(), anyBoolean())).thenReturn(true);
+ when(mEvent.getActionMasked()).thenReturn(MotionEvent.ACTION_UP);
+
+ assertTrue("Should be a dismiss gesture", mSwipeHelper.isDismissGesture(mEvent));
+ verify(mSwipeHelper, times(1)).isFalseGesture();
+ }
+
+ @Test
+ public void testIsDismissGesture_falseGesture() {
+ doReturn(true).when(mSwipeHelper).isFalseGesture();
+ doReturn(true).when(mSwipeHelper).swipedFarEnough();
+ doReturn(true).when(mSwipeHelper).swipedFastEnough();
+ when(mCallback.canChildBeDismissedInDirection(any(), anyBoolean())).thenReturn(true);
+ when(mEvent.getActionMasked()).thenReturn(MotionEvent.ACTION_UP);
+
+ assertFalse("False gesture should stop dismissal", mSwipeHelper.isDismissGesture(mEvent));
+ verify(mSwipeHelper, times(1)).isFalseGesture();
+ }
+
+ @Test
+ public void testIsDismissGesture_farEnough() {
+ doReturn(false).when(mSwipeHelper).isFalseGesture();
+ doReturn(true).when(mSwipeHelper).swipedFarEnough();
+ doReturn(false).when(mSwipeHelper).swipedFastEnough();
+ when(mCallback.canChildBeDismissedInDirection(any(), anyBoolean())).thenReturn(true);
+ when(mEvent.getActionMasked()).thenReturn(MotionEvent.ACTION_UP);
+
+ assertTrue("Should be a dismissal", mSwipeHelper.isDismissGesture(mEvent));
+ verify(mSwipeHelper, times(1)).isFalseGesture();
+ }
+
+ @Test
+ public void testIsDismissGesture_notFarOrFastEnough() {
+ doReturn(false).when(mSwipeHelper).isFalseGesture();
+ doReturn(false).when(mSwipeHelper).swipedFarEnough();
+ doReturn(false).when(mSwipeHelper).swipedFastEnough();
+ when(mCallback.canChildBeDismissedInDirection(any(), anyBoolean())).thenReturn(true);
+ when(mEvent.getActionMasked()).thenReturn(MotionEvent.ACTION_UP);
+
+ assertFalse("Should not be a dismissal", mSwipeHelper.isDismissGesture(mEvent));
+ verify(mSwipeHelper, times(1)).isFalseGesture();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index f568547d3b59..e680a4ec19d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -53,7 +53,7 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.AutoAddTracker;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.ReduceBrightColorsController;
import com.android.systemui.qs.SettingObserver;
import com.android.systemui.qs.external.CustomTile;
@@ -104,7 +104,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
private static final int USER = 0;
- @Mock private QSTileHost mQsTileHost;
+ @Mock private QSHost mQsHost;
@Mock private AutoAddTracker mAutoAddTracker;
@Mock private CastController mCastController;
@Mock private HotspotController mHotspotController;
@@ -144,7 +144,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
R.string.safety_quick_settings_tile_class, TEST_CUSTOM_SAFETY_CLASS);
when(mAutoAddTrackerBuilder.build()).thenReturn(mAutoAddTracker);
- when(mQsTileHost.getUserContext()).thenReturn(mUserContext);
+ when(mQsHost.getUserContext()).thenReturn(mUserContext);
when(mUserContext.getUser()).thenReturn(UserHandle.of(USER));
mPackageManager = Mockito.spy(mContext.getPackageManager());
when(mPackageManager.getPermissionControllerPackageName())
@@ -174,7 +174,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
WalletController walletController,
SafetyController safetyController,
@Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) {
- return new AutoTileManager(context, autoAddTrackerBuilder, mQsTileHost,
+ return new AutoTileManager(context, autoAddTrackerBuilder, mQsHost,
Handler.createAsync(TestableLooper.get(this).getLooper()),
mSecureSettings,
hotspotController,
@@ -359,7 +359,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
return;
}
mAutoTileManager.mNightDisplayCallback.onActivated(true);
- verify(mQsTileHost).addTile("night");
+ verify(mQsHost).addTile("night");
}
@Test
@@ -368,7 +368,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
return;
}
mAutoTileManager.mNightDisplayCallback.onActivated(false);
- verify(mQsTileHost, never()).addTile("night");
+ verify(mQsHost, never()).addTile("night");
}
@Test
@@ -378,7 +378,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
}
mAutoTileManager.mNightDisplayCallback.onAutoModeChanged(
ColorDisplayManager.AUTO_MODE_TWILIGHT);
- verify(mQsTileHost).addTile("night");
+ verify(mQsHost).addTile("night");
}
@Test
@@ -388,7 +388,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
}
mAutoTileManager.mNightDisplayCallback.onAutoModeChanged(
ColorDisplayManager.AUTO_MODE_CUSTOM_TIME);
- verify(mQsTileHost).addTile("night");
+ verify(mQsHost).addTile("night");
}
@Test
@@ -398,19 +398,19 @@ public class AutoTileManagerTest extends SysuiTestCase {
}
mAutoTileManager.mNightDisplayCallback.onAutoModeChanged(
ColorDisplayManager.AUTO_MODE_DISABLED);
- verify(mQsTileHost, never()).addTile("night");
+ verify(mQsHost, never()).addTile("night");
}
@Test
public void reduceBrightColorsTileAdded_whenActivated() {
mAutoTileManager.mReduceBrightColorsCallback.onActivated(true);
- verify(mQsTileHost).addTile("reduce_brightness");
+ verify(mQsHost).addTile("reduce_brightness");
}
@Test
public void reduceBrightColorsTileNotAdded_whenDeactivated() {
mAutoTileManager.mReduceBrightColorsCallback.onActivated(false);
- verify(mQsTileHost, never()).addTile("reduce_brightness");
+ verify(mQsHost, never()).addTile("reduce_brightness");
}
private static List<CastDevice> buildFakeCastDevice(boolean isCasting) {
@@ -423,28 +423,28 @@ public class AutoTileManagerTest extends SysuiTestCase {
public void castTileAdded_whenDeviceIsCasting() {
doReturn(buildFakeCastDevice(true)).when(mCastController).getCastDevices();
mAutoTileManager.mCastCallback.onCastDevicesChanged();
- verify(mQsTileHost).addTile("cast");
+ verify(mQsHost).addTile("cast");
}
@Test
public void castTileNotAdded_whenDeviceIsNotCasting() {
doReturn(buildFakeCastDevice(false)).when(mCastController).getCastDevices();
mAutoTileManager.mCastCallback.onCastDevicesChanged();
- verify(mQsTileHost, never()).addTile("cast");
+ verify(mQsHost, never()).addTile("cast");
}
@Test
public void testSettingTileAdded_onChanged() {
changeValue(TEST_SETTING, 1);
verify(mAutoAddTracker).setTileAdded(TEST_SPEC);
- verify(mQsTileHost).addTile(TEST_SPEC);
+ verify(mQsHost).addTile(TEST_SPEC);
}
@Test
public void testSettingTileAddedComponentAtEnd_onChanged() {
changeValue(TEST_SETTING_COMPONENT, 1);
verify(mAutoAddTracker).setTileAdded(TEST_CUSTOM_SPEC);
- verify(mQsTileHost).addTile(ComponentName.unflattenFromString(TEST_COMPONENT)
+ verify(mQsHost).addTile(ComponentName.unflattenFromString(TEST_COMPONENT)
, /* end */ true);
}
@@ -453,14 +453,14 @@ public class AutoTileManagerTest extends SysuiTestCase {
changeValue(TEST_SETTING, 1);
changeValue(TEST_SETTING, 2);
verify(mAutoAddTracker).setTileAdded(TEST_SPEC);
- verify(mQsTileHost).addTile(TEST_SPEC);
+ verify(mQsHost).addTile(TEST_SPEC);
}
@Test
public void testSettingTileNotAdded_onChangedTo0() {
changeValue(TEST_SETTING, 0);
verify(mAutoAddTracker, never()).setTileAdded(TEST_SPEC);
- verify(mQsTileHost, never()).addTile(TEST_SPEC);
+ verify(mQsHost, never()).addTile(TEST_SPEC);
}
@Test
@@ -469,27 +469,27 @@ public class AutoTileManagerTest extends SysuiTestCase {
changeValue(TEST_SETTING, 1);
verify(mAutoAddTracker, never()).setTileAdded(TEST_SPEC);
- verify(mQsTileHost, never()).addTile(TEST_SPEC);
+ verify(mQsHost, never()).addTile(TEST_SPEC);
}
@Test
public void testSafetyTileNotAdded_ifPreviouslyAdded() {
ComponentName safetyComponent = CustomTile.getComponentFromSpec(TEST_CUSTOM_SAFETY_SPEC);
mAutoTileManager.init();
- verify(mQsTileHost, times(1)).addTile(safetyComponent, true);
+ verify(mQsHost, times(1)).addTile(safetyComponent, true);
when(mAutoAddTracker.isAdded(TEST_CUSTOM_SAFETY_SPEC)).thenReturn(true);
mAutoTileManager.init();
- verify(mQsTileHost, times(1)).addTile(safetyComponent, true);
+ verify(mQsHost, times(1)).addTile(safetyComponent, true);
}
@Test
public void testSafetyTileAdded_onUserChange() {
ComponentName safetyComponent = CustomTile.getComponentFromSpec(TEST_CUSTOM_SAFETY_SPEC);
mAutoTileManager.init();
- verify(mQsTileHost, times(1)).addTile(safetyComponent, true);
+ verify(mQsHost, times(1)).addTile(safetyComponent, true);
when(mAutoAddTracker.isAdded(TEST_CUSTOM_SAFETY_SPEC)).thenReturn(false);
mAutoTileManager.changeUser(UserHandle.of(USER + 1));
- verify(mQsTileHost, times(2)).addTile(safetyComponent, true);
+ verify(mQsHost, times(2)).addTile(safetyComponent, true);
}
@Test
@@ -498,17 +498,17 @@ public class AutoTileManagerTest extends SysuiTestCase {
mAutoTileManager.init();
when(mAutoAddTracker.isAdded(TEST_CUSTOM_SAFETY_SPEC)).thenReturn(true);
mAutoTileManager.mSafetyCallback.onSafetyCenterEnableChanged(false);
- verify(mQsTileHost, times(1)).removeTile(TEST_CUSTOM_SAFETY_SPEC);
+ verify(mQsHost, times(1)).removeTile(TEST_CUSTOM_SAFETY_SPEC);
}
@Test
public void testSafetyTileAdded_onSafetyCenterEnable() {
ComponentName safetyComponent = CustomTile.getComponentFromSpec(TEST_CUSTOM_SAFETY_SPEC);
mAutoTileManager.init();
- verify(mQsTileHost, times(1)).addTile(safetyComponent, true);
+ verify(mQsHost, times(1)).addTile(safetyComponent, true);
mAutoTileManager.mSafetyCallback.onSafetyCenterEnableChanged(false);
mAutoTileManager.mSafetyCallback.onSafetyCenterEnableChanged(true);
- verify(mQsTileHost, times(2)).addTile(safetyComponent, true);
+ verify(mQsHost, times(2)).addTile(safetyComponent, true);
}
@Test
@@ -525,7 +525,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
mManagedProfileCallback.onManagedProfileChanged();
- verify(mQsTileHost, times(1)).addTile(eq("work"), eq(2));
+ verify(mQsHost, times(1)).addTile(eq("work"), eq(2));
verify(mAutoAddTracker, times(1)).setTileAdded(eq("work"));
}
@@ -542,7 +542,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
mManagedProfileCallback.onManagedProfileChanged();
- verify(mQsTileHost, times(1)).removeTile(eq("work"));
+ verify(mQsHost, times(1)).removeTile(eq("work"));
verify(mAutoAddTracker, times(1)).setTileRemoved(eq("work"));
}
@@ -550,7 +550,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
public void testAddControlsTileIfNotPresent() {
String spec = DEVICE_CONTROLS;
when(mAutoAddTracker.isAdded(eq(spec))).thenReturn(false);
- when(mQsTileHost.getTiles()).thenReturn(new ArrayList<>());
+ when(mQsHost.getTiles()).thenReturn(new ArrayList<>());
mAutoTileManager.init();
ArgumentCaptor<DeviceControlsController.Callback> captor =
@@ -559,7 +559,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
verify(mDeviceControlsController).setCallback(captor.capture());
captor.getValue().onControlsUpdate(3);
- verify(mQsTileHost).addTile(spec, 3);
+ verify(mQsHost).addTile(spec, 3);
verify(mAutoAddTracker).setTileAdded(spec);
}
@@ -567,7 +567,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
public void testDontAddControlsTileIfPresent() {
String spec = DEVICE_CONTROLS;
when(mAutoAddTracker.isAdded(eq(spec))).thenReturn(false);
- when(mQsTileHost.getTiles()).thenReturn(new ArrayList<>());
+ when(mQsHost.getTiles()).thenReturn(new ArrayList<>());
mAutoTileManager.init();
ArgumentCaptor<DeviceControlsController.Callback> captor =
@@ -576,7 +576,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
verify(mDeviceControlsController).setCallback(captor.capture());
captor.getValue().removeControlsAutoTracker();
- verify(mQsTileHost, never()).addTile(spec, 3);
+ verify(mQsHost, never()).addTile(spec, 3);
verify(mAutoAddTracker, never()).setTileAdded(spec);
verify(mAutoAddTracker).setTileRemoved(spec);
}
@@ -587,7 +587,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
when(mAutoAddTracker.isAdded(eq(spec))).thenReturn(true);
QSTile mockTile = mock(QSTile.class);
when(mockTile.getTileSpec()).thenReturn(spec);
- when(mQsTileHost.getTiles()).thenReturn(List.of(mockTile));
+ when(mQsHost.getTiles()).thenReturn(List.of(mockTile));
mAutoTileManager.init();
ArgumentCaptor<DeviceControlsController.Callback> captor =
@@ -596,7 +596,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
verify(mDeviceControlsController).setCallback(captor.capture());
captor.getValue().onControlsUpdate(3);
- verify(mQsTileHost, never()).addTile(spec, 3);
+ verify(mQsHost, never()).addTile(spec, 3);
verify(mAutoAddTracker, never()).setTileAdded(spec);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index daf7dd06b0d2..97226e4e68dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -537,6 +537,26 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
verify(mVibratorHelper).vibrateAuthError(anyString());
}
+ @Test
+ public void onFingerprintDetect_showBouncer() {
+ // WHEN fingerprint detect occurs
+ mBiometricUnlockController.onBiometricDetected(UserHandle.USER_CURRENT,
+ BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */);
+
+ // THEN shows primary bouncer
+ verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(anyBoolean());
+ }
+
+ @Test
+ public void onFaceDetect_showBouncer() {
+ // WHEN face detect occurs
+ mBiometricUnlockController.onBiometricDetected(UserHandle.USER_CURRENT,
+ BiometricSourceType.FACE, false /* isStrongBiometric */);
+
+ // THEN shows primary bouncer
+ verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(anyBoolean());
+ }
+
private void givenFingerprintModeUnlockCollapsing() {
when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
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 48573c63d728..2e6f62c2314e 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
@@ -43,6 +43,7 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.CameraLauncher;
import com.android.systemui.shade.NotificationPanelViewController;
@@ -94,6 +95,7 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase {
@Mock private SystemBarAttributesListener mSystemBarAttributesListener;
@Mock private Lazy<CameraLauncher> mCameraLauncherLazy;
@Mock private UserTracker mUserTracker;
+ @Mock private QSHost mQSHost;
CentralSurfacesCommandQueueCallbacks mSbcqCallbacks;
@@ -128,7 +130,8 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase {
DEFAULT_DISPLAY,
mSystemBarAttributesListener,
mCameraLauncherLazy,
- mUserTracker);
+ mUserTracker,
+ mQSHost);
when(mUserTracker.getUserHandle()).thenReturn(
UserHandle.of(ActivityManager.getCurrentUser()));
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 dbf416e9d1aa..5a5b1424758f 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
@@ -1025,6 +1025,17 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
}
@Test
+ public void testSetDozingNotUnlocking_transitionToAuthScrimmed_cancelKeyguardFadingAway() {
+ when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+ when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true);
+
+ mCentralSurfaces.updateScrimController();
+
+ verify(mScrimController).transitionTo(eq(ScrimState.AUTH_SCRIMMED_SHADE));
+ verify(mStatusBarKeyguardViewManager).onKeyguardFadedAway();
+ }
+
+ @Test
public void testShowKeyguardImplementation_setsState() {
when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(new SparseArray<>());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index eb5edbc21d89..f5b7ca804fbc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -180,6 +180,7 @@ public class DozeParametersTest extends SysuiTestCase {
when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "1");
+ verify(mScreenOffAnimationController).onAlwaysOnChanged(false);
assertThat(mDozeParameters.getAlwaysOn()).isFalse();
}
@@ -196,13 +197,16 @@ public class DozeParametersTest extends SysuiTestCase {
mBatteryStateChangeCallback.getValue().onPowerSaveChanged(true);
verify(callback, times(2)).onAlwaysOnChange();
+ verify(mScreenOffAnimationController, times(2)).onAlwaysOnChanged(false);
assertThat(mDozeParameters.getAlwaysOn()).isFalse();
+ reset(mScreenOffAnimationController);
reset(callback);
when(mBatteryController.isAodPowerSave()).thenReturn(false);
mBatteryStateChangeCallback.getValue().onPowerSaveChanged(true);
verify(callback).onAlwaysOnChange();
+ verify(mScreenOffAnimationController).onAlwaysOnChanged(true);
assertThat(mDozeParameters.getAlwaysOn()).isTrue();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
index 305b9fea7569..6b18169bcd86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.phone
import android.app.AlarmManager
-import android.app.IActivityManager
import android.app.admin.DevicePolicyManager
import android.content.SharedPreferences
import android.os.UserManager
@@ -87,7 +86,6 @@ class PhoneStatusBarPolicyTest : SysuiTestCase() {
@Mock private lateinit var keyguardStateController: KeyguardStateController
@Mock private lateinit var locationController: LocationController
@Mock private lateinit var sensorPrivacyController: SensorPrivacyController
- @Mock private lateinit var iActivityManager: IActivityManager
@Mock private lateinit var alarmManager: AlarmManager
@Mock private lateinit var userManager: UserManager
@Mock private lateinit var userTracker: UserTracker
@@ -176,6 +174,7 @@ class PhoneStatusBarPolicyTest : SysuiTestCase() {
commandQueue,
broadcastDispatcher,
executor,
+ executor,
testableLooper.looper,
context.resources,
castController,
@@ -190,7 +189,6 @@ class PhoneStatusBarPolicyTest : SysuiTestCase() {
keyguardStateController,
locationController,
sensorPrivacyController,
- iActivityManager,
alarmManager,
userManager,
userTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index c0537a6dc4cf..e1fba816382c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -24,6 +24,8 @@ import static com.android.systemui.statusbar.phone.ScrimState.SHADE_LOCKED;
import static com.google.common.truth.Truth.assertThat;
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -58,8 +60,14 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
+import com.android.systemui.keyguard.shared.model.KeyguardState;
+import com.android.systemui.keyguard.shared.model.TransitionState;
+import com.android.systemui.keyguard.shared.model.TransitionStep;
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.scrim.ScrimView;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.policy.FakeConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -85,8 +93,10 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import kotlinx.coroutines.CoroutineDispatcher;
+
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class ScrimControllerTest extends SysuiTestCase {
@@ -115,6 +125,11 @@ public class ScrimControllerTest extends SysuiTestCase {
@Mock private DockManager mDockManager;
@Mock private ScreenOffAnimationController mScreenOffAnimationController;
@Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
+ @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ @Mock private CoroutineDispatcher mMainDispatcher;
+ @Mock private SysuiStatusBarStateController mSysuiStatusBarStateController;
+
// TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
// event-dispatch-on-registration pattern caused some of these unit tests to fail.)
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -225,13 +240,22 @@ public class ScrimControllerTest extends SysuiTestCase {
when(mDelayedWakeLockBuilder.build()).thenReturn(mWakeLock);
when(mDockManager.isDocked()).thenReturn(false);
+ when(mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition())
+ .thenReturn(emptyFlow());
+ when(mPrimaryBouncerToGoneTransitionViewModel.getScrimBehindAlpha())
+ .thenReturn(emptyFlow());
+
mScrimController = new ScrimController(mLightBarController,
mDozeParameters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
mScreenOffAnimationController,
mKeyguardUnlockAnimationController,
- mStatusBarKeyguardViewManager);
+ mStatusBarKeyguardViewManager,
+ mPrimaryBouncerToGoneTransitionViewModel,
+ mKeyguardTransitionInteractor,
+ mSysuiStatusBarStateController,
+ mMainDispatcher);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
mScrimController.setAnimatorListener(mAnimatorListener);
@@ -861,7 +885,11 @@ public class ScrimControllerTest extends SysuiTestCase {
mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
mScreenOffAnimationController,
mKeyguardUnlockAnimationController,
- mStatusBarKeyguardViewManager);
+ mStatusBarKeyguardViewManager,
+ mPrimaryBouncerToGoneTransitionViewModel,
+ mKeyguardTransitionInteractor,
+ mSysuiStatusBarStateController,
+ mMainDispatcher);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
mScrimController.setAnimatorListener(mAnimatorListener);
@@ -1356,33 +1384,10 @@ public class ScrimControllerTest extends SysuiTestCase {
}
@Test
- public void notificationAlpha_unnocclusionAnimating_bouncerActive_usesKeyguardNotifAlpha() {
- when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(true);
- mScrimController.setClipsQsScrim(true);
-
- mScrimController.transitionTo(ScrimState.KEYGUARD);
- mScrimController.setUnocclusionAnimationRunning(true);
-
- assertAlphaAfterExpansion(
- mNotificationsScrim, ScrimState.KEYGUARD.getNotifAlpha(), /* expansion */ 0f);
- assertAlphaAfterExpansion(
- mNotificationsScrim, ScrimState.KEYGUARD.getNotifAlpha(), /* expansion */ 0.4f);
- assertAlphaAfterExpansion(
- mNotificationsScrim, ScrimState.KEYGUARD.getNotifAlpha(), /* expansion */ 1.0f);
-
- // Verify normal behavior after
- mScrimController.setUnocclusionAnimationRunning(false);
- float expansion = 0.4f;
- float alpha = 1 - BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(expansion);
- assertAlphaAfterExpansion(mNotificationsScrim, alpha, expansion);
- }
-
- @Test
public void notificationAlpha_unnocclusionAnimating_bouncerNotActive_usesKeyguardNotifAlpha() {
when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false);
mScrimController.transitionTo(ScrimState.KEYGUARD);
- mScrimController.setUnocclusionAnimationRunning(true);
assertAlphaAfterExpansion(
mNotificationsScrim, ScrimState.KEYGUARD.getNotifAlpha(), /* expansion */ 0f);
@@ -1392,7 +1397,6 @@ public class ScrimControllerTest extends SysuiTestCase {
mNotificationsScrim, ScrimState.KEYGUARD.getNotifAlpha(), /* expansion */ 1.0f);
// Verify normal behavior after
- mScrimController.setUnocclusionAnimationRunning(false);
float expansion = 0.4f;
float alpha = 1 - ShadeInterpolation.getNotificationScrimAlpha(expansion);
assertAlphaAfterExpansion(mNotificationsScrim, alpha, expansion);
@@ -1598,7 +1602,6 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void setUnOccludingAnimationKeyguard() {
- mScrimController.setUnocclusionAnimationRunning(true);
mScrimController.transitionTo(ScrimState.KEYGUARD);
finishAnimationsImmediately();
assertThat(mNotificationsScrim.getViewAlpha())
@@ -1654,6 +1657,28 @@ public class ScrimControllerTest extends SysuiTestCase {
assertScrimAlpha(mScrimBehind, 0);
}
+ @Test
+ public void ignoreTransitionRequestWhileKeyguardTransitionRunning() {
+ mScrimController.transitionTo(ScrimState.UNLOCKED);
+ mScrimController.mPrimaryBouncerToGoneTransition.accept(
+ new TransitionStep(KeyguardState.PRIMARY_BOUNCER, KeyguardState.GONE, 0f,
+ TransitionState.RUNNING, "ScrimControllerTest"));
+
+ // This request should not happen
+ mScrimController.transitionTo(ScrimState.BOUNCER);
+ assertThat(mScrimController.getState()).isEqualTo(ScrimState.UNLOCKED);
+ }
+
+ @Test
+ public void primaryBouncerToGoneOnFinishCallsKeyguardFadedAway() {
+ when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true);
+ mScrimController.mPrimaryBouncerToGoneTransition.accept(
+ new TransitionStep(KeyguardState.PRIMARY_BOUNCER, KeyguardState.GONE, 0f,
+ TransitionState.FINISHED, "ScrimControllerTest"));
+
+ verify(mStatusBarKeyguardViewManager).onKeyguardFadedAway();
+ }
+
private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
mScrimController.setRawPanelExpansionFraction(expansion);
finishAnimationsImmediately();
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 1aad83eb73ae..158e9adcff43 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
@@ -368,17 +368,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
}
@Test
- public void setOccluded_animatesPanelExpansion_onlyIfBouncerHidden() {
- mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, true /* animated */);
- verify(mCentralSurfaces).animateKeyguardUnoccluding();
-
- when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(true);
- clearInvocations(mCentralSurfaces);
- mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, true /* animated */);
- verify(mCentralSurfaces, never()).animateKeyguardUnoccluding();
- }
-
- @Test
public void setOccluded_onKeyguardOccludedChangedCalled() {
clearInvocations(mKeyguardStateController);
clearInvocations(mKeyguardUpdateMonitor);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt
index 1779de729e5b..7594c90daa8b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt
@@ -8,13 +8,14 @@ import android.view.WindowManager
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.unfold.TestUnfoldTransitionProvider
+import com.android.systemui.unfold.util.CurrentActivityTypeProvider
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
+import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@@ -26,6 +27,9 @@ class StatusBarMoveFromCenterAnimationControllerTest : SysuiTestCase() {
@Mock
private lateinit var display: Display
+ @Mock
+ private lateinit var currentActivityTypeProvider: CurrentActivityTypeProvider
+
private val view: View = View(context)
private val progressProvider = TestUnfoldTransitionProvider()
private val scopedProvider = ScopedUnfoldTransitionProgressProvider(progressProvider)
@@ -36,9 +40,9 @@ class StatusBarMoveFromCenterAnimationControllerTest : SysuiTestCase() {
fun setUp() {
MockitoAnnotations.initMocks(this)
- `when`(windowManager.defaultDisplay).thenReturn(display)
- `when`(display.rotation).thenReturn(Surface.ROTATION_0)
- `when`(display.getSize(any())).thenAnswer {
+ whenever(windowManager.defaultDisplay).thenReturn(display)
+ whenever(display.rotation).thenReturn(Surface.ROTATION_0)
+ whenever(display.getSize(any())).thenAnswer {
val point = it.arguments[0] as Point
point.x = 100
point.y = 100
@@ -47,7 +51,12 @@ class StatusBarMoveFromCenterAnimationControllerTest : SysuiTestCase() {
scopedProvider.setReadyToHandleTransition(true)
- controller = StatusBarMoveFromCenterAnimationController(scopedProvider, windowManager)
+ controller =
+ StatusBarMoveFromCenterAnimationController(
+ scopedProvider,
+ currentActivityTypeProvider,
+ windowManager
+ )
}
@Test
@@ -99,6 +108,31 @@ class StatusBarMoveFromCenterAnimationControllerTest : SysuiTestCase() {
}
@Test
+ fun alpha_onLauncher_alphaDoesNotChange() {
+ whenever(currentActivityTypeProvider.isHomeActivity).thenReturn(true)
+ controller.onViewsReady(arrayOf(view))
+ progressProvider.onTransitionStarted()
+ progressProvider.onTransitionProgress(0.0f)
+ assertThat(view.alpha).isEqualTo(1.0f)
+
+ progressProvider.onTransitionProgress(1.0f)
+
+ assertThat(view.alpha).isEqualTo(1.0f)
+ }
+
+ @Test
+ fun alpha_NotOnLauncher_alphaChanges() {
+ whenever(currentActivityTypeProvider.isHomeActivity).thenReturn(false)
+ controller.onViewsReady(arrayOf(view))
+ progressProvider.onTransitionStarted()
+ assertThat(view.alpha).isEqualTo(1.0f)
+
+ progressProvider.onTransitionProgress(0.5f)
+
+ assertThat(view.alpha).isNotEqualTo(1.0f)
+ }
+
+ @Test
fun transitionFinished_viewReAttached_noChangesToTranslation() {
controller.onViewsReady(arrayOf(view))
progressProvider.onTransitionProgress(0.5f)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLoggerTest.kt
index 86529dce948a..7c9351c8495d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLoggerTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.shared
+package com.android.systemui.statusbar.pipeline.mobile.data
import android.net.Network
import android.net.NetworkCapabilities
@@ -47,14 +47,14 @@ class MobileInputLoggerTest : SysuiTestCase() {
val expectedNetId = NET_1_ID.toString()
val expectedCaps = NET_1_CAPS.toString()
- assertThat(actualString).contains("true")
+ assertThat(actualString).contains("onDefaultCapabilitiesChanged")
assertThat(actualString).contains(expectedNetId)
assertThat(actualString).contains(expectedCaps)
}
@Test
fun testLogOnLost_bufferHasNetIdOfLostNetwork() {
- logger.logOnLost(NET_1)
+ logger.logOnLost(NET_1, isDefaultNetworkCallback = false)
val stringWriter = StringWriter()
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
@@ -62,6 +62,7 @@ class MobileInputLoggerTest : SysuiTestCase() {
val expectedNetId = NET_1_ID.toString()
+ assertThat(actualString).contains("onLost")
assertThat(actualString).contains(expectedNetId)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModelTest.kt
deleted file mode 100644
index 45189cf8d432..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModelTest.kt
+++ /dev/null
@@ -1,106 +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.pipeline.mobile.data.model
-
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.log.table.TableRowLogger
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_ACTIVITY_DIRECTION_IN
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_ACTIVITY_DIRECTION_OUT
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_CARRIER_NETWORK_CHANGE
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_CDMA_LEVEL
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_CONNECTION_STATE
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_EMERGENCY
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_IS_GSM
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_OPERATOR
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_PRIMARY_LEVEL
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_RESOLVED_NETWORK_TYPE
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_ROAMING
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-
-@SmallTest
-class MobileConnectionModelTest : SysuiTestCase() {
-
- @Test
- fun `log diff - initial log contains all columns`() {
- val logger = TestLogger()
- val connection = MobileConnectionModel()
-
- connection.logFull(logger)
-
- assertThat(logger.changes)
- .contains(Pair(COL_EMERGENCY, connection.isEmergencyOnly.toString()))
- assertThat(logger.changes).contains(Pair(COL_ROAMING, connection.isRoaming.toString()))
- assertThat(logger.changes)
- .contains(Pair(COL_OPERATOR, connection.operatorAlphaShort.toString()))
- assertThat(logger.changes).contains(Pair(COL_IS_GSM, connection.isGsm.toString()))
- assertThat(logger.changes).contains(Pair(COL_CDMA_LEVEL, connection.cdmaLevel.toString()))
- assertThat(logger.changes)
- .contains(Pair(COL_PRIMARY_LEVEL, connection.primaryLevel.toString()))
- assertThat(logger.changes)
- .contains(Pair(COL_CONNECTION_STATE, connection.dataConnectionState.toString()))
- assertThat(logger.changes)
- .contains(
- Pair(
- COL_ACTIVITY_DIRECTION_IN,
- connection.dataActivityDirection.hasActivityIn.toString(),
- )
- )
- assertThat(logger.changes)
- .contains(
- Pair(
- COL_ACTIVITY_DIRECTION_OUT,
- connection.dataActivityDirection.hasActivityOut.toString(),
- )
- )
- assertThat(logger.changes)
- .contains(
- Pair(COL_CARRIER_NETWORK_CHANGE, connection.carrierNetworkChangeActive.toString())
- )
- assertThat(logger.changes)
- .contains(Pair(COL_RESOLVED_NETWORK_TYPE, connection.resolvedNetworkType.toString()))
- }
-
- @Test
- fun `log diff - primary level changes - only level is logged`() {
- val logger = TestLogger()
- val connectionOld = MobileConnectionModel(primaryLevel = 1)
-
- val connectionNew = MobileConnectionModel(primaryLevel = 2)
-
- connectionNew.logDiffs(connectionOld, logger)
-
- assertThat(logger.changes).isEqualTo(listOf(Pair(COL_PRIMARY_LEVEL, "2")))
- }
-
- private class TestLogger : TableRowLogger {
- val changes = mutableListOf<Pair<String, String>>()
-
- override fun logChange(columnName: String, value: String?) {
- changes.add(Pair(columnName, value.toString()))
- }
-
- override fun logChange(columnName: String, value: Int) {
- changes.add(Pair(columnName, value.toString()))
- }
-
- override fun logChange(columnName: String, value: Boolean) {
- changes.add(Pair(columnName, value.toString()))
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
index 0145103d55e1..dfef62e95eda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
@@ -24,8 +24,8 @@ import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig
-import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
index 53cd71f1bdf9..44fbd5b99894 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
@@ -17,9 +17,11 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import kotlinx.coroutines.flow.MutableStateFlow
// TODO(b/261632894): remove this in favor of the real impl or DemoMobileConnectionRepository
@@ -27,8 +29,19 @@ class FakeMobileConnectionRepository(
override val subId: Int,
override val tableLogBuffer: TableLogBuffer,
) : MobileConnectionRepository {
- private val _connectionInfo = MutableStateFlow(MobileConnectionModel())
- override val connectionInfo = _connectionInfo
+ override val isEmergencyOnly = MutableStateFlow(false)
+ override val isRoaming = MutableStateFlow(false)
+ override val operatorAlphaShort: MutableStateFlow<String?> = MutableStateFlow(null)
+ override val isInService = MutableStateFlow(false)
+ override val isGsm = MutableStateFlow(false)
+ override val cdmaLevel = MutableStateFlow(0)
+ override val primaryLevel = MutableStateFlow(0)
+ override val dataConnectionState = MutableStateFlow(DataConnectionState.Disconnected)
+ override val dataActivityDirection =
+ MutableStateFlow(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
+ override val carrierNetworkChangeActive = MutableStateFlow(false)
+ override val resolvedNetworkType: MutableStateFlow<ResolvedNetworkType> =
+ MutableStateFlow(ResolvedNetworkType.UnknownNetworkType)
override val numberOfLevels = MutableStateFlow(DEFAULT_NUM_LEVELS)
@@ -40,10 +53,6 @@ class FakeMobileConnectionRepository(
override val networkName =
MutableStateFlow<NetworkNameModel>(NetworkNameModel.Default("default"))
- fun setConnectionInfo(model: MobileConnectionModel) {
- _connectionInfo.value = model
- }
-
fun setDataEnabled(enabled: Boolean) {
_dataEnabled.value = enabled
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
index 17502f28a479..07c8cee9a3d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
@@ -27,13 +27,13 @@ import com.android.systemui.demomode.DemoModeController
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoModeMobileConnectionDataSource
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.validMobileEvent
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl
-import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
index 00ce412f2a65..37fac3458c83 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
@@ -25,7 +25,6 @@ import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
@@ -36,8 +35,11 @@ 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.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
@@ -123,34 +125,49 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
assertConnection(underTest, networkModel)
}
- private fun assertConnection(
+ private fun TestScope.startCollection(conn: DemoMobileConnectionRepository): Job {
+ val job = launch {
+ launch { conn.cdmaLevel.collect {} }
+ launch { conn.primaryLevel.collect {} }
+ launch { conn.dataActivityDirection.collect {} }
+ launch { conn.carrierNetworkChangeActive.collect {} }
+ launch { conn.isRoaming.collect {} }
+ launch { conn.networkName.collect {} }
+ launch { conn.isEmergencyOnly.collect {} }
+ launch { conn.dataConnectionState.collect {} }
+ }
+ return job
+ }
+
+ private fun TestScope.assertConnection(
conn: DemoMobileConnectionRepository,
model: FakeNetworkEventModel
) {
+ val job = startCollection(underTest)
when (model) {
is FakeNetworkEventModel.Mobile -> {
- val connectionInfo: MobileConnectionModel = conn.connectionInfo.value
assertThat(conn.subId).isEqualTo(model.subId)
- assertThat(connectionInfo.cdmaLevel).isEqualTo(model.level)
- assertThat(connectionInfo.primaryLevel).isEqualTo(model.level)
- assertThat(connectionInfo.dataActivityDirection)
+ assertThat(conn.cdmaLevel.value).isEqualTo(model.level)
+ assertThat(conn.primaryLevel.value).isEqualTo(model.level)
+ assertThat(conn.dataActivityDirection.value)
.isEqualTo((model.activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel())
- assertThat(connectionInfo.carrierNetworkChangeActive)
+ assertThat(conn.carrierNetworkChangeActive.value)
.isEqualTo(model.carrierNetworkChange)
- assertThat(connectionInfo.isRoaming).isEqualTo(model.roaming)
+ assertThat(conn.isRoaming.value).isEqualTo(model.roaming)
assertThat(conn.networkName.value)
.isEqualTo(NetworkNameModel.IntentDerived(model.name))
// TODO(b/261029387): check these once we start handling them
- assertThat(connectionInfo.isEmergencyOnly).isFalse()
- assertThat(connectionInfo.isGsm).isFalse()
- assertThat(connectionInfo.dataConnectionState)
- .isEqualTo(DataConnectionState.Connected)
+ assertThat(conn.isEmergencyOnly.value).isFalse()
+ assertThat(conn.isGsm.value).isFalse()
+ assertThat(conn.dataConnectionState.value).isEqualTo(DataConnectionState.Connected)
}
// MobileDisabled isn't combinatorial in nature, and is tested in
// DemoMobileConnectionsRepositoryTest.kt
else -> {}
}
+
+ job.cancel()
}
/** Matches [FakeNetworkEventModel] */
@@ -239,6 +256,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC
* list2 = [false, true]
* list3 = [a, b, c]
* ```
+ *
* We'll generate test cases for:
*
* Test (1, false, a) Test (2, false, a) Test (3, false, a) Test (1, true, a) Test (1,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
index f60d92bde202..0e45d8ea5563 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
@@ -26,7 +26,6 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
@@ -40,9 +39,11 @@ import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
@@ -524,47 +525,65 @@ class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
job.cancel()
}
- private fun assertConnection(
+ private fun TestScope.startCollection(conn: DemoMobileConnectionRepository): Job {
+ val job = launch {
+ launch { conn.cdmaLevel.collect {} }
+ launch { conn.primaryLevel.collect {} }
+ launch { conn.dataActivityDirection.collect {} }
+ launch { conn.carrierNetworkChangeActive.collect {} }
+ launch { conn.isRoaming.collect {} }
+ launch { conn.networkName.collect {} }
+ launch { conn.isEmergencyOnly.collect {} }
+ launch { conn.dataConnectionState.collect {} }
+ }
+ return job
+ }
+
+ private fun TestScope.assertConnection(
conn: DemoMobileConnectionRepository,
- model: FakeNetworkEventModel
+ model: FakeNetworkEventModel,
) {
+ val job = startCollection(conn)
+ // Assert the fields using the `MutableStateFlow` so that we don't have to start up
+ // a collector for every field for every test
when (model) {
is FakeNetworkEventModel.Mobile -> {
- val connectionInfo: MobileConnectionModel = conn.connectionInfo.value
assertThat(conn.subId).isEqualTo(model.subId)
- assertThat(connectionInfo.cdmaLevel).isEqualTo(model.level)
- assertThat(connectionInfo.primaryLevel).isEqualTo(model.level)
- assertThat(connectionInfo.dataActivityDirection)
+ assertThat(conn.cdmaLevel.value).isEqualTo(model.level)
+ assertThat(conn.primaryLevel.value).isEqualTo(model.level)
+ assertThat(conn.dataActivityDirection.value)
.isEqualTo((model.activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel())
- assertThat(connectionInfo.carrierNetworkChangeActive)
+ assertThat(conn.carrierNetworkChangeActive.value)
.isEqualTo(model.carrierNetworkChange)
- assertThat(connectionInfo.isRoaming).isEqualTo(model.roaming)
+ assertThat(conn.isRoaming.value).isEqualTo(model.roaming)
assertThat(conn.networkName.value)
.isEqualTo(NetworkNameModel.IntentDerived(model.name))
// TODO(b/261029387) check these once we start handling them
- assertThat(connectionInfo.isEmergencyOnly).isFalse()
- assertThat(connectionInfo.isGsm).isFalse()
- assertThat(connectionInfo.dataConnectionState)
- .isEqualTo(DataConnectionState.Connected)
+ assertThat(conn.isEmergencyOnly.value).isFalse()
+ assertThat(conn.isGsm.value).isFalse()
+ assertThat(conn.dataConnectionState.value).isEqualTo(DataConnectionState.Connected)
}
else -> {}
}
+
+ job.cancel()
}
- private fun assertCarrierMergedConnection(
+ private fun TestScope.assertCarrierMergedConnection(
conn: DemoMobileConnectionRepository,
model: FakeWifiEventModel.CarrierMerged,
) {
- val connectionInfo: MobileConnectionModel = conn.connectionInfo.value
+ val job = startCollection(conn)
assertThat(conn.subId).isEqualTo(model.subscriptionId)
- assertThat(connectionInfo.cdmaLevel).isEqualTo(model.level)
- assertThat(connectionInfo.primaryLevel).isEqualTo(model.level)
- assertThat(connectionInfo.carrierNetworkChangeActive).isEqualTo(false)
- assertThat(connectionInfo.isRoaming).isEqualTo(false)
- assertThat(connectionInfo.isEmergencyOnly).isFalse()
- assertThat(connectionInfo.isGsm).isFalse()
- assertThat(connectionInfo.dataConnectionState).isEqualTo(DataConnectionState.Connected)
+ assertThat(conn.cdmaLevel.value).isEqualTo(model.level)
+ assertThat(conn.primaryLevel.value).isEqualTo(model.level)
+ assertThat(conn.carrierNetworkChangeActive.value).isEqualTo(false)
+ assertThat(conn.isRoaming.value).isEqualTo(false)
+ assertThat(conn.isEmergencyOnly.value).isFalse()
+ assertThat(conn.isGsm.value).isFalse()
+ assertThat(conn.dataConnectionState.value).isEqualTo(DataConnectionState.Connected)
+ job.cancel()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
index f0f213bc0d58..441186acb6b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
@@ -22,7 +22,6 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
@@ -75,36 +74,48 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() {
}
@Test
- fun connectionInfo_inactiveWifi_isDefault() =
+ fun inactiveWifi_isDefault() =
testScope.runTest {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latestConnState: DataConnectionState? = null
+ var latestNetType: ResolvedNetworkType? = null
+
+ val dataJob =
+ underTest.dataConnectionState.onEach { latestConnState = it }.launchIn(this)
+ val netJob = underTest.resolvedNetworkType.onEach { latestNetType = it }.launchIn(this)
wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
- assertThat(latest).isEqualTo(MobileConnectionModel())
+ assertThat(latestConnState).isEqualTo(DataConnectionState.Disconnected)
+ assertThat(latestNetType).isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
- job.cancel()
+ dataJob.cancel()
+ netJob.cancel()
}
@Test
- fun connectionInfo_activeWifi_isDefault() =
+ fun activeWifi_isDefault() =
testScope.runTest {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latestConnState: DataConnectionState? = null
+ var latestNetType: ResolvedNetworkType? = null
+
+ val dataJob =
+ underTest.dataConnectionState.onEach { latestConnState = it }.launchIn(this)
+ val netJob = underTest.resolvedNetworkType.onEach { latestNetType = it }.launchIn(this)
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = NET_ID, level = 1))
- assertThat(latest).isEqualTo(MobileConnectionModel())
+ assertThat(latestConnState).isEqualTo(DataConnectionState.Disconnected)
+ assertThat(latestNetType).isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
- job.cancel()
+ dataJob.cancel()
+ netJob.cancel()
}
@Test
- fun connectionInfo_carrierMergedWifi_isValidAndFieldsComeFromWifiNetwork() =
+ fun carrierMergedWifi_isValidAndFieldsComeFromWifiNetwork() =
testScope.runTest {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: Int? = null
+ val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this)
wifiRepository.setIsWifiEnabled(true)
wifiRepository.setIsWifiDefault(true)
@@ -117,34 +128,16 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() {
)
)
- val expected =
- MobileConnectionModel(
- primaryLevel = 3,
- cdmaLevel = 3,
- dataConnectionState = DataConnectionState.Connected,
- dataActivityDirection =
- DataActivityModel(
- hasActivityIn = false,
- hasActivityOut = false,
- ),
- resolvedNetworkType = ResolvedNetworkType.CarrierMergedNetworkType,
- isRoaming = false,
- isEmergencyOnly = false,
- operatorAlphaShort = null,
- isInService = true,
- isGsm = false,
- carrierNetworkChangeActive = false,
- )
- assertThat(latest).isEqualTo(expected)
+ assertThat(latest).isEqualTo(3)
job.cancel()
}
@Test
- fun connectionInfo_activity_comesFromWifiActivity() =
+ fun activity_comesFromWifiActivity() =
testScope.runTest {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: DataActivityModel? = null
+ val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
wifiRepository.setIsWifiEnabled(true)
wifiRepository.setIsWifiDefault(true)
@@ -162,8 +155,8 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() {
)
)
- assertThat(latest!!.dataActivityDirection.hasActivityIn).isTrue()
- assertThat(latest!!.dataActivityDirection.hasActivityOut).isFalse()
+ assertThat(latest!!.hasActivityIn).isTrue()
+ assertThat(latest!!.hasActivityOut).isFalse()
wifiRepository.setWifiActivity(
DataActivityModel(
@@ -172,17 +165,19 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() {
)
)
- assertThat(latest!!.dataActivityDirection.hasActivityIn).isFalse()
- assertThat(latest!!.dataActivityDirection.hasActivityOut).isTrue()
+ assertThat(latest!!.hasActivityIn).isFalse()
+ assertThat(latest!!.hasActivityOut).isTrue()
job.cancel()
}
@Test
- fun connectionInfo_carrierMergedWifi_wrongSubId_isDefault() =
+ fun carrierMergedWifi_wrongSubId_isDefault() =
testScope.runTest {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latestLevel: Int? = null
+ var latestType: ResolvedNetworkType? = null
+ val levelJob = underTest.primaryLevel.onEach { latestLevel = it }.launchIn(this)
+ val typeJob = underTest.resolvedNetworkType.onEach { latestType = it }.launchIn(this)
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
@@ -192,20 +187,19 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() {
)
)
- assertThat(latest).isEqualTo(MobileConnectionModel())
- assertThat(latest!!.primaryLevel).isNotEqualTo(3)
- assertThat(latest!!.resolvedNetworkType)
- .isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
+ assertThat(latestLevel).isNotEqualTo(3)
+ assertThat(latestType).isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
- job.cancel()
+ levelJob.cancel()
+ typeJob.cancel()
}
// This scenario likely isn't possible, but write a test for it anyway
@Test
- fun connectionInfo_carrierMergedButNotEnabled_isDefault() =
+ fun carrierMergedButNotEnabled_isDefault() =
testScope.runTest {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: Int? = null
+ val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this)
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
@@ -216,17 +210,17 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() {
)
wifiRepository.setIsWifiEnabled(false)
- assertThat(latest).isEqualTo(MobileConnectionModel())
+ assertThat(latest).isNotEqualTo(3)
job.cancel()
}
// This scenario likely isn't possible, but write a test for it anyway
@Test
- fun connectionInfo_carrierMergedButWifiNotDefault_isDefault() =
+ fun carrierMergedButWifiNotDefault_isDefault() =
testScope.runTest {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: Int? = null
+ val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this)
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
@@ -237,7 +231,7 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() {
)
wifiRepository.setIsWifiDefault(false)
- assertThat(latest).isEqualTo(MobileConnectionModel())
+ assertThat(latest).isNotEqualTo(3)
job.cancel()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
index cd4d8472763f..db5a7d1ad84a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
@@ -24,13 +24,12 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_EMERGENCY
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_OPERATOR
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_PRIMARY_LEVEL
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_EMERGENCY
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_OPERATOR
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_PRIMARY_LEVEL
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.getTelephonyCallbackForType
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
@@ -94,16 +93,16 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
@Test
fun startingIsCarrierMerged_usesCarrierMergedInitially() =
testScope.runTest {
- val carrierMergedConnectionInfo =
- MobileConnectionModel(
- operatorAlphaShort = "Carrier Merged Operator",
- )
- carrierMergedRepo.setConnectionInfo(carrierMergedConnectionInfo)
+ val carrierMergedOperatorName = "Carrier Merged Operator"
+ val nonCarrierMergedName = "Non-carrier-merged"
+
+ carrierMergedRepo.operatorAlphaShort.value = carrierMergedOperatorName
+ mobileRepo.operatorAlphaShort.value = nonCarrierMergedName
initializeRepo(startingIsCarrierMerged = true)
assertThat(underTest.activeRepo.value).isEqualTo(carrierMergedRepo)
- assertThat(underTest.connectionInfo.value).isEqualTo(carrierMergedConnectionInfo)
+ assertThat(underTest.operatorAlphaShort.value).isEqualTo(carrierMergedOperatorName)
verify(mobileFactory, never())
.build(
SUB_ID,
@@ -116,16 +115,16 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
@Test
fun startingNotCarrierMerged_usesTypicalInitially() =
testScope.runTest {
- val mobileConnectionInfo =
- MobileConnectionModel(
- operatorAlphaShort = "Typical Operator",
- )
- mobileRepo.setConnectionInfo(mobileConnectionInfo)
+ val carrierMergedOperatorName = "Carrier Merged Operator"
+ val nonCarrierMergedName = "Typical Operator"
+
+ carrierMergedRepo.operatorAlphaShort.value = carrierMergedOperatorName
+ mobileRepo.operatorAlphaShort.value = nonCarrierMergedName
initializeRepo(startingIsCarrierMerged = false)
assertThat(underTest.activeRepo.value).isEqualTo(mobileRepo)
- assertThat(underTest.connectionInfo.value).isEqualTo(mobileConnectionInfo)
+ assertThat(underTest.operatorAlphaShort.value).isEqualTo(nonCarrierMergedName)
verify(carrierMergedFactory, never()).build(SUB_ID, tableLogBuffer)
}
@@ -156,39 +155,40 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
testScope.runTest {
initializeRepo(startingIsCarrierMerged = false)
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latestName: String? = null
+ var latestLevel: Int? = null
+
+ val nameJob = underTest.operatorAlphaShort.onEach { latestName = it }.launchIn(this)
+ val levelJob = underTest.primaryLevel.onEach { latestLevel = it }.launchIn(this)
underTest.setIsCarrierMerged(true)
- val info1 =
- MobileConnectionModel(
- operatorAlphaShort = "Carrier Merged Operator",
- primaryLevel = 1,
- )
- carrierMergedRepo.setConnectionInfo(info1)
+ val operator1 = "Carrier Merged Operator"
+ val level1 = 1
+ carrierMergedRepo.operatorAlphaShort.value = operator1
+ carrierMergedRepo.primaryLevel.value = level1
- assertThat(latest).isEqualTo(info1)
+ assertThat(latestName).isEqualTo(operator1)
+ assertThat(latestLevel).isEqualTo(level1)
- val info2 =
- MobileConnectionModel(
- operatorAlphaShort = "Carrier Merged Operator #2",
- primaryLevel = 2,
- )
- carrierMergedRepo.setConnectionInfo(info2)
+ val operator2 = "Carrier Merged Operator #2"
+ val level2 = 2
+ carrierMergedRepo.operatorAlphaShort.value = operator2
+ carrierMergedRepo.primaryLevel.value = level2
- assertThat(latest).isEqualTo(info2)
+ assertThat(latestName).isEqualTo(operator2)
+ assertThat(latestLevel).isEqualTo(level2)
- val info3 =
- MobileConnectionModel(
- operatorAlphaShort = "Carrier Merged Operator #3",
- primaryLevel = 3,
- )
- carrierMergedRepo.setConnectionInfo(info3)
+ val operator3 = "Carrier Merged Operator #3"
+ val level3 = 3
+ carrierMergedRepo.operatorAlphaShort.value = operator3
+ carrierMergedRepo.primaryLevel.value = level3
- assertThat(latest).isEqualTo(info3)
+ assertThat(latestName).isEqualTo(operator3)
+ assertThat(latestLevel).isEqualTo(level3)
- job.cancel()
+ nameJob.cancel()
+ levelJob.cancel()
}
@Test
@@ -196,39 +196,40 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
testScope.runTest {
initializeRepo(startingIsCarrierMerged = false)
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latestName: String? = null
+ var latestLevel: Int? = null
+
+ val nameJob = underTest.operatorAlphaShort.onEach { latestName = it }.launchIn(this)
+ val levelJob = underTest.primaryLevel.onEach { latestLevel = it }.launchIn(this)
underTest.setIsCarrierMerged(false)
- val info1 =
- MobileConnectionModel(
- operatorAlphaShort = "Typical Merged Operator",
- primaryLevel = 1,
- )
- mobileRepo.setConnectionInfo(info1)
+ val operator1 = "Typical Merged Operator"
+ val level1 = 1
+ mobileRepo.operatorAlphaShort.value = operator1
+ mobileRepo.primaryLevel.value = level1
- assertThat(latest).isEqualTo(info1)
+ assertThat(latestName).isEqualTo(operator1)
+ assertThat(latestLevel).isEqualTo(level1)
- val info2 =
- MobileConnectionModel(
- operatorAlphaShort = "Typical Merged Operator #2",
- primaryLevel = 2,
- )
- mobileRepo.setConnectionInfo(info2)
+ val operator2 = "Typical Merged Operator #2"
+ val level2 = 2
+ mobileRepo.operatorAlphaShort.value = operator2
+ mobileRepo.primaryLevel.value = level2
- assertThat(latest).isEqualTo(info2)
+ assertThat(latestName).isEqualTo(operator2)
+ assertThat(latestLevel).isEqualTo(level2)
- val info3 =
- MobileConnectionModel(
- operatorAlphaShort = "Typical Merged Operator #3",
- primaryLevel = 3,
- )
- mobileRepo.setConnectionInfo(info3)
+ val operator3 = "Typical Merged Operator #3"
+ val level3 = 3
+ mobileRepo.operatorAlphaShort.value = operator3
+ mobileRepo.primaryLevel.value = level3
- assertThat(latest).isEqualTo(info3)
+ assertThat(latestName).isEqualTo(operator3)
+ assertThat(latestLevel).isEqualTo(level3)
- job.cancel()
+ nameJob.cancel()
+ levelJob.cancel()
}
@Test
@@ -236,57 +237,58 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
testScope.runTest {
initializeRepo(startingIsCarrierMerged = false)
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latestName: String? = null
+ var latestLevel: Int? = null
- val carrierMergedInfo =
- MobileConnectionModel(
- operatorAlphaShort = "Carrier Merged Operator",
- primaryLevel = 4,
- )
- carrierMergedRepo.setConnectionInfo(carrierMergedInfo)
+ val nameJob = underTest.operatorAlphaShort.onEach { latestName = it }.launchIn(this)
+ val levelJob = underTest.primaryLevel.onEach { latestLevel = it }.launchIn(this)
- val mobileInfo =
- MobileConnectionModel(
- operatorAlphaShort = "Typical Operator",
- primaryLevel = 2,
- )
- mobileRepo.setConnectionInfo(mobileInfo)
+ val carrierMergedOperator = "Carrier Merged Operator"
+ val carrierMergedLevel = 4
+ carrierMergedRepo.operatorAlphaShort.value = carrierMergedOperator
+ carrierMergedRepo.primaryLevel.value = carrierMergedLevel
+
+ val mobileName = "Typical Operator"
+ val mobileLevel = 2
+ mobileRepo.operatorAlphaShort.value = mobileName
+ mobileRepo.primaryLevel.value = mobileLevel
// Start with the mobile info
- assertThat(latest).isEqualTo(mobileInfo)
+ assertThat(latestName).isEqualTo(mobileName)
+ assertThat(latestLevel).isEqualTo(mobileLevel)
// WHEN isCarrierMerged is set to true
underTest.setIsCarrierMerged(true)
// THEN the carrier merged info is used
- assertThat(latest).isEqualTo(carrierMergedInfo)
+ assertThat(latestName).isEqualTo(carrierMergedOperator)
+ assertThat(latestLevel).isEqualTo(carrierMergedLevel)
- val newCarrierMergedInfo =
- MobileConnectionModel(
- operatorAlphaShort = "New CM Operator",
- primaryLevel = 0,
- )
- carrierMergedRepo.setConnectionInfo(newCarrierMergedInfo)
+ val newCarrierMergedName = "New CM Operator"
+ val newCarrierMergedLevel = 0
+ carrierMergedRepo.operatorAlphaShort.value = newCarrierMergedName
+ carrierMergedRepo.primaryLevel.value = newCarrierMergedLevel
- assertThat(latest).isEqualTo(newCarrierMergedInfo)
+ assertThat(latestName).isEqualTo(newCarrierMergedName)
+ assertThat(latestLevel).isEqualTo(newCarrierMergedLevel)
// WHEN isCarrierMerged is set to false
underTest.setIsCarrierMerged(false)
// THEN the typical info is used
- assertThat(latest).isEqualTo(mobileInfo)
+ assertThat(latestName).isEqualTo(mobileName)
+ assertThat(latestLevel).isEqualTo(mobileLevel)
- val newMobileInfo =
- MobileConnectionModel(
- operatorAlphaShort = "New Mobile Operator",
- primaryLevel = 3,
- )
- mobileRepo.setConnectionInfo(newMobileInfo)
+ val newMobileName = "New MobileOperator"
+ val newMobileLevel = 3
+ mobileRepo.operatorAlphaShort.value = newMobileName
+ mobileRepo.primaryLevel.value = newMobileLevel
- assertThat(latest).isEqualTo(newMobileInfo)
+ assertThat(latestName).isEqualTo(newMobileName)
+ assertThat(latestLevel).isEqualTo(newMobileLevel)
- job.cancel()
+ nameJob.cancel()
+ levelJob.cancel()
}
@Test
@@ -370,7 +372,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
initializeRepo(startingIsCarrierMerged = false)
- val job = underTest.connectionInfo.launchIn(this)
+ val emergencyJob = underTest.isEmergencyOnly.launchIn(this)
+ val operatorJob = underTest.operatorAlphaShort.launchIn(this)
// WHEN we set up some mobile connection info
val serviceState = ServiceState()
@@ -394,7 +397,8 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
assertThat(dumpBuffer()).contains("$COL_OPERATOR${BUFFER_SEPARATOR}OpDiff")
assertThat(dumpBuffer()).contains("$COL_EMERGENCY${BUFFER_SEPARATOR}true")
- job.cancel()
+ emergencyJob.cancel()
+ operatorJob.cancel()
}
@Test
@@ -409,7 +413,7 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
initializeRepo(startingIsCarrierMerged = true)
- val job = underTest.connectionInfo.launchIn(this)
+ val job = underTest.primaryLevel.launchIn(this)
// WHEN we set up carrier merged info
val networkId = 2
@@ -452,7 +456,7 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
initializeRepo(startingIsCarrierMerged = false)
- val job = underTest.connectionInfo.launchIn(this)
+ val job = underTest.primaryLevel.launchIn(this)
// WHEN we set up some mobile connection info
val signalStrength = mock<SignalStrength>()
@@ -502,12 +506,7 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
assertThat(bufferAfterCarrierMerged).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}1")
// WHEN the normal network is updated
- val newMobileInfo =
- MobileConnectionModel(
- operatorAlphaShort = "Mobile Operator 2",
- primaryLevel = 0,
- )
- mobileRepo.setConnectionInfo(newMobileInfo)
+ mobileRepo.primaryLevel.value = 0
// THEN the new level is logged
assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}0")
@@ -529,7 +528,7 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
// WHEN isCarrierMerged = false
initializeRepo(startingIsCarrierMerged = false)
- val job = underTest.connectionInfo.launchIn(this)
+ val job = underTest.primaryLevel.launchIn(this)
val signalStrength = mock<SignalStrength>()
whenever(signalStrength.level).thenReturn(1)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index b2577e349da7..f6e595924f58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -50,12 +50,15 @@ import android.telephony.TelephonyManager.EXTRA_SHOW_SPN
import android.telephony.TelephonyManager.EXTRA_SPN
import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID
import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
+import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
import androidx.test.filters.SmallTest
+import com.android.settingslib.mobile.MobileMappings
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
@@ -65,7 +68,6 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrier
import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
-import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
@@ -135,235 +137,285 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
}
@Test
- fun testFlowForSubId_default() =
+ fun emergencyOnly() =
runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
-
- assertThat(latest).isEqualTo(MobileConnectionModel())
-
- job.cancel()
- }
-
- @Test
- fun testFlowForSubId_emergencyOnly() =
- runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: Boolean? = null
+ val job = underTest.isEmergencyOnly.onEach { latest = it }.launchIn(this)
val serviceState = ServiceState()
serviceState.isEmergencyOnly = true
getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
- assertThat(latest?.isEmergencyOnly).isEqualTo(true)
+ assertThat(latest).isEqualTo(true)
job.cancel()
}
@Test
- fun testFlowForSubId_emergencyOnly_toggles() =
+ fun emergencyOnly_toggles() =
runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: Boolean? = null
+ val job = underTest.isEmergencyOnly.onEach { latest = it }.launchIn(this)
val callback = getTelephonyCallbackForType<ServiceStateListener>()
val serviceState = ServiceState()
serviceState.isEmergencyOnly = true
callback.onServiceStateChanged(serviceState)
+ assertThat(latest).isTrue()
+
serviceState.isEmergencyOnly = false
callback.onServiceStateChanged(serviceState)
- assertThat(latest?.isEmergencyOnly).isEqualTo(false)
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun cdmaLevelUpdates() =
+ runBlocking(IMMEDIATE) {
+ var latest: Int? = null
+ val job = underTest.cdmaLevel.onEach { latest = it }.launchIn(this)
+
+ val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>()
+ var strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
+ callback.onSignalStrengthsChanged(strength)
+
+ assertThat(latest).isEqualTo(2)
+
+ // gsmLevel updates, no change to cdmaLevel
+ strength = signalStrength(gsmLevel = 3, cdmaLevel = 2, isGsm = true)
+
+ assertThat(latest).isEqualTo(2)
job.cancel()
}
@Test
- fun testFlowForSubId_signalStrengths_levelsUpdate() =
+ fun gsmLevelUpdates() =
runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: Int? = null
+ val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this)
val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>()
- val strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
+ var strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
callback.onSignalStrengthsChanged(strength)
- assertThat(latest?.isGsm).isEqualTo(true)
- assertThat(latest?.primaryLevel).isEqualTo(1)
- assertThat(latest?.cdmaLevel).isEqualTo(2)
+ assertThat(latest).isEqualTo(1)
+
+ strength = signalStrength(gsmLevel = 3, cdmaLevel = 2, isGsm = true)
+ callback.onSignalStrengthsChanged(strength)
+
+ assertThat(latest).isEqualTo(3)
job.cancel()
}
@Test
- fun testFlowForSubId_dataConnectionState_connected() =
+ fun isGsm() =
runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: Boolean? = null
+ val job = underTest.isGsm.onEach { latest = it }.launchIn(this)
+
+ val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>()
+ var strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
+ callback.onSignalStrengthsChanged(strength)
+
+ assertThat(latest).isTrue()
+
+ strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = false)
+ callback.onSignalStrengthsChanged(strength)
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun dataConnectionState_connected() =
+ runBlocking(IMMEDIATE) {
+ var latest: DataConnectionState? = null
+ val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
val callback =
getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
callback.onDataConnectionStateChanged(DATA_CONNECTED, 200 /* unused */)
- assertThat(latest?.dataConnectionState).isEqualTo(DataConnectionState.Connected)
+ assertThat(latest).isEqualTo(DataConnectionState.Connected)
job.cancel()
}
@Test
- fun testFlowForSubId_dataConnectionState_connecting() =
+ fun dataConnectionState_connecting() =
runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: DataConnectionState? = null
+ val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
val callback =
getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
callback.onDataConnectionStateChanged(DATA_CONNECTING, 200 /* unused */)
- assertThat(latest?.dataConnectionState).isEqualTo(DataConnectionState.Connecting)
+ assertThat(latest).isEqualTo(DataConnectionState.Connecting)
job.cancel()
}
@Test
- fun testFlowForSubId_dataConnectionState_disconnected() =
+ fun dataConnectionState_disconnected() =
runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: DataConnectionState? = null
+ val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
val callback =
getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
callback.onDataConnectionStateChanged(DATA_DISCONNECTED, 200 /* unused */)
- assertThat(latest?.dataConnectionState).isEqualTo(DataConnectionState.Disconnected)
+ assertThat(latest).isEqualTo(DataConnectionState.Disconnected)
job.cancel()
}
@Test
- fun testFlowForSubId_dataConnectionState_disconnecting() =
+ fun dataConnectionState_disconnecting() =
runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: DataConnectionState? = null
+ val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
val callback =
getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
callback.onDataConnectionStateChanged(DATA_DISCONNECTING, 200 /* unused */)
- assertThat(latest?.dataConnectionState).isEqualTo(DataConnectionState.Disconnecting)
+ assertThat(latest).isEqualTo(DataConnectionState.Disconnecting)
job.cancel()
}
@Test
- fun testFlowForSubId_dataConnectionState_suspended() =
+ fun dataConnectionState_suspended() =
runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: DataConnectionState? = null
+ val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
val callback =
getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
callback.onDataConnectionStateChanged(DATA_SUSPENDED, 200 /* unused */)
- assertThat(latest?.dataConnectionState).isEqualTo(DataConnectionState.Suspended)
+ assertThat(latest).isEqualTo(DataConnectionState.Suspended)
job.cancel()
}
@Test
- fun testFlowForSubId_dataConnectionState_handoverInProgress() =
+ fun dataConnectionState_handoverInProgress() =
runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: DataConnectionState? = null
+ val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
val callback =
getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
callback.onDataConnectionStateChanged(DATA_HANDOVER_IN_PROGRESS, 200 /* unused */)
- assertThat(latest?.dataConnectionState)
- .isEqualTo(DataConnectionState.HandoverInProgress)
+ assertThat(latest).isEqualTo(DataConnectionState.HandoverInProgress)
job.cancel()
}
@Test
- fun testFlowForSubId_dataConnectionState_unknown() =
+ fun dataConnectionState_unknown() =
runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: DataConnectionState? = null
+ val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
val callback =
getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
callback.onDataConnectionStateChanged(DATA_UNKNOWN, 200 /* unused */)
- assertThat(latest?.dataConnectionState).isEqualTo(DataConnectionState.Unknown)
+ assertThat(latest).isEqualTo(DataConnectionState.Unknown)
job.cancel()
}
@Test
- fun testFlowForSubId_dataConnectionState_invalid() =
+ fun dataConnectionState_invalid() =
runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: DataConnectionState? = null
+ val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
val callback =
getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
callback.onDataConnectionStateChanged(45, 200 /* unused */)
- assertThat(latest?.dataConnectionState).isEqualTo(DataConnectionState.Invalid)
+ assertThat(latest).isEqualTo(DataConnectionState.Invalid)
job.cancel()
}
@Test
- fun testFlowForSubId_dataActivity() =
+ fun dataActivity() =
runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: DataActivityModel? = null
+ val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
val callback = getTelephonyCallbackForType<DataActivityListener>()
callback.onDataActivity(DATA_ACTIVITY_INOUT)
- assertThat(latest?.dataActivityDirection)
- .isEqualTo(DATA_ACTIVITY_INOUT.toMobileDataActivityModel())
+ assertThat(latest).isEqualTo(DATA_ACTIVITY_INOUT.toMobileDataActivityModel())
job.cancel()
}
@Test
- fun testFlowForSubId_carrierNetworkChange() =
+ fun carrierNetworkChange() =
runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: Boolean? = null
+ val job = underTest.carrierNetworkChangeActive.onEach { latest = it }.launchIn(this)
val callback = getTelephonyCallbackForType<TelephonyCallback.CarrierNetworkListener>()
callback.onCarrierNetworkChange(true)
- assertThat(latest?.carrierNetworkChangeActive).isEqualTo(true)
+ assertThat(latest).isEqualTo(true)
+
+ job.cancel()
+ }
+
+ @Test
+ fun networkType_default() =
+ runBlocking(IMMEDIATE) {
+ var latest: ResolvedNetworkType? = null
+ val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
+
+ val expected = UnknownNetworkType
+
+ assertThat(latest).isEqualTo(expected)
job.cancel()
}
@Test
- fun subscriptionFlow_networkType_default() =
+ fun networkType_unknown_hasCorrectKey() =
runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: ResolvedNetworkType? = null
+ val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
+ val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
+ val type = NETWORK_TYPE_UNKNOWN
val expected = UnknownNetworkType
+ val ti = mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type) }
+ callback.onDisplayInfoChanged(ti)
- assertThat(latest?.resolvedNetworkType).isEqualTo(expected)
+ assertThat(latest).isEqualTo(expected)
+ assertThat(latest!!.lookupKey).isEqualTo(MobileMappings.toIconKey(type))
job.cancel()
}
@Test
- fun subscriptionFlow_networkType_updatesUsingDefault() =
+ fun networkType_updatesUsingDefault() =
runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: ResolvedNetworkType? = null
+ val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
val type = NETWORK_TYPE_LTE
@@ -371,16 +423,16 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
val ti = mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type) }
callback.onDisplayInfoChanged(ti)
- assertThat(latest?.resolvedNetworkType).isEqualTo(expected)
+ assertThat(latest).isEqualTo(expected)
job.cancel()
}
@Test
- fun subscriptionFlow_networkType_updatesUsingOverride() =
+ fun networkType_updatesUsingOverride() =
runBlocking(IMMEDIATE) {
- var latest: MobileConnectionModel? = null
- val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+ var latest: ResolvedNetworkType? = null
+ val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
val type = OVERRIDE_NETWORK_TYPE_LTE_CA
@@ -392,7 +444,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
}
callback.onDisplayInfoChanged(ti)
- assertThat(latest?.resolvedNetworkType).isEqualTo(expected)
+ assertThat(latest).isEqualTo(expected)
job.cancel()
}
@@ -466,7 +518,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
fun `roaming - gsm - queries service state`() =
runBlocking(IMMEDIATE) {
var latest: Boolean? = null
- val job = underTest.connectionInfo.onEach { latest = it.isRoaming }.launchIn(this)
+ val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
val serviceState = ServiceState()
serviceState.roaming = false
@@ -492,8 +544,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
fun `activity - updates from callback`() =
runBlocking(IMMEDIATE) {
var latest: DataActivityModel? = null
- val job =
- underTest.connectionInfo.onEach { latest = it.dataActivityDirection }.launchIn(this)
+ val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
assertThat(latest)
.isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
@@ -611,8 +662,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
runBlocking(IMMEDIATE) {
var latest: String? = null
- val job =
- underTest.connectionInfo.onEach { latest = it.operatorAlphaShort }.launchIn(this)
+ val job = underTest.operatorAlphaShort.onEach { latest = it }.launchIn(this)
val shortName = "short name"
val serviceState = ServiceState()
@@ -633,7 +683,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
fun `connection model - isInService - not iwlan`() =
runBlocking(IMMEDIATE) {
var latest: Boolean? = null
- val job = underTest.connectionInfo.onEach { latest = it.isInService }.launchIn(this)
+ val job = underTest.isInService.onEach { latest = it }.launchIn(this)
val serviceState = ServiceState()
serviceState.voiceRegState = STATE_IN_SERVICE
@@ -658,7 +708,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
fun `connection model - isInService - is iwlan - voice out of service - data in service`() =
runBlocking(IMMEDIATE) {
var latest: Boolean? = null
- val job = underTest.connectionInfo.onEach { latest = it.isInService }.launchIn(this)
+ val job = underTest.isInService.onEach { latest = it }.launchIn(this)
// Mock the service state here so we can make it specifically IWLAN
val serviceState: ServiceState = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 09b7a66c925d..68b1cda62f4c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -37,12 +37,12 @@ import com.android.settingslib.mobile.MobileMappings
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.tableBufferLogName
-import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index fa072fc366eb..1eb1056204cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -23,7 +23,6 @@ import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.CarrierMergedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
@@ -74,9 +73,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
@Test
fun gsm_level_default_unknown() =
runBlocking(IMMEDIATE) {
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(isGsm = true),
- )
+ connectionRepository.isGsm.value = true
var latest: Int? = null
val job = underTest.level.onEach { latest = it }.launchIn(this)
@@ -89,13 +86,9 @@ class MobileIconInteractorTest : SysuiTestCase() {
@Test
fun gsm_usesGsmLevel() =
runBlocking(IMMEDIATE) {
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- isGsm = true,
- primaryLevel = GSM_LEVEL,
- cdmaLevel = CDMA_LEVEL
- ),
- )
+ connectionRepository.isGsm.value = true
+ connectionRepository.primaryLevel.value = GSM_LEVEL
+ connectionRepository.cdmaLevel.value = CDMA_LEVEL
var latest: Int? = null
val job = underTest.level.onEach { latest = it }.launchIn(this)
@@ -108,13 +101,9 @@ class MobileIconInteractorTest : SysuiTestCase() {
@Test
fun gsm_alwaysShowCdmaTrue_stillUsesGsmLevel() =
runBlocking(IMMEDIATE) {
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- isGsm = true,
- primaryLevel = GSM_LEVEL,
- cdmaLevel = CDMA_LEVEL,
- ),
- )
+ connectionRepository.isGsm.value = true
+ connectionRepository.primaryLevel.value = GSM_LEVEL
+ connectionRepository.cdmaLevel.value = CDMA_LEVEL
mobileIconsInteractor.alwaysUseCdmaLevel.value = true
var latest: Int? = null
@@ -128,9 +117,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
@Test
fun notGsm_level_default_unknown() =
runBlocking(IMMEDIATE) {
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(isGsm = false),
- )
+ connectionRepository.isGsm.value = false
var latest: Int? = null
val job = underTest.level.onEach { latest = it }.launchIn(this)
@@ -142,13 +129,9 @@ class MobileIconInteractorTest : SysuiTestCase() {
@Test
fun notGsm_alwaysShowCdmaTrue_usesCdmaLevel() =
runBlocking(IMMEDIATE) {
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- isGsm = false,
- primaryLevel = GSM_LEVEL,
- cdmaLevel = CDMA_LEVEL
- ),
- )
+ connectionRepository.isGsm.value = false
+ connectionRepository.primaryLevel.value = GSM_LEVEL
+ connectionRepository.cdmaLevel.value = CDMA_LEVEL
mobileIconsInteractor.alwaysUseCdmaLevel.value = true
var latest: Int? = null
@@ -162,13 +145,9 @@ class MobileIconInteractorTest : SysuiTestCase() {
@Test
fun notGsm_alwaysShowCdmaFalse_usesPrimaryLevel() =
runBlocking(IMMEDIATE) {
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- isGsm = false,
- primaryLevel = GSM_LEVEL,
- cdmaLevel = CDMA_LEVEL,
- ),
- )
+ connectionRepository.isGsm.value = false
+ connectionRepository.primaryLevel.value = GSM_LEVEL
+ connectionRepository.cdmaLevel.value = CDMA_LEVEL
mobileIconsInteractor.alwaysUseCdmaLevel.value = false
var latest: Int? = null
@@ -197,11 +176,8 @@ class MobileIconInteractorTest : SysuiTestCase() {
@Test
fun iconGroup_three_g() =
runBlocking(IMMEDIATE) {
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- resolvedNetworkType = DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
- ),
- )
+ connectionRepository.resolvedNetworkType.value =
+ DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
var latest: MobileIconGroup? = null
val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
@@ -214,23 +190,14 @@ class MobileIconInteractorTest : SysuiTestCase() {
@Test
fun iconGroup_updates_on_change() =
runBlocking(IMMEDIATE) {
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- resolvedNetworkType = DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
- ),
- )
+ connectionRepository.resolvedNetworkType.value =
+ DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
var latest: MobileIconGroup? = null
val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- resolvedNetworkType =
- DefaultNetworkType(
- mobileMappingsProxy.toIconKey(FOUR_G),
- ),
- ),
- )
+ connectionRepository.resolvedNetworkType.value =
+ DefaultNetworkType(mobileMappingsProxy.toIconKey(FOUR_G))
yield()
assertThat(latest).isEqualTo(TelephonyIcons.FOUR_G)
@@ -241,12 +208,8 @@ class MobileIconInteractorTest : SysuiTestCase() {
@Test
fun iconGroup_5g_override_type() =
runBlocking(IMMEDIATE) {
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- resolvedNetworkType =
- OverrideNetworkType(mobileMappingsProxy.toIconKeyOverride(FIVE_G_OVERRIDE))
- ),
- )
+ connectionRepository.resolvedNetworkType.value =
+ OverrideNetworkType(mobileMappingsProxy.toIconKeyOverride(FIVE_G_OVERRIDE))
var latest: MobileIconGroup? = null
val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
@@ -259,12 +222,8 @@ class MobileIconInteractorTest : SysuiTestCase() {
@Test
fun iconGroup_default_if_no_lookup() =
runBlocking(IMMEDIATE) {
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- resolvedNetworkType =
- DefaultNetworkType(mobileMappingsProxy.toIconKey(NETWORK_TYPE_UNKNOWN)),
- ),
- )
+ connectionRepository.resolvedNetworkType.value =
+ DefaultNetworkType(mobileMappingsProxy.toIconKey(NETWORK_TYPE_UNKNOWN))
var latest: MobileIconGroup? = null
val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
@@ -277,11 +236,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
@Test
fun iconGroup_carrierMerged_usesOverride() =
runBlocking(IMMEDIATE) {
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- resolvedNetworkType = CarrierMergedNetworkType,
- ),
- )
+ connectionRepository.resolvedNetworkType.value = CarrierMergedNetworkType
var latest: MobileIconGroup? = null
val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
@@ -295,11 +250,8 @@ class MobileIconInteractorTest : SysuiTestCase() {
fun `icon group - checks default data`() =
runBlocking(IMMEDIATE) {
mobileIconsInteractor.defaultDataSubId.value = SUB_1_ID
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- resolvedNetworkType = DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
- ),
- )
+ connectionRepository.resolvedNetworkType.value =
+ DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
var latest: MobileIconGroup? = null
val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
@@ -380,9 +332,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
var latest: Boolean? = null
val job = underTest.isDataConnected.onEach { latest = it }.launchIn(this)
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(dataConnectionState = DataConnectionState.Connected)
- )
+ connectionRepository.dataConnectionState.value = DataConnectionState.Connected
yield()
assertThat(latest).isTrue()
@@ -396,9 +346,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
var latest: Boolean? = null
val job = underTest.isDataConnected.onEach { latest = it }.launchIn(this)
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(dataConnectionState = DataConnectionState.Disconnected)
- )
+ connectionRepository.dataConnectionState.value = DataConnectionState.Disconnected
assertThat(latest).isFalse()
@@ -411,11 +359,11 @@ class MobileIconInteractorTest : SysuiTestCase() {
var latest: Boolean? = null
val job = underTest.isInService.onEach { latest = it }.launchIn(this)
- connectionRepository.setConnectionInfo(MobileConnectionModel(isInService = true))
+ connectionRepository.isInService.value = true
assertThat(latest).isTrue()
- connectionRepository.setConnectionInfo(MobileConnectionModel(isInService = false))
+ connectionRepository.isInService.value = false
assertThat(latest).isFalse()
@@ -429,22 +377,13 @@ class MobileIconInteractorTest : SysuiTestCase() {
val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
connectionRepository.cdmaRoaming.value = true
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- isGsm = true,
- isRoaming = false,
- )
- )
+ connectionRepository.isGsm.value = true
+ connectionRepository.isRoaming.value = false
yield()
assertThat(latest).isFalse()
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- isGsm = true,
- isRoaming = true,
- )
- )
+ connectionRepository.isRoaming.value = true
yield()
assertThat(latest).isTrue()
@@ -459,23 +398,15 @@ class MobileIconInteractorTest : SysuiTestCase() {
val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
connectionRepository.cdmaRoaming.value = false
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- isGsm = false,
- isRoaming = true,
- )
- )
+ connectionRepository.isGsm.value = false
+ connectionRepository.isRoaming.value = true
yield()
assertThat(latest).isFalse()
connectionRepository.cdmaRoaming.value = true
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- isGsm = false,
- isRoaming = false,
- )
- )
+ connectionRepository.isGsm.value = false
+ connectionRepository.isRoaming.value = false
yield()
assertThat(latest).isTrue()
@@ -490,25 +421,15 @@ class MobileIconInteractorTest : SysuiTestCase() {
val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
connectionRepository.cdmaRoaming.value = true
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- isGsm = false,
- isRoaming = true,
- carrierNetworkChangeActive = true,
- )
- )
+ connectionRepository.isGsm.value = false
+ connectionRepository.isRoaming.value = true
+ connectionRepository.carrierNetworkChangeActive.value = true
yield()
assertThat(latest).isFalse()
connectionRepository.cdmaRoaming.value = true
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(
- isGsm = true,
- isRoaming = true,
- carrierNetworkChangeActive = true,
- )
- )
+ connectionRepository.isGsm.value = true
yield()
assertThat(latest).isFalse()
@@ -526,24 +447,20 @@ class MobileIconInteractorTest : SysuiTestCase() {
// Default network name, operator name is non-null, uses the operator name
connectionRepository.networkName.value = DEFAULT_NAME
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(operatorAlphaShort = testOperatorName)
- )
+ connectionRepository.operatorAlphaShort.value = testOperatorName
yield()
assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived(testOperatorName))
// Default network name, operator name is null, uses the default
- connectionRepository.setConnectionInfo(MobileConnectionModel(operatorAlphaShort = null))
+ connectionRepository.operatorAlphaShort.value = null
yield()
assertThat(latest).isEqualTo(DEFAULT_NAME)
// Derived network name, operator name non-null, uses the derived name
connectionRepository.networkName.value = DERIVED_NAME
- connectionRepository.setConnectionInfo(
- MobileConnectionModel(operatorAlphaShort = testOperatorName)
- )
+ connectionRepository.operatorAlphaShort.value = testOperatorName
yield()
assertThat(latest).isEqualTo(DERIVED_NAME)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt
new file mode 100644
index 000000000000..4aa48d6f25f1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt
@@ -0,0 +1,100 @@
+/*
+ * 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.pipeline.mobile.ui
+
+import android.widget.TextView
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger.Companion.getIdForLogging
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.KeyguardMobileIconViewModel
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.QsMobileIconViewModel
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class MobileViewLoggerTest : SysuiTestCase() {
+ private val buffer = LogBufferFactory(DumpManager(), mock()).create("buffer", 10)
+ private val stringWriter = StringWriter()
+ private val printWriter = PrintWriter(stringWriter)
+
+ private val underTest = MobileViewLogger(buffer, mock())
+
+ @Mock private lateinit var flags: StatusBarPipelineFlags
+ @Mock private lateinit var commonViewModel: MobileIconViewModel
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun collectionStarted_dumpHasInfo() {
+ val view = TextView(context)
+ val viewModel = QsMobileIconViewModel(commonViewModel, flags)
+
+ underTest.logCollectionStarted(view, viewModel)
+
+ val dumpString = getDumpString()
+ assertThat(dumpString).contains("${view.getIdForLogging()}, isCollecting=true")
+ }
+
+ @Test
+ fun collectionStarted_multipleViews_dumpHasInfo() {
+ val view = TextView(context)
+ val view2 = TextView(context)
+ val viewModel = QsMobileIconViewModel(commonViewModel, flags)
+ val viewModel2 = KeyguardMobileIconViewModel(commonViewModel, flags)
+
+ underTest.logCollectionStarted(view, viewModel)
+ underTest.logCollectionStarted(view2, viewModel2)
+
+ val dumpString = getDumpString()
+ assertThat(dumpString).contains("${view.getIdForLogging()}, isCollecting=true")
+ assertThat(dumpString).contains("${view2.getIdForLogging()}, isCollecting=true")
+ }
+
+ @Test
+ fun collectionStopped_dumpHasInfo() {
+ val view = TextView(context)
+ val view2 = TextView(context)
+ val viewModel = QsMobileIconViewModel(commonViewModel, flags)
+ val viewModel2 = KeyguardMobileIconViewModel(commonViewModel, flags)
+
+ underTest.logCollectionStarted(view, viewModel)
+ underTest.logCollectionStarted(view2, viewModel2)
+ underTest.logCollectionStopped(view, viewModel)
+
+ val dumpString = getDumpString()
+ assertThat(dumpString).contains("${view.getIdForLogging()}, isCollecting=false")
+ assertThat(dumpString).contains("${view2.getIdForLogging()}, isCollecting=true")
+ }
+
+ private fun getDumpString(): String {
+ underTest.dump(printWriter, args = arrayOf())
+ return stringWriter.toString()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt
index e68a3970ae93..7420db2e895e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt
@@ -32,6 +32,7 @@ import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.QsMobileIconViewModel
@@ -60,6 +61,7 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() {
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
@Mock private lateinit var tableLogBuffer: TableLogBuffer
+ @Mock private lateinit var viewLogger: MobileViewLogger
@Mock private lateinit var constants: ConnectivityConstants
private lateinit var interactor: FakeMobileIconInteractor
private lateinit var airplaneModeRepository: FakeAirplaneModeRepository
@@ -94,7 +96,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() {
@Test
fun setVisibleState_icon_iconShownDotHidden() {
- val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
+ val view =
+ ModernStatusBarMobileView.constructAndBind(
+ context,
+ viewLogger,
+ SLOT_NAME,
+ viewModel,
+ )
view.setVisibleState(StatusBarIconView.STATE_ICON, /* animate= */ false)
@@ -109,8 +117,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() {
@Test
fun setVisibleState_dot_iconHiddenDotShown() {
- val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
-
+ val view =
+ ModernStatusBarMobileView.constructAndBind(
+ context,
+ viewLogger,
+ SLOT_NAME,
+ viewModel,
+ )
view.setVisibleState(StatusBarIconView.STATE_DOT, /* animate= */ false)
ViewUtils.attachView(view)
@@ -124,8 +137,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() {
@Test
fun setVisibleState_hidden_iconAndDotHidden() {
- val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
-
+ val view =
+ ModernStatusBarMobileView.constructAndBind(
+ context,
+ viewLogger,
+ SLOT_NAME,
+ viewModel,
+ )
view.setVisibleState(StatusBarIconView.STATE_HIDDEN, /* animate= */ false)
ViewUtils.attachView(view)
@@ -142,8 +160,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() {
whenever(constants.hasDataCapabilities).thenReturn(false)
createViewModel()
- val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
-
+ val view =
+ ModernStatusBarMobileView.constructAndBind(
+ context,
+ viewLogger,
+ SLOT_NAME,
+ viewModel,
+ )
ViewUtils.attachView(view)
testableLooper.processAllMessages()
@@ -157,8 +180,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() {
whenever(constants.hasDataCapabilities).thenReturn(true)
createViewModel()
- val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
-
+ val view =
+ ModernStatusBarMobileView.constructAndBind(
+ context,
+ viewLogger,
+ SLOT_NAME,
+ viewModel,
+ )
ViewUtils.attachView(view)
testableLooper.processAllMessages()
@@ -171,8 +199,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() {
fun isIconVisible_notAirplaneMode_outputsTrue() {
airplaneModeRepository.setIsAirplaneMode(false)
- val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
-
+ val view =
+ ModernStatusBarMobileView.constructAndBind(
+ context,
+ viewLogger,
+ SLOT_NAME,
+ viewModel,
+ )
ViewUtils.attachView(view)
testableLooper.processAllMessages()
@@ -185,8 +218,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() {
fun isIconVisible_airplaneMode_outputsTrue() {
airplaneModeRepository.setIsAirplaneMode(true)
- val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
-
+ val view =
+ ModernStatusBarMobileView.constructAndBind(
+ context,
+ viewLogger,
+ SLOT_NAME,
+ viewModel,
+ )
ViewUtils.attachView(view)
testableLooper.processAllMessages()
@@ -198,7 +236,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() {
@Test
fun onDarkChanged_iconHasNewColor() {
whenever(statusBarPipelineFlags.useDebugColoring()).thenReturn(false)
- val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
+ val view =
+ ModernStatusBarMobileView.constructAndBind(
+ context,
+ viewLogger,
+ SLOT_NAME,
+ viewModel,
+ )
ViewUtils.attachView(view)
testableLooper.processAllMessages()
@@ -214,7 +258,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() {
@Test
fun setStaticDrawableColor_iconHasNewColor() {
whenever(statusBarPipelineFlags.useDebugColoring()).thenReturn(false)
- val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
+ val view =
+ ModernStatusBarMobileView.constructAndBind(
+ context,
+ viewLogger,
+ SLOT_NAME,
+ viewModel,
+ )
ViewUtils.attachView(view)
testableLooper.processAllMessages()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
index f9830309252d..a6d915243f60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
@@ -28,6 +28,7 @@ import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModelTest.Companion.defaultSignal
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
@@ -84,7 +85,7 @@ class LocationBasedMobileIconViewModelTest : SysuiTestCase() {
testScope.backgroundScope,
)
- homeIcon = HomeMobileIconViewModel(commonImpl, statusBarPipelineFlags)
+ homeIcon = HomeMobileIconViewModel(commonImpl, statusBarPipelineFlags, mock())
qsIcon = QsMobileIconViewModel(commonImpl, statusBarPipelineFlags)
keyguardIcon = KeyguardMobileIconViewModel(commonImpl, statusBarPipelineFlags)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
index 4628f8410245..ddb7f4d88d30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
@@ -24,6 +24,8 @@ import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirp
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
+import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
@@ -51,6 +53,8 @@ class MobileIconsViewModelTest : SysuiTestCase() {
private lateinit var airplaneModeInteractor: AirplaneModeInteractor
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
@Mock private lateinit var constants: ConnectivityConstants
+ @Mock private lateinit var logger: MobileViewLogger
+ @Mock private lateinit var verboseLogger: VerboseMobileViewLogger
private val testDispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(testDispatcher)
@@ -73,6 +77,8 @@ class MobileIconsViewModelTest : SysuiTestCase() {
underTest =
MobileIconsViewModel(
subscriptionIdsFlow,
+ logger,
+ verboseLogger,
interactor,
airplaneModeInteractor,
constants,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt
index e4c8fd0cd8a1..b4039d906810 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt
@@ -164,6 +164,10 @@ class ModernStatusBarViewTest : SysuiTestCase() {
override fun getShouldIconBeVisible(): Boolean {
return shouldIconBeVisibleInternal
}
+
+ override fun isCollecting(): Boolean {
+ return true
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
index 48b17322da4d..481d453fa0b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
@@ -38,6 +38,7 @@ import com.android.internal.R;
import com.android.internal.view.RotationPolicy;
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.wrapper.RotationPolicyWrapper;
@@ -55,10 +56,12 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
private static final String[] DEFAULT_SETTINGS = new String[]{"0:1", "2:0:1", "1:2"};
+ @Mock private DeviceStateManager mDeviceStateManager;
+ @Mock private DeviceStateRotationLockSettingControllerLogger mLogger;
+ @Mock private DumpManager mDumpManager;
+
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private final FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock);
- @Mock
- private DeviceStateManager mDeviceStateManager;
private final RotationPolicyWrapper mFakeRotationPolicy = new FakeRotationPolicy();
private DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
private DeviceStateManager.DeviceStateCallback mDeviceStateCallback;
@@ -78,7 +81,13 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
mSettingsManager = DeviceStateRotationLockSettingsManager.getInstance(mContext);
mDeviceStateRotationLockSettingController =
new DeviceStateRotationLockSettingController(
- mFakeRotationPolicy, mDeviceStateManager, mFakeExecutor, mSettingsManager);
+ mFakeRotationPolicy,
+ mDeviceStateManager,
+ mFakeExecutor,
+ mSettingsManager,
+ mLogger,
+ mDumpManager
+ );
mDeviceStateRotationLockSettingController.setListening(true);
verify(mDeviceStateManager)
@@ -173,15 +182,11 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
}
@Test
- public void whenDeviceStateSwitchedToIgnoredState_usePreviousSetting() {
- initializeSettingsWith(
- 0, DEVICE_STATE_ROTATION_LOCK_IGNORED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
- mFakeRotationPolicy.setRotationLock(true);
-
- mDeviceStateCallback.onStateChanged(1);
- assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
-
+ public void whenDeviceStateSwitchedToIgnoredState_useFallbackSetting() {
mDeviceStateCallback.onStateChanged(0);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
+
+ mDeviceStateCallback.onStateChanged(2);
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
index 5288608a202d..0413d92b6abb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
@@ -25,7 +25,6 @@ import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_OPENING
-import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
import com.android.systemui.unfold.util.TestFoldStateProvider
import org.junit.Before
import org.junit.Test
@@ -50,7 +49,7 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
runOnMainThreadWithInterval(
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
{ foldStateProvider.sendHingeAngleUpdate(10f) },
- { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) },
+ { foldStateProvider.sendUnfoldedScreenAvailable() },
{ foldStateProvider.sendHingeAngleUpdate(90f) },
{ foldStateProvider.sendHingeAngleUpdate(180f) },
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) },
@@ -67,7 +66,7 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
runOnMainThreadWithInterval(
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
{ foldStateProvider.sendHingeAngleUpdate(10f) },
- { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) },
+ { foldStateProvider.sendUnfoldedScreenAvailable() },
{ foldStateProvider.sendHingeAngleUpdate(90f) },
{ foldStateProvider.sendHingeAngleUpdate(180f) },
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) },
@@ -84,7 +83,7 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
{ foldStateProvider.sendHingeAngleUpdate(90f) },
{ foldStateProvider.sendHingeAngleUpdate(180f) },
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) },
- { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) },
+ { foldStateProvider.sendUnfoldedScreenAvailable() },
)
with(listener.ensureTransitionFinished()) {
@@ -113,7 +112,7 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
fun testUnfoldAndStopUnfolding_finishesTheUnfoldTransition() {
runOnMainThreadWithInterval(
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
- { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) },
+ { foldStateProvider.sendUnfoldedScreenAvailable() },
{ foldStateProvider.sendHingeAngleUpdate(10f) },
{ foldStateProvider.sendHingeAngleUpdate(90f) },
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN) },
@@ -129,7 +128,7 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
fun testFoldImmediatelyAfterUnfold_runsFoldAnimation() {
runOnMainThreadWithInterval(
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
- { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) },
+ { foldStateProvider.sendUnfoldedScreenAvailable() },
{ foldStateProvider.sendHingeAngleUpdate(10f) },
{ foldStateProvider.sendHingeAngleUpdate(90f) },
{
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
index 6086e16fb49a..8476d0d45603 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
@@ -26,6 +26,7 @@ import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.system.ActivityManagerActivityTypeProvider
import com.android.systemui.unfold.updates.FoldProvider.FoldCallback
import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListener
+import com.android.systemui.unfold.updates.hinge.FULLY_OPEN_DEGREES
import com.android.systemui.unfold.updates.hinge.HingeAngleProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
@@ -71,6 +72,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
private val foldUpdates: MutableList<Int> = arrayListOf()
private val hingeAngleUpdates: MutableList<Float> = arrayListOf()
+ private val unfoldedScreenAvailabilityUpdates: MutableList<Unit> = arrayListOf()
private var scheduledRunnable: Runnable? = null
private var scheduledRunnableDelay: Long? = null
@@ -106,6 +108,10 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
override fun onFoldUpdate(update: Int) {
foldUpdates.add(update)
}
+
+ override fun onUnfoldedScreenAvailable() {
+ unfoldedScreenAvailabilityUpdates.add(Unit)
+ }
})
foldStateProvider.start()
@@ -156,8 +162,8 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
sendHingeAngleEvent(10)
screenOnStatusProvider.notifyScreenTurnedOn()
- assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_OPENING,
- FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE)
+ assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_OPENING)
+ assertThat(unfoldedScreenAvailabilityUpdates).hasSize(1)
}
@Test
@@ -174,8 +180,9 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
sendHingeAngleEvent(40)
sendHingeAngleEvent(10)
- assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_OPENING,
- FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE, FOLD_UPDATE_START_CLOSING)
+ assertThat(foldUpdates)
+ .containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING)
+ assertThat(unfoldedScreenAvailabilityUpdates).hasSize(1)
}
@Test
@@ -223,7 +230,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
fireScreenOnEvent()
- assertThat(foldUpdates).containsExactly(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE)
+ assertThat(unfoldedScreenAvailabilityUpdates).hasSize(1)
}
@Test
@@ -277,7 +284,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
@Test
fun startClosingEvent_afterTimeout_finishHalfOpenEventEmitted() {
- sendHingeAngleEvent(90)
+ setInitialHingeAngle(90)
sendHingeAngleEvent(80)
simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS)
@@ -288,7 +295,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
@Test
fun startClosingEvent_beforeTimeout_abortNotEmitted() {
- sendHingeAngleEvent(90)
+ setInitialHingeAngle(90)
sendHingeAngleEvent(80)
simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS - 1)
@@ -298,7 +305,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
@Test
fun startClosingEvent_eventBeforeTimeout_oneEventEmitted() {
- sendHingeAngleEvent(180)
+ setInitialHingeAngle(180)
sendHingeAngleEvent(90)
simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS - 1)
@@ -309,7 +316,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
@Test
fun startClosingEvent_timeoutAfterTimeoutRescheduled_finishHalfOpenStateEmitted() {
- sendHingeAngleEvent(180)
+ setInitialHingeAngle(180)
sendHingeAngleEvent(90)
// The timeout should not trigger here.
@@ -323,7 +330,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
@Test
fun startClosingEvent_shortTimeBetween_emitsOnlyOneEvents() {
- sendHingeAngleEvent(180)
+ setInitialHingeAngle(180)
sendHingeAngleEvent(90)
sendHingeAngleEvent(80)
@@ -334,20 +341,19 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
@Test
fun startClosingEvent_whileClosing_emittedDespiteInitialAngle() {
val maxAngle = 180 - FULLY_OPEN_THRESHOLD_DEGREES.toInt()
- for (i in 1..maxAngle) {
- foldUpdates.clear()
-
- simulateFolding(startAngle = i)
+ val minAngle = Math.ceil(HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toDouble()).toInt() + 1
+ for (startAngle in minAngle..maxAngle) {
+ setInitialHingeAngle(startAngle)
+ sendHingeAngleEvent(startAngle - HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() - 1)
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
- simulateTimeout() // Timeout to set the state to aborted.
}
}
@Test
fun startClosingEvent_whileNotOnLauncher_doesNotTriggerBeforeThreshold() {
setupForegroundActivityType(isHomeActivity = false)
- sendHingeAngleEvent(180)
+ setInitialHingeAngle(180)
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
@@ -357,7 +363,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
@Test
fun startClosingEvent_whileActivityTypeNotAvailable_triggerBeforeThreshold() {
setupForegroundActivityType(isHomeActivity = null)
- sendHingeAngleEvent(180)
+ setInitialHingeAngle(180)
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
@@ -367,7 +373,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
@Test
fun startClosingEvent_whileOnLauncher_doesTriggerBeforeThreshold() {
setupForegroundActivityType(isHomeActivity = true)
- sendHingeAngleEvent(180)
+ setInitialHingeAngle(180)
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
@@ -377,9 +383,11 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
@Test
fun startClosingEvent_whileNotOnLauncher_triggersAfterThreshold() {
setupForegroundActivityType(isHomeActivity = false)
- sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
+ setInitialHingeAngle(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
- sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES - 1)
+ sendHingeAngleEvent(
+ START_CLOSING_ON_APPS_THRESHOLD_DEGREES -
+ HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() - 1)
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
}
@@ -388,7 +396,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
fun startClosingEvent_whileNotOnKeyguardAndNotOnLauncher_doesNotTriggerBeforeThreshold() {
setKeyguardVisibility(visible = false)
setupForegroundActivityType(isHomeActivity = false)
- sendHingeAngleEvent(180)
+ setInitialHingeAngle(180)
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
@@ -398,7 +406,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
@Test
fun startClosingEvent_whileKeyguardStateNotAvailable_triggerBeforeThreshold() {
setKeyguardVisibility(visible = null)
- sendHingeAngleEvent(180)
+ setInitialHingeAngle(180)
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
@@ -408,7 +416,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
@Test
fun startClosingEvent_whileonKeyguard_doesTriggerBeforeThreshold() {
setKeyguardVisibility(visible = true)
- sendHingeAngleEvent(180)
+ setInitialHingeAngle(180)
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
@@ -418,9 +426,59 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
@Test
fun startClosingEvent_whileNotOnKeyguard_triggersAfterThreshold() {
setKeyguardVisibility(visible = false)
- sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
+ setInitialHingeAngle(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
- sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES - 1)
+ sendHingeAngleEvent(
+ START_CLOSING_ON_APPS_THRESHOLD_DEGREES -
+ HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() - 1)
+
+ assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
+ }
+
+ @Test
+ fun startClosingEvent_doesNotTriggerBelowThreshold() {
+ val thresholdAngle = (FULLY_OPEN_DEGREES - FULLY_OPEN_THRESHOLD_DEGREES).toInt()
+ setInitialHingeAngle(180)
+ sendHingeAngleEvent(thresholdAngle + 1)
+
+ assertThat(foldUpdates).isEmpty()
+ }
+
+ @Test
+ fun startClosingEvent_triggersAfterThreshold() {
+ val thresholdAngle = (FULLY_OPEN_DEGREES - FULLY_OPEN_THRESHOLD_DEGREES).toInt()
+ setInitialHingeAngle(180)
+ sendHingeAngleEvent(thresholdAngle + 1)
+ sendHingeAngleEvent(thresholdAngle - 1)
+
+ assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
+ }
+
+ @Test
+ fun startClosingEvent_triggersAfterThreshold_fromHalfOpen() {
+ setInitialHingeAngle(120)
+ sendHingeAngleEvent((120 - HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES + 1).toInt())
+ assertThat(foldUpdates).isEmpty()
+ sendHingeAngleEvent((120 - HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES - 1).toInt())
+
+ assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
+ }
+
+ @Test
+ fun startOpeningAndClosingEvents_triggerWithOpenAndClose() {
+ setInitialHingeAngle(120)
+ sendHingeAngleEvent(130)
+ sendHingeAngleEvent(120)
+ assertThat(foldUpdates)
+ .containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING)
+ }
+
+ @Test
+ fun startClosingEvent_notInterrupted_whenAngleIsSlightlyIncreased() {
+ setInitialHingeAngle(120)
+ sendHingeAngleEvent(110)
+ sendHingeAngleEvent(111)
+ sendHingeAngleEvent(100)
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
}
@@ -504,11 +562,6 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
}
}
- private fun simulateFolding(startAngle: Int) {
- sendHingeAngleEvent(startAngle)
- sendHingeAngleEvent(startAngle - 1)
- }
-
private fun setFoldState(folded: Boolean) {
foldProvider.notifyFolded(folded)
}
@@ -521,6 +574,17 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
testHingeAngleProvider.notifyAngle(angle.toFloat())
}
+ private fun setInitialHingeAngle(angle: Int) {
+ setFoldState(angle == 0)
+ sendHingeAngleEvent(angle)
+ if (scheduledRunnableDelay != null) {
+ simulateTimeout()
+ }
+ hingeAngleUpdates.clear()
+ foldUpdates.clear()
+ unfoldedScreenAvailabilityUpdates.clear()
+ }
+
private class TestFoldProvider : FoldProvider {
private val callbacks = arrayListOf<FoldCallback>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
index 85cfef727954..fd368eb07b5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
@@ -16,22 +16,24 @@
package com.android.systemui.unfold.updates
+import android.content.Context
+import android.hardware.display.DisplayManager
+import android.os.Looper
import android.testing.AndroidTestingRunner
-import android.view.IRotationWatcher
-import android.view.IWindowManager
+import android.view.Display
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListener
-import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.utils.os.FakeHandler
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Captor
import org.mockito.Mock
+import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
@@ -42,19 +44,23 @@ class RotationChangeProviderTest : SysuiTestCase() {
private lateinit var rotationChangeProvider: RotationChangeProvider
- @Mock lateinit var windowManagerInterface: IWindowManager
+ @Mock lateinit var displayManager: DisplayManager
@Mock lateinit var listener: RotationListener
- @Captor lateinit var rotationWatcher: ArgumentCaptor<IRotationWatcher>
- private val fakeExecutor = FakeExecutor(FakeSystemClock())
+ @Mock lateinit var display: Display
+ @Captor lateinit var displayListener: ArgumentCaptor<DisplayManager.DisplayListener>
+ private val fakeHandler = FakeHandler(Looper.getMainLooper())
+
+ private lateinit var spyContext: Context
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- rotationChangeProvider =
- RotationChangeProvider(windowManagerInterface, context, fakeExecutor)
+ spyContext = spy(context)
+ whenever(spyContext.display).thenReturn(display)
+ rotationChangeProvider = RotationChangeProvider(displayManager, spyContext, fakeHandler)
rotationChangeProvider.addCallback(listener)
- fakeExecutor.runAllReady()
- verify(windowManagerInterface).watchRotation(rotationWatcher.capture(), anyInt())
+ fakeHandler.dispatchQueuedMessages()
+ verify(displayManager).registerDisplayListener(displayListener.capture(), any())
}
@Test
@@ -70,15 +76,16 @@ class RotationChangeProviderTest : SysuiTestCase() {
verify(listener).onRotationChanged(42)
rotationChangeProvider.removeCallback(listener)
- fakeExecutor.runAllReady()
+ fakeHandler.dispatchQueuedMessages()
sendRotationUpdate(43)
- verify(windowManagerInterface).removeRotationWatcher(any())
+ verify(displayManager).unregisterDisplayListener(any())
verifyNoMoreInteractions(listener)
}
private fun sendRotationUpdate(newRotation: Int) {
- rotationWatcher.value.onRotationChanged(newRotation)
- fakeExecutor.runAllReady()
+ whenever(display.rotation).thenReturn(newRotation)
+ displayListener.allValues.forEach { it.onDisplayChanged(display.displayId) }
+ fakeHandler.dispatchQueuedMessages()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
index a064e8c81076..fbb0e5a72cd1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
@@ -57,4 +57,8 @@ class TestFoldStateProvider : FoldStateProvider {
fun sendHingeAngleUpdate(angle: Float) {
listeners.forEach { it.onHingeAngleUpdate(angle) }
}
+
+ fun sendUnfoldedScreenAvailable() {
+ listeners.forEach { it.onUnfoldedScreenAvailable() }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
index ccf378a71abd..ddd880b8037c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
@@ -17,10 +17,7 @@
package com.android.systemui.user.data.repository
-import android.app.IActivityManager
-import android.app.UserSwitchObserver
import android.content.pm.UserInfo
-import android.os.IRemoteCallback
import android.os.UserHandle
import android.os.UserManager
import android.provider.Settings
@@ -44,14 +41,8 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.mockito.ArgumentCaptor
-import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.any
-import org.mockito.Mockito.anyString
import org.mockito.Mockito.mock
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@@ -60,8 +51,6 @@ import org.mockito.MockitoAnnotations
class UserRepositoryImplTest : SysuiTestCase() {
@Mock private lateinit var manager: UserManager
- @Mock private lateinit var activityManager: IActivityManager
- @Captor private lateinit var userSwitchObserver: ArgumentCaptor<UserSwitchObserver>
private lateinit var underTest: UserRepositoryImpl
@@ -229,30 +218,31 @@ class UserRepositoryImplTest : SysuiTestCase() {
}
@Test
- fun userSwitchingInProgress_registersOnlyOneUserSwitchObserver() = runSelfCancelingTest {
+ fun userSwitchingInProgress_registersUserTrackerCallback() = runSelfCancelingTest {
underTest = create(this)
underTest.userSwitchingInProgress.launchIn(this)
underTest.userSwitchingInProgress.launchIn(this)
underTest.userSwitchingInProgress.launchIn(this)
- verify(activityManager, times(1)).registerUserSwitchObserver(any(), anyString())
+ // Two callbacks registered - one for observing user switching and one for observing the
+ // selected user
+ assertThat(tracker.callbacks.size).isEqualTo(2)
}
@Test
- fun userSwitchingInProgress_propagatesStateFromActivityManager() = runSelfCancelingTest {
+ fun userSwitchingInProgress_propagatesStateFromUserTracker() = runSelfCancelingTest {
underTest = create(this)
- verify(activityManager)
- .registerUserSwitchObserver(userSwitchObserver.capture(), anyString())
+ assertThat(tracker.callbacks.size).isEqualTo(2)
- userSwitchObserver.value.onUserSwitching(0, mock(IRemoteCallback::class.java))
+ tracker.onUserChanging(0)
var mostRecentSwitchingValue = false
underTest.userSwitchingInProgress.onEach { mostRecentSwitchingValue = it }.launchIn(this)
assertThat(mostRecentSwitchingValue).isTrue()
- userSwitchObserver.value.onUserSwitchComplete(0)
+ tracker.onUserChanged(0)
assertThat(mostRecentSwitchingValue).isFalse()
}
@@ -332,7 +322,6 @@ class UserRepositoryImplTest : SysuiTestCase() {
backgroundDispatcher = IMMEDIATE,
globalSettings = globalSettings,
tracker = tracker,
- activityManager = activityManager,
featureFlags = featureFlags,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
index 31cce4f3168b..468c5a73645b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
@@ -88,7 +88,7 @@ public class ImageWallpaperTest extends SysuiTestCase {
@Mock
private Bitmap mWallpaperBitmap;
FakeSystemClock mFakeSystemClock = new FakeSystemClock();
- FakeExecutor mFakeBackgroundExecutor = new FakeExecutor(mFakeSystemClock);
+ FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock);
@Before
public void setUp() throws Exception {
@@ -125,7 +125,7 @@ public class ImageWallpaperTest extends SysuiTestCase {
@Test
public void testBitmapWallpaper_normal() {
- // Will use a image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH.
+ // Will use an image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH.
// Then we expect the surface size will be also DISPLAY_WIDTH x DISPLAY_WIDTH.
int bitmapSide = DISPLAY_WIDTH;
testSurfaceHelper(
@@ -137,7 +137,7 @@ public class ImageWallpaperTest extends SysuiTestCase {
@Test
public void testBitmapWallpaper_low_resolution() {
- // Will use a image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT.
+ // Will use an image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT.
// Then we expect the surface size will be also BMP_WIDTH x BMP_HEIGHT.
testSurfaceHelper(LOW_BMP_WIDTH /* bitmapWidth */,
LOW_BMP_HEIGHT /* bitmapHeight */,
@@ -161,13 +161,13 @@ public class ImageWallpaperTest extends SysuiTestCase {
ImageWallpaper.CanvasEngine spyEngine = getSpyEngine();
spyEngine.onCreate(mSurfaceHolder);
spyEngine.onSurfaceRedrawNeeded(mSurfaceHolder);
- assertThat(mFakeBackgroundExecutor.numPending()).isAtLeast(1);
+ assertThat(mFakeExecutor.numPending()).isAtLeast(1);
int n = 0;
- while (mFakeBackgroundExecutor.numPending() >= 1) {
+ while (mFakeExecutor.numPending() >= 1) {
n++;
assertThat(n).isAtMost(10);
- mFakeBackgroundExecutor.runNextReady();
+ mFakeExecutor.runNextReady();
mFakeSystemClock.advanceTime(1000);
}
@@ -176,7 +176,7 @@ public class ImageWallpaperTest extends SysuiTestCase {
}
private ImageWallpaper createImageWallpaper() {
- return new ImageWallpaper(mFakeBackgroundExecutor, mUserTracker) {
+ return new ImageWallpaper(mFakeExecutor, mUserTracker) {
@Override
public Engine onCreateEngine() {
return new CanvasEngine() {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/Flow.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/Flow.kt
index 9b4f4969f9e9..c2947b42f56d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/Flow.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/Flow.kt
@@ -29,6 +29,7 @@ import kotlinx.coroutines.test.runCurrent
/**
* Collect [flow] in a new [Job] and return a getter for the last collected value.
+ *
* ```
* fun myTest() = runTest {
* // ...
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt
new file mode 100644
index 000000000000..4e435462be50
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.keyboard.data.repository
+
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.filterNotNull
+
+class FakeKeyboardRepository : KeyboardRepository {
+
+ private val _keyboardConnected = MutableStateFlow(false)
+ override val keyboardConnected: Flow<Boolean> = _keyboardConnected
+
+ private val _backlightState: MutableStateFlow<BacklightModel?> = MutableStateFlow(null)
+ // filtering to make sure backlight doesn't have default initial value
+ override val backlight: Flow<BacklightModel> = _backlightState.filterNotNull()
+
+ fun setBacklight(state: BacklightModel) {
+ _backlightState.value = state
+ }
+
+ fun setKeyboardConnected(connected: Boolean) {
+ _keyboardConnected.value = connected
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt
index 01dac362432d..d4b1701892c7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt
@@ -21,6 +21,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.flowOf
class FakeBiometricSettingsRepository : BiometricSettingsRepository {
@@ -42,6 +43,9 @@ class FakeBiometricSettingsRepository : BiometricSettingsRepository {
override val isFingerprintEnabledByDevicePolicy =
_isFingerprintEnabledByDevicePolicy.asStateFlow()
+ override val isFaceAuthSupportedInCurrentPosture: Flow<Boolean>
+ get() = flowOf(true)
+
fun setFingerprintEnrolled(isFingerprintEnrolled: Boolean) {
_isFingerprintEnrolled.value = isFingerprintEnrolled
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDevicePostureRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDevicePostureRepository.kt
new file mode 100644
index 000000000000..914c786a1c7f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDevicePostureRepository.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.data.repository
+
+import com.android.systemui.keyguard.shared.model.DevicePosture
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeDevicePostureRepository : DevicePostureRepository {
+ private val _currentDevicePosture = MutableStateFlow(DevicePosture.UNKNOWN)
+ override val currentDevicePosture: Flow<DevicePosture>
+ get() = _currentDevicePosture
+
+ fun setCurrentPosture(posture: DevicePosture) {
+ _currentDevicePosture.value = posture
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 1a371c73550c..194ed02712b2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -47,6 +47,9 @@ class FakeKeyguardRepository : KeyguardRepository {
private val _isKeyguardShowing = MutableStateFlow(false)
override val isKeyguardShowing: Flow<Boolean> = _isKeyguardShowing
+ private val _isKeyguardUnlocked = MutableStateFlow(false)
+ override val isKeyguardUnlocked: Flow<Boolean> = _isKeyguardUnlocked
+
private val _isKeyguardOccluded = MutableStateFlow(false)
override val isKeyguardOccluded: Flow<Boolean> = _isKeyguardOccluded
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
index eac1bd145033..16442bb525b6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
@@ -37,7 +37,7 @@ class FakeKeyguardTransitionRepository : KeyguardTransitionRepository {
_transitions.emit(step)
}
- override fun startTransition(info: TransitionInfo): UUID? {
+ override fun startTransition(info: TransitionInfo, resetIfCanceled: Boolean): UUID? {
return null
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
index 251014fc50b3..4242c1635468 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
@@ -22,6 +22,7 @@ import android.content.pm.UserInfo
import android.os.UserHandle
import android.test.mock.MockContentResolver
import com.android.systemui.util.mockito.mock
+import java.util.concurrent.CountDownLatch
import java.util.concurrent.Executor
/** A fake [UserTracker] to be used in tests. */
@@ -66,11 +67,19 @@ class FakeUserTracker(
_userId = _userInfo.id
_userHandle = UserHandle.of(_userId)
+ onUserChanging()
+ onUserChanged()
+ }
+
+ fun onUserChanging(userId: Int = _userId) {
+ val copy = callbacks.toList()
+ val latch = CountDownLatch(copy.size)
+ copy.forEach { it.onUserChanging(userId, userContext, latch) }
+ }
+
+ fun onUserChanged(userId: Int = _userId) {
val copy = callbacks.toList()
- copy.forEach {
- it.onUserChanging(_userId, userContext)
- it.onUserChanged(_userId, userContext)
- }
+ copy.forEach { it.onUserChanged(userId, userContext) }
}
fun onProfileChanged() {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSystemUIDialogController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSystemUIDialogController.kt
new file mode 100644
index 000000000000..0c9ce0f145f1
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSystemUIDialogController.kt
@@ -0,0 +1,86 @@
+/*
+ * 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
+
+import android.content.DialogInterface
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import org.mockito.ArgumentCaptor
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.verify
+import org.mockito.stubbing.Stubber
+
+class FakeSystemUIDialogController {
+
+ val dialog: SystemUIDialog = mock()
+
+ private val clickListeners: MutableMap<Int, DialogInterface.OnClickListener> = mutableMapOf()
+
+ init {
+ saveListener(DialogInterface.BUTTON_POSITIVE)
+ .whenever(dialog)
+ .setPositiveButton(any(), any())
+ saveListener(DialogInterface.BUTTON_POSITIVE)
+ .whenever(dialog)
+ .setPositiveButton(any(), any(), any())
+
+ saveListener(DialogInterface.BUTTON_NEGATIVE)
+ .whenever(dialog)
+ .setNegativeButton(any(), any())
+ saveListener(DialogInterface.BUTTON_NEGATIVE)
+ .whenever(dialog)
+ .setNegativeButton(any(), any(), any())
+
+ saveListener(DialogInterface.BUTTON_NEUTRAL).whenever(dialog).setNeutralButton(any(), any())
+ saveListener(DialogInterface.BUTTON_NEUTRAL)
+ .whenever(dialog)
+ .setNeutralButton(any(), any(), any())
+ }
+
+ fun clickNegative() {
+ performClick(DialogInterface.BUTTON_NEGATIVE, "This dialog has no negative button")
+ }
+
+ fun clickPositive() {
+ performClick(DialogInterface.BUTTON_POSITIVE, "This dialog has no positive button")
+ }
+
+ fun clickNeutral() {
+ performClick(DialogInterface.BUTTON_NEUTRAL, "This dialog has no neutral button")
+ }
+
+ fun cancel() {
+ val captor = ArgumentCaptor.forClass(DialogInterface.OnCancelListener::class.java)
+ verify(dialog).setOnCancelListener(captor.capture())
+ captor.value.onCancel(dialog)
+ }
+
+ private fun performClick(which: Int, errorMessage: String) {
+ clickListeners
+ .getOrElse(which) { throw IllegalAccessException(errorMessage) }
+ .onClick(dialog, which)
+ }
+
+ private fun saveListener(which: Int): Stubber = doAnswer {
+ val listener = it.getArgument<DialogInterface.OnClickListener>(1)
+ clickListeners[which] = listener
+ Unit
+ }
+}
diff --git a/packages/SystemUI/unfold/Android.bp b/packages/SystemUI/unfold/Android.bp
index 180b611aa13b..2e0a9462ffbe 100644
--- a/packages/SystemUI/unfold/Android.bp
+++ b/packages/SystemUI/unfold/Android.bp
@@ -35,6 +35,7 @@ android_library {
],
kotlincflags: ["-Xjvm-default=enable"],
java_version: "1.8",
+ sdk_version: "current",
min_sdk_version: "current",
plugins: ["dagger2-compiler"],
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
index 068347cfe9d8..c3a6cf035d09 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
@@ -19,14 +19,15 @@ package com.android.systemui.unfold
import android.content.ContentResolver
import android.content.Context
import android.hardware.SensorManager
+import android.hardware.display.DisplayManager
import android.os.Handler
-import android.view.IWindowManager
import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.dagger.UnfoldMain
import com.android.systemui.unfold.dagger.UnfoldSingleThreadBg
import com.android.systemui.unfold.progress.RemoteUnfoldTransitionReceiver
import com.android.systemui.unfold.updates.FoldProvider
import com.android.systemui.unfold.updates.RotationChangeProvider
+import com.android.systemui.unfold.updates.hinge.HingeAngleProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
import com.android.systemui.unfold.util.CurrentActivityTypeProvider
import com.android.systemui.unfold.util.UnfoldTransitionATracePrefix
@@ -61,12 +62,13 @@ interface UnfoldSharedComponent {
@BindsInstance @UnfoldMain executor: Executor,
@BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor,
@BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String,
- @BindsInstance windowManager: IWindowManager,
+ @BindsInstance displayManager: DisplayManager,
@BindsInstance contentResolver: ContentResolver = context.contentResolver
): UnfoldSharedComponent
}
val unfoldTransitionProvider: Optional<UnfoldTransitionProgressProvider>
+ val hingeAngleProvider: HingeAngleProvider
val rotationChangeProvider: RotationChangeProvider
}
@@ -84,8 +86,9 @@ interface RemoteUnfoldSharedComponent {
@BindsInstance context: Context,
@BindsInstance config: UnfoldTransitionConfig,
@BindsInstance @UnfoldMain executor: Executor,
+ @BindsInstance @UnfoldMain handler: Handler,
@BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor,
- @BindsInstance windowManager: IWindowManager,
+ @BindsInstance displayManager: DisplayManager,
@BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String,
): RemoteUnfoldSharedComponent
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
index 8eb79df55496..18399194434a 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
@@ -19,8 +19,8 @@ package com.android.systemui.unfold
import android.content.Context
import android.hardware.SensorManager
+import android.hardware.display.DisplayManager
import android.os.Handler
-import android.view.IWindowManager
import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.updates.FoldProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
@@ -47,7 +47,7 @@ fun createUnfoldSharedComponent(
mainExecutor: Executor,
singleThreadBgExecutor: Executor,
tracingTagPrefix: String,
- windowManager: IWindowManager,
+ displayManager: DisplayManager,
): UnfoldSharedComponent =
DaggerUnfoldSharedComponent.factory()
.create(
@@ -61,7 +61,7 @@ fun createUnfoldSharedComponent(
mainExecutor,
singleThreadBgExecutor,
tracingTagPrefix,
- windowManager,
+ displayManager,
)
/**
@@ -73,16 +73,18 @@ fun createRemoteUnfoldSharedComponent(
context: Context,
config: UnfoldTransitionConfig,
mainExecutor: Executor,
+ mainHandler: Handler,
singleThreadBgExecutor: Executor,
tracingTagPrefix: String,
- windowManager: IWindowManager,
+ displayManager: DisplayManager,
): RemoteUnfoldSharedComponent =
DaggerRemoteUnfoldSharedComponent.factory()
.create(
context,
config,
mainExecutor,
+ mainHandler,
singleThreadBgExecutor,
- windowManager,
+ displayManager,
tracingTagPrefix,
)
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
index 4622464b204d..c437e5c23d1b 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt
@@ -21,7 +21,6 @@ import android.util.FloatProperty
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
-import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
import com.android.systemui.unfold.updates.FoldStateProvider
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
import javax.inject.Inject
@@ -59,12 +58,15 @@ constructor(private val foldStateProvider: FoldStateProvider) :
}
override fun onFoldUpdate(@FoldUpdate update: Int) {
- when (update) {
- FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> animator.start()
- FOLD_UPDATE_FINISH_CLOSED -> animator.cancel()
+ if (update == FOLD_UPDATE_FINISH_CLOSED) {
+ animator.cancel()
}
}
+ override fun onUnfoldedScreenAvailable() {
+ animator.start()
+ }
+
override fun addCallback(listener: TransitionProgressListener) {
listeners.add(listener)
}
@@ -73,8 +75,6 @@ constructor(private val foldStateProvider: FoldStateProvider) :
listeners.remove(listener)
}
- override fun onHingeAngleUpdate(angle: Float) {}
-
private object AnimationProgressProperty :
FloatProperty<FixedTimingTransitionProgressProvider>("animation_progress") {
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
index 6ffbe5aa25c0..28e493651137 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -16,7 +16,6 @@
package com.android.systemui.unfold.progress
import android.os.Trace
-import android.os.Trace.TRACE_TAG_APP
import android.util.Log
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.FloatPropertyCompat
@@ -28,7 +27,6 @@ import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
-import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
import com.android.systemui.unfold.updates.FoldStateProvider
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
@@ -78,21 +76,11 @@ class PhysicsBasedUnfoldTransitionProgressProvider @Inject constructor(
override fun onFoldUpdate(@FoldUpdate update: Int) {
when (update) {
- FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> {
- startTransition(startValue = 0f)
-
- // Stop the animation if the device has already opened by the time when
- // the display is available as we won't receive the full open event anymore
- if (foldStateProvider.isFinishedOpening) {
- cancelTransition(endValue = 1f, animate = true)
- }
- }
FOLD_UPDATE_FINISH_FULL_OPEN, FOLD_UPDATE_FINISH_HALF_OPEN -> {
// Do not cancel if we haven't started the transition yet.
// This could happen when we fully unfolded the device before the screen
// became available. In this case we start and immediately cancel the animation
- // in FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE event handler, so we don't need to
- // cancel it here.
+ // in onUnfoldedScreenAvailable event handler, so we don't need to cancel it here.
if (isTransitionRunning) {
cancelTransition(endValue = 1f, animate = true)
}
@@ -121,7 +109,17 @@ class PhysicsBasedUnfoldTransitionProgressProvider @Inject constructor(
if (DEBUG) {
Log.d(TAG, "onFoldUpdate = ${update.name()}")
- Trace.traceCounter(Trace.TRACE_TAG_APP, "fold_update", update)
+ Trace.setCounter("fold_update", update.toLong())
+ }
+ }
+
+ override fun onUnfoldedScreenAvailable() {
+ startTransition(startValue = 0f)
+
+ // Stop the animation if the device has already opened by the time when
+ // the display is available as we won't receive the full open event anymore
+ if (foldStateProvider.isFinishedOpening) {
+ cancelTransition(endValue = 1f, animate = true)
}
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 97c9ba99f096..d653fc7beff2 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -54,6 +54,7 @@ constructor(
@FoldUpdate private var lastFoldUpdate: Int? = null
@FloatRange(from = 0.0, to = 180.0) private var lastHingeAngle: Float = 0f
+ @FloatRange(from = 0.0, to = 180.0) private var lastHingeAngleBeforeTransition: Float = 0f
private val hingeAngleListener = HingeAngleListener()
private val screenListener = ScreenStatusListener()
@@ -112,29 +113,45 @@ constructor(
private fun onHingeAngle(angle: Float) {
if (DEBUG) {
- Log.d(TAG, "Hinge angle: $angle, lastHingeAngle: $lastHingeAngle")
- Trace.traceCounter(Trace.TRACE_TAG_APP, "hinge_angle", angle.toInt())
+ Log.d(
+ TAG,
+ "Hinge angle: $angle, " +
+ "lastHingeAngle: $lastHingeAngle, " +
+ "lastHingeAngleBeforeTransition: $lastHingeAngleBeforeTransition"
+ )
+ Trace.setCounter( "hinge_angle", angle.toLong())
}
- val isClosing = angle < lastHingeAngle
+ val currentDirection =
+ if (angle < lastHingeAngle) FOLD_UPDATE_START_CLOSING else FOLD_UPDATE_START_OPENING
+ if (isTransitionInProgress && currentDirection != lastFoldUpdate) {
+ lastHingeAngleBeforeTransition = lastHingeAngle
+ }
+
+ val isClosing = angle < lastHingeAngleBeforeTransition
+ val transitionUpdate =
+ if (isClosing) FOLD_UPDATE_START_CLOSING else FOLD_UPDATE_START_OPENING
+ val angleChangeSurpassedThreshold =
+ Math.abs(angle - lastHingeAngleBeforeTransition) > HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES
val isFullyOpened = FULLY_OPEN_DEGREES - angle < FULLY_OPEN_THRESHOLD_DEGREES
- val closingEventDispatched = lastFoldUpdate == FOLD_UPDATE_START_CLOSING
+ val eventNotAlreadyDispatched = lastFoldUpdate != transitionUpdate
val screenAvailableEventSent = isUnfoldHandled
- if (isClosing // hinge angle should be decreasing since last update
- && !closingEventDispatched // we haven't sent closing event already
- && !isFullyOpened // do not send closing event if we are in fully opened hinge
+ if (
+ angleChangeSurpassedThreshold && // Do not react immediately to small changes in angle
+ eventNotAlreadyDispatched && // we haven't sent transition event already
+ !isFullyOpened && // do not send transition event if we are in fully opened hinge
// angle range as closing threshold could overlap this range
- && screenAvailableEventSent // do not send closing event if we are still in
- // the process of turning on the inner display
- && isClosingThresholdMet(angle) // hinge angle is below certain threshold.
+ screenAvailableEventSent && // do not send transition event if we are still in the
+ // process of turning on the inner display
+ isClosingThresholdMet(angle) // hinge angle is below certain threshold.
) {
- notifyFoldUpdate(FOLD_UPDATE_START_CLOSING)
+ notifyFoldUpdate(transitionUpdate, lastHingeAngle)
}
if (isTransitionInProgress) {
if (isFullyOpened) {
- notifyFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN)
+ notifyFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN, angle)
cancelTimeout()
} else {
// The timeout will trigger some constant time after the last angle update.
@@ -146,7 +163,7 @@ constructor(
outputListeners.forEach { it.onHingeAngleUpdate(angle) }
}
- private fun isClosingThresholdMet(currentAngle: Float) : Boolean {
+ private fun isClosingThresholdMet(currentAngle: Float): Boolean {
val closingThreshold = getClosingThreshold()
return closingThreshold == null || currentAngle < closingThreshold
}
@@ -179,23 +196,29 @@ constructor(
if (isFolded) {
hingeAngleProvider.stop()
- notifyFoldUpdate(FOLD_UPDATE_FINISH_CLOSED)
+ notifyFoldUpdate(FOLD_UPDATE_FINISH_CLOSED, lastHingeAngle)
cancelTimeout()
isUnfoldHandled = false
} else {
- notifyFoldUpdate(FOLD_UPDATE_START_OPENING)
+ notifyFoldUpdate(FOLD_UPDATE_START_OPENING, lastHingeAngle)
rescheduleAbortAnimationTimeout()
hingeAngleProvider.start()
}
}
}
- private fun notifyFoldUpdate(@FoldUpdate update: Int) {
+ private fun notifyFoldUpdate(@FoldUpdate update: Int, angle: Float) {
if (DEBUG) {
Log.d(TAG, update.name())
}
+ val previouslyTransitioning = isTransitionInProgress
+
outputListeners.forEach { it.onFoldUpdate(update) }
lastFoldUpdate = update
+
+ if (previouslyTransitioning != isTransitionInProgress) {
+ lastHingeAngleBeforeTransition = angle
+ }
}
private fun rescheduleAbortAnimationTimeout() {
@@ -209,7 +232,8 @@ constructor(
handler.removeCallbacks(timeoutRunnable)
}
- private fun cancelAnimation(): Unit = notifyFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN)
+ private fun cancelAnimation(): Unit =
+ notifyFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN, lastHingeAngle)
private inner class ScreenStatusListener : ScreenStatusProvider.ScreenListener {
@@ -221,7 +245,7 @@ constructor(
// receive 'folded' event. If SystemUI started when device is already folded it will
// still receive 'folded' event on startup.
if (!isFolded && !isUnfoldHandled) {
- outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) }
+ outputListeners.forEach { it.onUnfoldedScreenAvailable() }
isUnfoldHandled = true
}
}
@@ -257,7 +281,6 @@ fun @receiver:FoldUpdate Int.name() =
when (this) {
FOLD_UPDATE_START_OPENING -> "START_OPENING"
FOLD_UPDATE_START_CLOSING -> "START_CLOSING"
- FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> "UNFOLDED_SCREEN_AVAILABLE"
FOLD_UPDATE_FINISH_HALF_OPEN -> "FINISH_HALF_OPEN"
FOLD_UPDATE_FINISH_FULL_OPEN -> "FINISH_FULL_OPEN"
FOLD_UPDATE_FINISH_CLOSED -> "FINISH_CLOSED"
@@ -270,5 +293,8 @@ private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
/** Threshold after which we consider the device fully unfolded. */
@VisibleForTesting const val FULLY_OPEN_THRESHOLD_DEGREES = 15f
+/** Threshold after which hinge angle updates are considered. This is to eliminate noise. */
+@VisibleForTesting const val HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES = 7.5f
+
/** Fold animation on top of apps only when the angle exceeds this threshold. */
@VisibleForTesting const val START_CLOSING_ON_APPS_THRESHOLD_DEGREES = 60
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
index c7a8bf336777..0af372f9da24 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
@@ -31,8 +31,9 @@ interface FoldStateProvider : CallbackController<FoldUpdatesListener> {
val isFinishedOpening: Boolean
interface FoldUpdatesListener {
- fun onHingeAngleUpdate(@FloatRange(from = 0.0, to = 180.0) angle: Float)
- fun onFoldUpdate(@FoldUpdate update: Int)
+ @JvmDefault fun onHingeAngleUpdate(@FloatRange(from = 0.0, to = 180.0) angle: Float) {}
+ @JvmDefault fun onFoldUpdate(@FoldUpdate update: Int) {}
+ @JvmDefault fun onUnfoldedScreenAvailable() {}
}
@IntDef(
@@ -40,7 +41,6 @@ interface FoldStateProvider : CallbackController<FoldUpdatesListener> {
[
FOLD_UPDATE_START_OPENING,
FOLD_UPDATE_START_CLOSING,
- FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE,
FOLD_UPDATE_FINISH_HALF_OPEN,
FOLD_UPDATE_FINISH_FULL_OPEN,
FOLD_UPDATE_FINISH_CLOSED])
@@ -50,7 +50,6 @@ interface FoldStateProvider : CallbackController<FoldUpdatesListener> {
const val FOLD_UPDATE_START_OPENING = 0
const val FOLD_UPDATE_START_CLOSING = 1
-const val FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE = 2
-const val FOLD_UPDATE_FINISH_HALF_OPEN = 3
-const val FOLD_UPDATE_FINISH_FULL_OPEN = 4
-const val FOLD_UPDATE_FINISH_CLOSED = 5
+const val FOLD_UPDATE_FINISH_HALF_OPEN = 2
+const val FOLD_UPDATE_FINISH_FULL_OPEN = 3
+const val FOLD_UPDATE_FINISH_CLOSED = 4
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
index 0cf8224d3a3f..ce8f1a178d05 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
@@ -17,36 +17,32 @@
package com.android.systemui.unfold.updates
import android.content.Context
+import android.hardware.display.DisplayManager
+import android.os.Handler
import android.os.RemoteException
-import android.view.IRotationWatcher
-import android.view.IWindowManager
-import android.view.Surface.Rotation
import com.android.systemui.unfold.dagger.UnfoldMain
import com.android.systemui.unfold.util.CallbackController
-import java.util.concurrent.Executor
import javax.inject.Inject
/**
- * Allows to subscribe to rotation changes.
- *
- * This is needed as rotation updates from [IWindowManager] are received in a binder thread, while
- * most of the times we want them in the main one. Updates are provided for the display associated
+ * Allows to subscribe to rotation changes. Updates are provided for the display associated
* to [context].
*/
class RotationChangeProvider
@Inject
constructor(
- private val windowManagerInterface: IWindowManager,
+ private val displayManager: DisplayManager,
private val context: Context,
- @UnfoldMain private val mainExecutor: Executor,
+ @UnfoldMain private val mainHandler: Handler,
) : CallbackController<RotationChangeProvider.RotationListener> {
private val listeners = mutableListOf<RotationListener>()
- private val rotationWatcher = RotationWatcher()
+ private val displayListener = RotationDisplayListener()
+ private var lastRotation: Int? = null
override fun addCallback(listener: RotationListener) {
- mainExecutor.execute {
+ mainHandler.post {
if (listeners.isEmpty()) {
subscribeToRotation()
}
@@ -55,17 +51,18 @@ constructor(
}
override fun removeCallback(listener: RotationListener) {
- mainExecutor.execute {
+ mainHandler.post {
listeners -= listener
if (listeners.isEmpty()) {
unsubscribeToRotation()
+ lastRotation = null
}
}
}
private fun subscribeToRotation() {
try {
- windowManagerInterface.watchRotation(rotationWatcher, context.displayId)
+ displayManager.registerDisplayListener(displayListener, mainHandler)
} catch (e: RemoteException) {
throw e.rethrowFromSystemServer()
}
@@ -73,7 +70,7 @@ constructor(
private fun unsubscribeToRotation() {
try {
- windowManagerInterface.removeRotationWatcher(rotationWatcher)
+ displayManager.unregisterDisplayListener(displayListener)
} catch (e: RemoteException) {
throw e.rethrowFromSystemServer()
}
@@ -82,12 +79,25 @@ constructor(
/** Gets notified of rotation changes. */
fun interface RotationListener {
/** Called once rotation changes. */
- fun onRotationChanged(@Rotation newRotation: Int)
+ fun onRotationChanged(newRotation: Int)
}
- private inner class RotationWatcher : IRotationWatcher.Stub() {
- override fun onRotationChanged(rotation: Int) {
- mainExecutor.execute { listeners.forEach { it.onRotationChanged(rotation) } }
+ private inner class RotationDisplayListener : DisplayManager.DisplayListener {
+
+ override fun onDisplayChanged(displayId: Int) {
+ val display = context.display ?: return
+
+ if (displayId == display.displayId) {
+ val currentRotation = display.rotation
+ if (lastRotation == null || lastRotation != currentRotation) {
+ listeners.forEach { it.onRotationChanged(currentRotation) }
+ lastRotation = currentRotation
+ }
+ }
}
+
+ override fun onDisplayAdded(displayId: Int) {}
+
+ override fun onDisplayRemoved(displayId: Int) {}
}
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
index 06ca153b694b..ce5c5f91914b 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
@@ -79,10 +79,9 @@ constructor(
companion object {
fun ContentResolver.areAnimationsEnabled(): Boolean {
val animationScale =
- Settings.Global.getStringForUser(
+ Settings.Global.getString(
this,
Settings.Global.ANIMATOR_DURATION_SCALE,
- this.userId
)
?.toFloatOrNull()
?: 1f
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
index b7bab3e5ed5a..f9751d9c279c 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
@@ -47,6 +47,7 @@ constructor(source: UnfoldTransitionProgressProvider? = null) :
/**
* Sets the source for the unfold transition progress updates. Replaces current provider if it
* is already set
+ *
* @param provider transition provider that emits transition progress updates
*/
fun setSourceProvider(provider: UnfoldTransitionProgressProvider?) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d78fe8628c60..f0dac2607a4e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3831,8 +3831,20 @@ public class ActivityManagerService extends IActivityManager.Stub
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int callingAppId = UserHandle.getAppId(callingUid);
- userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ ProcessRecord proc;
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(callingPid);
+ }
+ final boolean hasKillAllPermission = PERMISSION_GRANTED == checkPermission(
+ android.Manifest.permission.FORCE_STOP_PACKAGES, callingPid, callingUid)
+ || UserHandle.isCore(callingUid)
+ || (proc != null && proc.info.isSystemApp());
+
+ userId = mUserController.handleIncomingUser(callingPid, callingUid,
userId, true, ALLOW_FULL_ONLY, "killBackgroundProcesses", null);
final int[] userIds = mUserController.expandUserId(userId);
@@ -3847,7 +3859,7 @@ public class ActivityManagerService extends IActivityManager.Stub
targetUserId));
} catch (RemoteException e) {
}
- if (appId == -1) {
+ if (appId == -1 || (!hasKillAllPermission && appId != callingAppId)) {
Slog.w(TAG, "Invalid packageName: " + packageName);
return;
}
@@ -3875,6 +3887,22 @@ public class ActivityManagerService extends IActivityManager.Stub
throw new SecurityException(msg);
}
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+
+ ProcessRecord proc;
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(callingPid);
+ }
+ if (callingUid >= FIRST_APPLICATION_UID
+ && (proc == null || !proc.info.isSystemApp())) {
+ final String msg = "Permission Denial: killAllBackgroundProcesses() from pid="
+ + callingPid + ", uid=" + callingUid + " is not allowed";
+ Slog.w(TAG, msg);
+ // Silently return to avoid existing apps from crashing.
+ return;
+ }
+
final long callingId = Binder.clearCallingIdentity();
try {
synchronized (this) {
@@ -13089,12 +13117,17 @@ public class ActivityManagerService extends IActivityManager.Stub
public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
String callerFeatureId, String receiverId, IIntentReceiver receiver,
IntentFilter filter, String permission, int userId, int flags) {
+ enforceNotIsolatedCaller("registerReceiver");
+
// Allow Sandbox process to register only unexported receivers.
- if ((flags & Context.RECEIVER_NOT_EXPORTED) != 0) {
- enforceNotIsolatedCaller("registerReceiver");
- } else if (mSdkSandboxSettings.isBroadcastReceiverRestrictionsEnforced()) {
- enforceNotIsolatedOrSdkSandboxCaller("registerReceiver");
+ boolean unexported = (flags & Context.RECEIVER_NOT_EXPORTED) != 0;
+ if (mSdkSandboxSettings.isBroadcastReceiverRestrictionsEnforced()
+ && Process.isSdkSandboxUid(Binder.getCallingUid())
+ && !unexported) {
+ throw new SecurityException("SDK sandbox process not allowed to call "
+ + "registerReceiver");
}
+
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
final boolean visibleToInstantApps
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 2f95716639f0..207c10c44c9b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -21,7 +21,6 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
import android.annotation.NonNull;
-import android.app.AlarmManager;
import android.app.StatsManager;
import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothActivityEnergyInfo;
@@ -357,16 +356,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
com.android.internal.R.integer.config_radioScanningTimeout) * 1000L);
mStats.setPowerProfileLocked(mPowerProfile);
-
- final boolean resetOnUnplugHighBatteryLevel = context.getResources().getBoolean(
- com.android.internal.R.bool.config_batteryStatsResetOnUnplugHighBatteryLevel);
- final boolean resetOnUnplugAfterSignificantCharge = context.getResources().getBoolean(
- com.android.internal.R.bool.config_batteryStatsResetOnUnplugAfterSignificantCharge);
- mStats.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugHighBatteryLevel(resetOnUnplugHighBatteryLevel)
- .setResetOnUnplugAfterSignificantCharge(resetOnUnplugAfterSignificantCharge)
- .build());
mStats.startTrackingSystemServerCpuTime();
if (BATTERY_USAGE_STORE_ENABLED) {
@@ -397,18 +386,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub
Slog.e(TAG, "Could not register INetworkManagement event observer " + e);
}
- final AlarmManager am = mContext.getSystemService(AlarmManager.class);
- mHandler.post(() -> {
- synchronized (mStats) {
- mStats.setLongPlugInAlarmInterface(new AlarmInterface(am, () -> {
- synchronized (mStats) {
- if (mStats.isOnBattery()) return;
- mStats.maybeResetWhilePluggedInLocked();
- }
- }));
- }
- });
-
synchronized (mPowerStatsLock) {
mPowerStatsInternal = LocalServices.getService(PowerStatsInternal.class);
if (mPowerStatsInternal != null) {
@@ -2282,32 +2259,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
}
- final class AlarmInterface implements BatteryStatsImpl.AlarmInterface,
- AlarmManager.OnAlarmListener {
- private AlarmManager mAm;
- private Runnable mOnAlarm;
-
- AlarmInterface(AlarmManager am, Runnable onAlarm) {
- mAm = am;
- mOnAlarm = onAlarm;
- }
-
- @Override
- public void schedule(long rtcTimeMs, long windowLengthMs) {
- mAm.setWindow(AlarmManager.RTC, rtcTimeMs, windowLengthMs, TAG, this, mHandler);
- }
-
- @Override
- public void cancel() {
- mAm.cancel(this);
- }
-
- @Override
- public void onAlarm() {
- mOnAlarm.run();
- }
- }
-
private static native int nativeWaitWakeup(ByteBuffer outBuffer);
private void dumpHelp(PrintWriter pw) {
@@ -2494,8 +2445,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
} else if ("--reset-all".equals(arg)) {
awaitCompletion();
synchronized (mStats) {
- mStats.resetAllStatsAndHistoryLocked(
- BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ mStats.resetAllStatsCmdLocked();
mBatteryUsageStatsStore.removeAllSnapshots();
pw.println("Battery stats and history reset.");
noOutput = true;
@@ -2503,8 +2453,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
} else if ("--reset".equals(arg)) {
awaitCompletion();
synchronized (mStats) {
- mStats.resetAllStatsAndHistoryLocked(
- BatteryStatsImpl.RESET_REASON_ADB_COMMAND);
+ mStats.resetAllStatsCmdLocked();
pw.println("Battery stats reset.");
noOutput = true;
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 9700e562b518..8c9373b98c58 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -3005,9 +3005,10 @@ public final class ProcessList {
hostingRecord.getDefiningUid(), hostingRecord.getDefiningProcessName());
final ProcessStateRecord state = r.mState;
- if (!mService.mBooted && !mService.mBooting
+ if (!isolated && !isSdkSandbox
&& userId == UserHandle.USER_SYSTEM
- && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
+ && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK
+ && (TextUtils.equals(proc, info.processName))) {
// The system process is initialized to SCHED_GROUP_DEFAULT in init.rc.
state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
state.setSetSchedGroup(ProcessList.SCHED_GROUP_DEFAULT);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 9f1512825c3a..521f342455d6 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -8396,7 +8396,9 @@ public class AudioService extends IAudioService.Stub
if (isMutable()) {
// For call stream, align mute only when muted, not when index is set to 0
mVolumeGroupState.mute(
- forceMuteState ? mIsMuted : groupIndex == 0 || mIsMuted);
+ forceMuteState ? mIsMuted :
+ (groupIndex == 0 && !isCallStream(mStreamType))
+ || mIsMuted);
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 94b67cedf86c..598e2b990ea5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -452,13 +452,6 @@ public class FingerprintService extends SystemService {
return -1;
}
- if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) {
- // If this happens, something in KeyguardUpdateMonitor is wrong. This should only
- // ever be invoked when the user is encrypted or lockdown.
- Slog.e(TAG, "detectFingerprint invoked when user is not encrypted or lockdown");
- return -1;
- }
-
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for detectFingerprint");
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 76d71e2b968a..bb39307bdc0d 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -22,6 +22,7 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayViewport;
import android.os.IBinder;
+import android.util.Slog;
import android.view.Display;
import android.view.DisplayAddress;
import android.view.Surface;
@@ -37,6 +38,7 @@ import java.io.PrintWriter;
* </p>
*/
abstract class DisplayDevice {
+ private static final String TAG = "DisplayDevice";
private static final Display.Mode EMPTY_DISPLAY_MODE = new Display.Mode.Builder().build();
private final DisplayAdapter mDisplayAdapter;
@@ -266,10 +268,13 @@ abstract class DisplayDevice {
/**
* Sets the display layer stack while in a transaction.
*/
- public final void setLayerStackLocked(SurfaceControl.Transaction t, int layerStack) {
+ public final void setLayerStackLocked(SurfaceControl.Transaction t, int layerStack,
+ int layerStackTag) {
if (mCurrentLayerStack != layerStack) {
mCurrentLayerStack = layerStack;
t.setDisplayLayerStack(mDisplayToken, layerStack);
+ Slog.i(TAG, "[" + layerStackTag + "] Layerstack set to " + layerStack + " for "
+ + mUniqueId);
}
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index e6f27c1b0dd9..7dc412ed1cf8 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -494,7 +494,7 @@ final class LogicalDisplay {
DisplayDevice device,
boolean isBlanked) {
// Set the layer stack.
- device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack);
+ device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack, mDisplayId);
// Also inform whether the device is the same one sent to inputflinger for its layerstack.
// Prevent displays that are disabled from receiving input.
// TODO(b/188914255): Remove once input can dispatch against device vs layerstack.
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index f74356debd0f..ccab7bc9f31d 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -42,6 +42,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;
+import java.util.Objects;
/**
* Internal controller for starting and stopping the current dream and managing related state.
@@ -119,10 +120,19 @@ final class DreamController {
+ ", isPreviewMode=" + isPreviewMode + ", canDoze=" + canDoze
+ ", userId=" + userId + ", reason='" + reason + "'");
- if (mCurrentDream != null) {
- mPreviousDreams.add(mCurrentDream);
- }
+ final DreamRecord oldDream = mCurrentDream;
mCurrentDream = new DreamRecord(token, name, isPreviewMode, canDoze, userId, wakeLock);
+ if (oldDream != null) {
+ if (Objects.equals(oldDream.mName, mCurrentDream.mName)) {
+ // We are attempting to start a dream that is currently waking up gently.
+ // Let's silently stop the old instance here to clear the dream state.
+ // This should happen after the new mCurrentDream is set to avoid announcing
+ // a "dream stopped" state.
+ stopDreamInstance(/* immediately */ true, "restarting same dream", oldDream);
+ } else {
+ mPreviousDreams.add(oldDream);
+ }
+ }
mCurrentDream.mDreamStartTime = SystemClock.elapsedRealtime();
MetricsLogger.visible(mContext,
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 350aa6b2f686..2a807b2a3ef3 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -608,6 +608,9 @@ class MediaRouter2ServiceImpl {
/* package */ void updateRunningUserAndProfiles(int newActiveUserId) {
synchronized (mLock) {
if (mCurrentActiveUserId != newActiveUserId) {
+ Slog.i(TAG, TextUtils.formatSimple(
+ "switchUser | user: %d", newActiveUserId));
+
mCurrentActiveUserId = newActiveUserId;
for (int i = 0; i < mUserRecords.size(); i++) {
int userId = mUserRecords.keyAt(i);
@@ -679,6 +682,10 @@ class MediaRouter2ServiceImpl {
userRecord.mHandler.sendMessage(
obtainMessage(UserHandler::notifyRouterRegistered,
userRecord.mHandler, routerRecord));
+
+ Slog.i(TAG, TextUtils.formatSimple(
+ "registerRouter2 | package: %s, uid: %d, pid: %d, router: %d",
+ packageName, uid, pid, routerRecord.mRouterId));
}
@GuardedBy("mLock")
@@ -689,6 +696,11 @@ class MediaRouter2ServiceImpl {
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "unregisterRouter2 | package: %s, router: %d",
+ routerRecord.mPackageName,
+ routerRecord.mRouterId));
+
UserRecord userRecord = routerRecord.mUserRecord;
userRecord.mRouterRecords.remove(routerRecord);
routerRecord.mUserRecord.mHandler.sendMessage(
@@ -707,6 +719,11 @@ class MediaRouter2ServiceImpl {
if (routerRecord.mDiscoveryPreference.equals(discoveryRequest)) {
return;
}
+
+ Slog.i(TAG, TextUtils.formatSimple(
+ "setDiscoveryRequestWithRouter2 | router: %d, discovery request: %s",
+ routerRecord.mRouterId, discoveryRequest.toString()));
+
routerRecord.mDiscoveryPreference = discoveryRequest;
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::notifyDiscoveryPreferenceChangedToManagers,
@@ -724,6 +741,10 @@ class MediaRouter2ServiceImpl {
RouterRecord routerRecord = mAllRouterRecords.get(binder);
if (routerRecord != null) {
+ Slog.i(TAG, TextUtils.formatSimple(
+ "setRouteVolumeWithRouter2 | router: %d, volume: %d",
+ routerRecord.mRouterId, volume));
+
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::setRouteVolumeOnHandler,
routerRecord.mUserRecord.mHandler,
@@ -804,6 +825,10 @@ class MediaRouter2ServiceImpl {
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "selectRouteWithRouter2 | router: %d, route: %s",
+ routerRecord.mRouterId, route.getId()));
+
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::selectRouteOnHandler,
routerRecord.mUserRecord.mHandler,
@@ -819,6 +844,10 @@ class MediaRouter2ServiceImpl {
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "deselectRouteWithRouter2 | router: %d, route: %s",
+ routerRecord.mRouterId, route.getId()));
+
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::deselectRouteOnHandler,
routerRecord.mUserRecord.mHandler,
@@ -834,6 +863,10 @@ class MediaRouter2ServiceImpl {
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "transferToRouteWithRouter2 | router: %d, route: %s",
+ routerRecord.mRouterId, route.getId()));
+
String defaultRouteId =
routerRecord.mUserRecord.mHandler.mSystemProvider.getDefaultRoute().getId();
if (route.isSystemRoute() && !routerRecord.mHasModifyAudioRoutingPermission
@@ -859,6 +892,10 @@ class MediaRouter2ServiceImpl {
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "setSessionVolumeWithRouter2 | router: %d, session: %s, volume: %d",
+ routerRecord.mRouterId, uniqueSessionId, volume));
+
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::setSessionVolumeOnHandler,
routerRecord.mUserRecord.mHandler,
@@ -874,6 +911,10 @@ class MediaRouter2ServiceImpl {
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "releaseSessionWithRouter2 | router: %d, session: %s",
+ routerRecord.mRouterId, uniqueSessionId));
+
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::releaseSessionOnHandler,
routerRecord.mUserRecord.mHandler,
@@ -916,6 +957,10 @@ class MediaRouter2ServiceImpl {
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "registerManager | uid: %d, pid: %d, package: %s, user: %d",
+ uid, pid, packageName, userId));
+
mContext.enforcePermission(Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid,
"Must hold MEDIA_CONTENT_CONTROL permission.");
@@ -951,6 +996,13 @@ class MediaRouter2ServiceImpl {
return;
}
UserRecord userRecord = managerRecord.mUserRecord;
+
+ Slog.i(TAG, TextUtils.formatSimple(
+ "unregisterManager | package: %s, user: %d, manager: %d",
+ managerRecord.mPackageName,
+ userRecord.mUserId,
+ managerRecord.mManagerId));
+
userRecord.mManagerRecords.remove(managerRecord);
managerRecord.dispose();
disposeUserIfNeededLocked(userRecord); // since manager removed from user
@@ -962,6 +1014,10 @@ class MediaRouter2ServiceImpl {
if (managerRecord == null) {
return;
}
+
+ Slog.i(TAG, TextUtils.formatSimple(
+ "startScan | manager: %d", managerRecord.mManagerId));
+
managerRecord.startScan();
}
@@ -971,6 +1027,10 @@ class MediaRouter2ServiceImpl {
if (managerRecord == null) {
return;
}
+
+ Slog.i(TAG, TextUtils.formatSimple(
+ "stopScan | manager: %d", managerRecord.mManagerId));
+
managerRecord.stopScan();
}
@@ -984,6 +1044,10 @@ class MediaRouter2ServiceImpl {
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "setRouteVolumeWithManager | manager: %d, route: %s, volume: %d",
+ managerRecord.mManagerId, route.getId(), volume));
+
long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::setRouteVolumeOnHandler,
@@ -999,6 +1063,10 @@ class MediaRouter2ServiceImpl {
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "requestCreateSessionWithManager | manager: %d, route: %s",
+ managerRecord.mManagerId, route.getId()));
+
String packageName = oldSession.getClientPackageName();
RouterRecord routerRecord = managerRecord.mUserRecord.findRouterRecordLocked(packageName);
@@ -1044,6 +1112,10 @@ class MediaRouter2ServiceImpl {
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "selectRouteWithManager | manager: %d, session: %s, route: %s",
+ managerRecord.mManagerId, uniqueSessionId, route.getId()));
+
// Can be null if the session is system's or RCN.
RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
.findRouterWithSessionLocked(uniqueSessionId);
@@ -1065,6 +1137,10 @@ class MediaRouter2ServiceImpl {
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "deselectRouteWithManager | manager: %d, session: %s, route: %s",
+ managerRecord.mManagerId, uniqueSessionId, route.getId()));
+
// Can be null if the session is system's or RCN.
RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
.findRouterWithSessionLocked(uniqueSessionId);
@@ -1086,6 +1162,10 @@ class MediaRouter2ServiceImpl {
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "transferToRouteWithManager | manager: %d, session: %s, route: %s",
+ managerRecord.mManagerId, uniqueSessionId, route.getId()));
+
// Can be null if the session is system's or RCN.
RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
.findRouterWithSessionLocked(uniqueSessionId);
@@ -1107,6 +1187,10 @@ class MediaRouter2ServiceImpl {
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "setSessionVolumeWithManager | manager: %d, session: %s, volume: %d",
+ managerRecord.mManagerId, uniqueSessionId, volume));
+
long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::setSessionVolumeOnHandler,
@@ -1124,6 +1208,10 @@ class MediaRouter2ServiceImpl {
return;
}
+ Slog.i(TAG, TextUtils.formatSimple(
+ "releaseSessionWithManager | manager: %d, session: %s",
+ managerRecord.mManagerId, uniqueSessionId));
+
RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
.findRouterWithSessionLocked(uniqueSessionId);
@@ -1484,6 +1572,24 @@ class MediaRouter2ServiceImpl {
List<IMediaRouter2> routersWithModifyAudioRoutingPermission = getRouters(true);
List<IMediaRouter2> routersWithoutModifyAudioRoutingPermission = getRouters(false);
+
+ if (!addedRoutes.isEmpty()) {
+ // If routes were added, currentInfo cannot be null.
+ Slog.i(TAG,
+ toLoggingMessage(
+ /* source= */ "addProviderRoutes",
+ currentInfo.getUniqueId(),
+ (ArrayList) addedRoutes));
+ }
+ if (!removedRoutes.isEmpty()) {
+ // If routes were removed, prevInfo cannot be null.
+ Slog.i(TAG,
+ toLoggingMessage(
+ /* source= */ "removeProviderRoutes",
+ prevInfo.getUniqueId(),
+ (ArrayList) removedRoutes));
+ }
+
List<IMediaRouter2Manager> managers = getManagers();
List<MediaRoute2Info> defaultRoute = new ArrayList<>();
defaultRoute.add(mSystemProvider.getDefaultRoute());
@@ -1522,6 +1628,16 @@ class MediaRouter2ServiceImpl {
}
}
+ private static String toLoggingMessage(
+ String source, String providerId, ArrayList<MediaRoute2Info> routes) {
+ String routesString =
+ routes.stream()
+ .map(it -> String.format("%s | %s", it.getOriginalId(), it.getName()))
+ .collect(Collectors.joining(/* delimiter= */ ", "));
+ return TextUtils.formatSimple("%s | provider: %s, routes: [%s]",
+ source, providerId, routesString);
+ }
+
private int getLastProviderInfoIndex(@NonNull String providerId) {
for (int i = 0; i < mLastProviderInfos.size(); i++) {
MediaRoute2ProviderInfo providerInfo = mLastProviderInfos.get(i);
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index b75ba75e028b..c5a337d853a6 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -21,7 +21,9 @@ import static com.android.server.media.MediaSessionPolicyProvider.SESSION_POLICY
import android.media.Session2Token;
import android.media.session.MediaSession;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Log;
+import android.util.Slog;
import android.util.SparseArray;
import java.io.PrintWriter;
@@ -82,6 +84,10 @@ class MediaSessionStack {
* @param record The record to add.
*/
public void addSession(MediaSessionRecordImpl record) {
+ Slog.i(TAG, TextUtils.formatSimple(
+ "addSession to bottom of stack | record: %s",
+ record
+ ));
mSessions.add(record);
clearCache(record.getUserId());
@@ -97,6 +103,10 @@ class MediaSessionStack {
* @param record The record to remove.
*/
public void removeSession(MediaSessionRecordImpl record) {
+ Slog.i(TAG, TextUtils.formatSimple(
+ "removeSession | record: %s",
+ record
+ ));
mSessions.remove(record);
if (mMediaButtonSession == record) {
// When the media button session is removed, nullify the media button session and do not
@@ -142,6 +152,10 @@ class MediaSessionStack {
public void onPlaybackStateChanged(
MediaSessionRecordImpl record, boolean shouldUpdatePriority) {
if (shouldUpdatePriority) {
+ Slog.i(TAG, TextUtils.formatSimple(
+ "onPlaybackStateChanged - Pushing session to top | record: %s",
+ record
+ ));
mSessions.remove(record);
mSessions.add(0, record);
clearCache(record.getUserId());
diff --git a/services/core/java/com/android/server/media/projection/OWNERS b/services/core/java/com/android/server/media/projection/OWNERS
index 9ca391013aa3..832bcd9d70e6 100644
--- a/services/core/java/com/android/server/media/projection/OWNERS
+++ b/services/core/java/com/android/server/media/projection/OWNERS
@@ -1,2 +1 @@
-michaelwr@google.com
-santoscordon@google.com
+include /media/java/android/media/projection/OWNERS
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 632a34e4470d..921233132931 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -430,6 +430,7 @@ class ShortcutPackage extends ShortcutPackageItem {
@NonNull List<ShortcutInfo> changedShortcuts) {
Preconditions.checkArgument(newShortcut.isEnabled(),
"pushDynamicShortcuts() cannot publish disabled shortcuts");
+ ensureShortcutCountBeforePush();
newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
@@ -437,7 +438,7 @@ class ShortcutPackage extends ShortcutPackageItem {
final ShortcutInfo oldShortcut = findShortcutById(newShortcut.getId());
boolean deleted = false;
- if (oldShortcut == null) {
+ if (oldShortcut == null || !oldShortcut.isDynamic()) {
final ShortcutService service = mShortcutUser.mService;
final int maxShortcuts = service.getMaxActivityShortcuts();
@@ -446,18 +447,12 @@ class ShortcutPackage extends ShortcutPackageItem {
final ArrayList<ShortcutInfo> activityShortcuts = all.get(newShortcut.getActivity());
if (activityShortcuts != null && activityShortcuts.size() > maxShortcuts) {
- Slog.e(TAG, "Error pushing shortcut. There are already "
- + activityShortcuts.size() + " shortcuts, exceeding the " + maxShortcuts
- + " shortcuts limit when pushing the new shortcut " + newShortcut
- + ". Id of shortcuts currently available in system memory are "
- + activityShortcuts.stream().map(ShortcutInfo::getId)
- .collect(Collectors.joining(",", "[", "]")));
- // TODO: This should not have happened. If it does, identify the root cause where
- // possible, otherwise bail-out early to prevent memory issue.
+ // Root cause was discovered in b/233155034, so this should not be happening.
+ service.wtf("Error pushing shortcut. There are already "
+ + activityShortcuts.size() + " shortcuts.");
}
if (activityShortcuts != null && activityShortcuts.size() == maxShortcuts) {
// Max has reached. Delete the shortcut with lowest rank.
-
// Sort by isManifestShortcut() and getRank().
Collections.sort(activityShortcuts, mShortcutTypeAndRankComparator);
@@ -473,7 +468,8 @@ class ShortcutPackage extends ShortcutPackageItem {
deleted = deleteDynamicWithId(shortcut.getId(), /* ignoreInvisible =*/ true,
/*ignorePersistedShortcuts=*/ true) != null;
}
- } else {
+ }
+ if (oldShortcut != null) {
// It's an update case.
// Make sure the target is updatable. (i.e. should be mutable.)
oldShortcut.ensureUpdatableWith(newShortcut, /*isUpdating=*/ false);
@@ -505,6 +501,32 @@ class ShortcutPackage extends ShortcutPackageItem {
return deleted;
}
+ private void ensureShortcutCountBeforePush() {
+ final ShortcutService service = mShortcutUser.mService;
+ // Ensure the total number of shortcuts doesn't exceed the hard limit per app.
+ final int maxShortcutPerApp = service.getMaxAppShortcuts();
+ synchronized (mLock) {
+ final List<ShortcutInfo> appShortcuts = mShortcuts.values().stream().filter(si ->
+ !si.isPinned()).collect(Collectors.toList());
+ if (appShortcuts.size() >= maxShortcutPerApp) {
+ // Max has reached. Removes shortcuts until they fall within the hard cap.
+ // Sort by isManifestShortcut(), isDynamic() and getLastChangedTimestamp().
+ Collections.sort(appShortcuts, mShortcutTypeRankAndTimeComparator);
+
+ while (appShortcuts.size() >= maxShortcutPerApp) {
+ final ShortcutInfo shortcut = appShortcuts.remove(appShortcuts.size() - 1);
+ if (shortcut.isDeclaredInManifest()) {
+ // All shortcuts are manifest shortcuts and cannot be removed.
+ throw new IllegalArgumentException(getPackageName() + " has published "
+ + appShortcuts.size() + " manifest shortcuts across different"
+ + " activities.");
+ }
+ forceDeleteShortcutInner(shortcut.getId());
+ }
+ }
+ }
+ }
+
/**
* Remove all shortcuts that aren't pinned, cached nor dynamic.
*
@@ -1371,6 +1393,61 @@ class ShortcutPackage extends ShortcutPackageItem {
};
/**
+ * To sort by isManifestShortcut(), isDynamic(), getRank() and
+ * getLastChangedTimestamp(). i.e. manifest shortcuts come before non-manifest shortcuts,
+ * dynamic shortcuts come before floating shortcuts, then sort by last changed timestamp.
+ *
+ * This is used to decide which shortcuts to remove when the total number of shortcuts retained
+ * for the app exceeds the limit defined in {@link ShortcutService#getMaxAppShortcuts()}.
+ *
+ * (Note the number of manifest shortcuts is always <= the max number, because if there are
+ * more, ShortcutParser would ignore the rest.)
+ */
+ final Comparator<ShortcutInfo> mShortcutTypeRankAndTimeComparator = (ShortcutInfo a,
+ ShortcutInfo b) -> {
+ if (a.isDeclaredInManifest() && !b.isDeclaredInManifest()) {
+ return -1;
+ }
+ if (!a.isDeclaredInManifest() && b.isDeclaredInManifest()) {
+ return 1;
+ }
+ if (a.isDynamic() && b.isDynamic()) {
+ return Integer.compare(a.getRank(), b.getRank());
+ }
+ if (a.isDynamic()) {
+ return -1;
+ }
+ if (b.isDynamic()) {
+ return 1;
+ }
+ if (a.isCached() && b.isCached()) {
+ // if both shortcuts are cached, prioritize shortcuts cached by people tile,
+ if (a.hasFlags(ShortcutInfo.FLAG_CACHED_PEOPLE_TILE)
+ && !b.hasFlags(ShortcutInfo.FLAG_CACHED_PEOPLE_TILE)) {
+ return -1;
+ } else if (!a.hasFlags(ShortcutInfo.FLAG_CACHED_PEOPLE_TILE)
+ && b.hasFlags(ShortcutInfo.FLAG_CACHED_PEOPLE_TILE)) {
+ return 1;
+ }
+ // followed by bubbles.
+ if (a.hasFlags(ShortcutInfo.FLAG_CACHED_BUBBLES)
+ && !b.hasFlags(ShortcutInfo.FLAG_CACHED_BUBBLES)) {
+ return -1;
+ } else if (!a.hasFlags(ShortcutInfo.FLAG_CACHED_BUBBLES)
+ && b.hasFlags(ShortcutInfo.FLAG_CACHED_BUBBLES)) {
+ return 1;
+ }
+ }
+ if (a.isCached()) {
+ return -1;
+ }
+ if (b.isCached()) {
+ return 1;
+ }
+ return Long.compare(b.getLastChangedTimestamp(), a.getLastChangedTimestamp());
+ };
+
+ /**
* Build a list of shortcuts for each target activity and return as a map. The result won't
* contain "floating" shortcuts because they don't belong on any activities.
*/
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 49831d75db49..7fc46fd6f757 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -181,6 +181,9 @@ public class ShortcutService extends IShortcutService.Stub {
static final int DEFAULT_MAX_SHORTCUTS_PER_ACTIVITY = 15;
@VisibleForTesting
+ static final int DEFAULT_MAX_SHORTCUTS_PER_APP = 100;
+
+ @VisibleForTesting
static final int DEFAULT_MAX_ICON_DIMENSION_DP = 96;
@VisibleForTesting
@@ -257,6 +260,11 @@ public class ShortcutService extends IShortcutService.Stub {
String KEY_MAX_SHORTCUTS = "max_shortcuts";
/**
+ * Key name for the max shortcuts can be retained in system ram per app. (int)
+ */
+ String KEY_MAX_SHORTCUTS_PER_APP = "max_shortcuts_per_app";
+
+ /**
* Key name for icon compression quality, 0-100.
*/
String KEY_ICON_QUALITY = "icon_quality";
@@ -329,11 +337,16 @@ public class ShortcutService extends IShortcutService.Stub {
new SparseArray<>();
/**
- * Max number of dynamic + manifest shortcuts that each application can have at a time.
+ * Max number of dynamic + manifest shortcuts that each activity can have at a time.
*/
private int mMaxShortcuts;
/**
+ * Max number of shortcuts that can exists in system ram for each application.
+ */
+ private int mMaxShortcutsPerApp;
+
+ /**
* Max number of updating API calls that each application can make during the interval.
*/
int mMaxUpdatesPerInterval;
@@ -807,6 +820,9 @@ public class ShortcutService extends IShortcutService.Stub {
mMaxShortcuts = Math.max(0, (int) parser.getLong(
ConfigConstants.KEY_MAX_SHORTCUTS, DEFAULT_MAX_SHORTCUTS_PER_ACTIVITY));
+ mMaxShortcutsPerApp = Math.max(0, (int) parser.getLong(
+ ConfigConstants.KEY_MAX_SHORTCUTS_PER_APP, DEFAULT_MAX_SHORTCUTS_PER_APP));
+
final int iconDimensionDp = Math.max(1, injectIsLowRamDevice()
? (int) parser.getLong(
ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM,
@@ -1759,6 +1775,13 @@ public class ShortcutService extends IShortcutService.Stub {
}
/**
+ * Return the max number of shortcuts can be retaiend in system ram for each application.
+ */
+ int getMaxAppShortcuts() {
+ return mMaxShortcutsPerApp;
+ }
+
+ /**
* - Sends a notification to LauncherApps
* - Write to file
*/
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index ab7292d49c7d..6e342939c95a 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -152,6 +152,13 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
static final long REQUEST_LISTENING_MUST_MATCH_PACKAGE = 172251878L;
+ /**
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+ static final long REQUEST_LISTENING_OTHER_USER_NOOP = 242194868L;
+
private final Context mContext;
private final Handler mHandler = new Handler();
@@ -1859,7 +1866,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
// Check current user
if (userId != currentUser) {
- throw new IllegalArgumentException("User " + userId + " is not the current user.");
+ if (CompatChanges.isChangeEnabled(REQUEST_LISTENING_OTHER_USER_NOOP, callingUid)) {
+ return;
+ } else {
+ throw new IllegalArgumentException(
+ "User " + userId + " is not the current user.");
+ }
}
}
if (mBar != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 7489f80946eb..7c9244e39e67 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -696,6 +696,8 @@ class ActivityClientController extends IActivityClientController.Stub {
synchronized (mGlobalLock) {
final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
if (r != null) {
+ EventLogTags.writeWmSetRequestedOrientation(requestedOrientation,
+ r.shortComponentName);
r.setRequestedOrientation(requestedOrientation);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5f8e01e583c4..de5defa1bcd4 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1487,6 +1487,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mLastReportedMultiWindowMode = inPictureInPictureMode;
ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS,
true /* ignoreVisibility */);
+ if (inPictureInPictureMode && findMainWindow() == null) {
+ // Prevent malicious app entering PiP without valid WindowState, which can in turn
+ // result a non-touchable PiP window since the InputConsumer for PiP requires it.
+ EventLog.writeEvent(0x534e4554, "265293293", -1, "");
+ removeImmediately();
+ }
}
}
@@ -7973,11 +7979,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return false;
}
}
- // Activity should be resizable if the task is.
- final boolean isResizeable = task != null
- ? task.isResizeable() || isResizeable()
- : isResizeable();
- return !isResizeable && (info.isFixedOrientation() || hasFixedAspectRatio())
+ return !isResizeable() && (info.isFixedOrientation() || hasFixedAspectRatio())
// The configuration of non-standard type should be enforced by system.
// {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} is set when this activity is
// added to a task, but this function is called when resolving the launch params, at
@@ -8012,9 +8014,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// The smallest screen width is the short side of screen bounds. Because the bounds
// and density won't be changed, smallestScreenWidthDp is also fixed.
overrideConfig.smallestScreenWidthDp = fullConfig.smallestScreenWidthDp;
- // TODO(b/264276741): Check whether the runtime orietnation request is fixed rather than
- // the manifest orientation which may be obsolete.
- if (info.isFixedOrientation()) {
+ if (ActivityInfo.isFixedOrientation(getOverrideOrientation())) {
// lock rotation too. When in size-compat, onConfigurationChanged will watch for and
// apply runtime rotation changes.
overrideConfig.windowConfiguration.setRotation(
@@ -8039,7 +8039,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
// Clear config override in #updateCompatDisplayInsets().
- onRequestedOverrideConfigurationChanged(EMPTY);
+ final int activityType = getActivityType();
+ final Configuration overrideConfig = getRequestedOverrideConfiguration();
+ overrideConfig.unset();
+ // Keep the activity type which was set when attaching to a task to prevent leaving it
+ // undefined.
+ overrideConfig.windowConfiguration.setActivityType(activityType);
+ onRequestedOverrideConfigurationChanged(overrideConfig);
}
@Override
@@ -8099,9 +8105,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (isFixedOrientationLetterboxAllowed) {
resolveFixedOrientationConfiguration(newParentConfiguration);
}
-
- if (getCompatDisplayInsets() != null) {
- resolveSizeCompatModeConfiguration(newParentConfiguration);
+ final CompatDisplayInsets compatDisplayInsets = getCompatDisplayInsets();
+ if (compatDisplayInsets != null) {
+ resolveSizeCompatModeConfiguration(newParentConfiguration, compatDisplayInsets);
} else if (inMultiWindowMode() && !isFixedOrientationLetterboxAllowed) {
// We ignore activities' requested orientation in multi-window modes. They may be
// taken into consideration in resolveFixedOrientationConfiguration call above.
@@ -8118,7 +8124,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
resolveAspectRatioRestriction(newParentConfiguration);
}
- if (isFixedOrientationLetterboxAllowed || getCompatDisplayInsets() != null
+ if (isFixedOrientationLetterboxAllowed || compatDisplayInsets != null
// In fullscreen, can be letterboxed for aspect ratio.
|| !inMultiWindowMode()) {
updateResolvedBoundsPosition(newParentConfiguration);
@@ -8126,7 +8132,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean isIgnoreOrientationRequest = mDisplayContent != null
&& mDisplayContent.getIgnoreOrientationRequest();
- if (getCompatDisplayInsets() == null
+ if (compatDisplayInsets == null
// for size compat mode set in updateCompatDisplayInsets
// Fixed orientation letterboxing is possible on both large screen devices
// with ignoreOrientationRequest enabled and on phones in split screen even with
@@ -8173,7 +8179,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
info.neverSandboxDisplayApis(sConstrainDisplayApisConfig),
info.alwaysSandboxDisplayApis(sConstrainDisplayApisConfig),
!matchParentBounds(),
- getCompatDisplayInsets() != null,
+ compatDisplayInsets != null,
shouldCreateCompatDisplayInsets());
}
resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds);
@@ -8185,7 +8191,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/**
* @return The orientation to use to understand if reachability is enabled.
*/
- @ActivityInfo.ScreenOrientation
+ @Configuration.Orientation
int getOrientationForReachability() {
return mLetterboxUiController.hasInheritedLetterboxBehavior()
? mLetterboxUiController.getInheritedOrientation()
@@ -8581,7 +8587,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* Resolves consistent screen configuration for orientation and rotation changes without
* inheriting the parent bounds.
*/
- private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration) {
+ private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration,
+ @NonNull CompatDisplayInsets compatDisplayInsets) {
final Configuration resolvedConfig = getResolvedOverrideConfiguration();
final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
@@ -8602,13 +8609,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
? requestedOrientation
// We should use the original orientation of the activity when possible to avoid
// forcing the activity in the opposite orientation.
- : getCompatDisplayInsets().mOriginalRequestedOrientation != ORIENTATION_UNDEFINED
- ? getCompatDisplayInsets().mOriginalRequestedOrientation
+ : compatDisplayInsets.mOriginalRequestedOrientation != ORIENTATION_UNDEFINED
+ ? compatDisplayInsets.mOriginalRequestedOrientation
: newParentConfiguration.orientation;
int rotation = newParentConfiguration.windowConfiguration.getRotation();
final boolean isFixedToUserRotation = mDisplayContent == null
|| mDisplayContent.getDisplayRotation().isFixedToUserRotation();
- if (!isFixedToUserRotation && !getCompatDisplayInsets().mIsFloating) {
+ if (!isFixedToUserRotation && !compatDisplayInsets.mIsFloating) {
// Use parent rotation because the original display can be rotated.
resolvedConfig.windowConfiguration.setRotation(rotation);
} else {
@@ -8624,11 +8631,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// rely on them to contain the original and unchanging width and height of the app.
final Rect containingAppBounds = new Rect();
final Rect containingBounds = mTmpBounds;
- getCompatDisplayInsets().getContainerBounds(containingAppBounds, containingBounds, rotation,
+ compatDisplayInsets.getContainerBounds(containingAppBounds, containingBounds, rotation,
orientation, orientationRequested, isFixedToUserRotation);
resolvedBounds.set(containingBounds);
// The size of floating task is fixed (only swap), so the aspect ratio is already correct.
- if (!getCompatDisplayInsets().mIsFloating) {
+ if (!compatDisplayInsets.mIsFloating) {
mIsAspectRatioApplied =
applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds);
}
@@ -8637,7 +8644,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// are calculated in compat container space. The actual position on screen will be applied
// later, so the calculation is simpler that doesn't need to involve offset from parent.
getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
- getCompatDisplayInsets());
+ compatDisplayInsets);
// Use current screen layout as source because the size of app is independent to parent.
resolvedConfig.screenLayout = TaskFragment.computeScreenLayoutOverride(
getConfiguration().screenLayout, resolvedConfig.screenWidthDp,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index c527310abb14..491e58b63f76 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1486,7 +1486,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
a.persistableMode = ActivityInfo.PERSIST_NEVER;
a.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
a.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
- a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
+ a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS | ActivityInfo.FLAG_NO_HISTORY;
a.resizeMode = RESIZE_MODE_UNRESIZEABLE;
a.configChanges = 0xffffffff;
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index ec07d6f143a6..41130812d658 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1577,9 +1577,8 @@ public class DisplayPolicy {
applyKeyguardPolicy(win, imeTarget);
// Check if the freeform window overlaps with the navigation bar area.
- final boolean isOverlappingWithNavBar = isOverlappingWithNavBar(win);
- if (isOverlappingWithNavBar && !mIsFreeformWindowOverlappingWithNavBar
- && win.inFreeformWindowingMode()) {
+ if (!mIsFreeformWindowOverlappingWithNavBar && win.inFreeformWindowingMode()
+ && win.mActivityRecord != null && isOverlappingWithNavBar(win)) {
mIsFreeformWindowOverlappingWithNavBar = true;
}
@@ -1637,7 +1636,7 @@ public class DisplayPolicy {
// mode; if it's in gesture navigation mode, the navigation bar will be
// NAV_BAR_FORCE_TRANSPARENT and its appearance won't be decided by overlapping
// windows.
- if (isOverlappingWithNavBar) {
+ if (isOverlappingWithNavBar(win)) {
if (mNavBarColorWindowCandidate == null) {
mNavBarColorWindowCandidate = win;
addSystemBarColorApp(win);
@@ -1665,7 +1664,7 @@ public class DisplayPolicy {
addSystemBarColorApp(win);
}
}
- if (isOverlappingWithNavBar && mNavBarColorWindowCandidate == null) {
+ if (isOverlappingWithNavBar(win) && mNavBarColorWindowCandidate == null) {
mNavBarColorWindowCandidate = win;
}
}
@@ -2007,7 +2006,8 @@ public class DisplayPolicy {
dc.getDisplayPolicy().simulateLayoutDisplay(df);
final InsetsState insetsState = df.mInsetsState;
final Rect displayFrame = insetsState.getDisplayFrame();
- final Insets decor = calculateDecorInsetsWithInternalTypes(insetsState);
+ final Insets decor = insetsState.calculateInsets(displayFrame, DECOR_TYPES,
+ true /* ignoreVisibility */);
final Insets statusBar = insetsState.calculateInsets(displayFrame,
Type.statusBars(), true /* ignoreVisibility */);
mNonDecorInsets.set(decor.left, decor.top, decor.right, decor.bottom);
@@ -2039,17 +2039,8 @@ public class DisplayPolicy {
}
}
- // TODO (b/235842600): Use public type once we can treat task bar as navigation bar.
- static final int[] INTERNAL_DECOR_TYPES;
- static {
- final ArraySet<Integer> decorTypes = InsetsState.toInternalType(
- Type.displayCutout() | Type.navigationBars());
- decorTypes.remove(ITYPE_EXTRA_NAVIGATION_BAR);
- INTERNAL_DECOR_TYPES = new int[decorTypes.size()];
- for (int i = 0; i < INTERNAL_DECOR_TYPES.length; i++) {
- INTERNAL_DECOR_TYPES[i] = decorTypes.valueAt(i);
- }
- }
+
+ static final int DECOR_TYPES = Type.displayCutout() | Type.navigationBars();
private final DisplayContent mDisplayContent;
private final Info[] mInfoForRotation = new Info[4];
@@ -2076,20 +2067,6 @@ public class DisplayPolicy {
info.mNeedUpdate = true;
}
}
-
- // TODO (b/235842600): Remove this method once we can treat task bar as navigation bar.
- private static Insets calculateDecorInsetsWithInternalTypes(InsetsState state) {
- final Rect frame = state.getDisplayFrame();
- Insets insets = Insets.NONE;
- for (int i = INTERNAL_DECOR_TYPES.length - 1; i >= 0; i--) {
- final InsetsSource source = state.peekSource(INTERNAL_DECOR_TYPES[i]);
- if (source != null) {
- insets = Insets.max(source.calculateInsets(frame, true /* ignoreVisibility */),
- insets);
- }
- }
- return insets;
- }
}
/**
@@ -2880,7 +2857,7 @@ public class DisplayPolicy {
@VisibleForTesting
static boolean isOverlappingWithNavBar(@NonNull WindowState win) {
- if (win.mActivityRecord == null || !win.isVisible()) {
+ if (!win.isVisible()) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index 47bdba34ee24..41eb2c92923f 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -359,12 +359,6 @@ final class DisplayRotationCompatPolicy {
CAMERA_OPENED_ROTATION_UPDATE_DELAY_MS);
}
- private void updateOrientationWithWmLock() {
- synchronized (mWmService.mGlobalLock) {
- mDisplayContent.updateOrientation();
- }
- }
-
private void delayedUpdateOrientationWithWmLock(
@NonNull String cameraId, @NonNull String packageName) {
synchronized (this) {
@@ -375,25 +369,28 @@ final class DisplayRotationCompatPolicy {
}
mCameraIdPackageBiMap.put(packageName, cameraId);
}
- ActivityRecord topActivity = mDisplayContent.topRunningActivity(
- /* considerKeyguardState= */ true);
- if (topActivity == null || topActivity.getTask() == null) {
- return;
- }
- // Checking whether an activity in fullscreen rather than the task as this camera compat
- // treatment doesn't cover activity embedding.
- if (topActivity.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
- if (topActivity.mLetterboxUiController.isOverrideOrientationOnlyForCameraEnabled()) {
- topActivity.recomputeConfiguration();
+ synchronized (mWmService.mGlobalLock) {
+ ActivityRecord topActivity = mDisplayContent.topRunningActivity(
+ /* considerKeyguardState= */ true);
+ if (topActivity == null || topActivity.getTask() == null) {
+ return;
+ }
+ // Checking whether an activity in fullscreen rather than the task as this camera
+ // compat treatment doesn't cover activity embedding.
+ if (topActivity.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
+ if (topActivity.mLetterboxUiController
+ .isOverrideOrientationOnlyForCameraEnabled()) {
+ topActivity.recomputeConfiguration();
+ }
+ mDisplayContent.updateOrientation();
+ return;
+ }
+ // Checking that the whole app is in multi-window mode as we shouldn't show toast
+ // for the activity embedding case.
+ if (topActivity.getTask().getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW
+ && isTreatmentEnabledForActivity(topActivity, /* mustBeFullscreen */ false)) {
+ showToast(R.string.display_rotation_camera_compat_toast_in_split_screen);
}
- updateOrientationWithWmLock();
- return;
- }
- // Checking that the whole app is in multi-window mode as we shouldn't show toast
- // for the activity embedding case.
- if (topActivity.getTask().getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW
- && isTreatmentEnabledForActivity(topActivity, /* mustBeFullscreen */ false)) {
- showToast(R.string.display_rotation_camera_compat_toast_in_split_screen);
}
}
@@ -441,18 +438,20 @@ final class DisplayRotationCompatPolicy {
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Display id=%d is notified that Camera %s is closed, updating rotation.",
mDisplayContent.mDisplayId, cameraId);
- ActivityRecord topActivity = mDisplayContent.topRunningActivity(
- /* considerKeyguardState= */ true);
- if (topActivity == null
- // Checking whether an activity in fullscreen rather than the task as this camera
- // compat treatment doesn't cover activity embedding.
- || topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
- return;
- }
- if (topActivity.mLetterboxUiController.isOverrideOrientationOnlyForCameraEnabled()) {
- topActivity.recomputeConfiguration();
+ synchronized (mWmService.mGlobalLock) {
+ ActivityRecord topActivity = mDisplayContent.topRunningActivity(
+ /* considerKeyguardState= */ true);
+ if (topActivity == null
+ // Checking whether an activity in fullscreen rather than the task as this
+ // camera compat treatment doesn't cover activity embedding.
+ || topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
+ return;
+ }
+ if (topActivity.mLetterboxUiController.isOverrideOrientationOnlyForCameraEnabled()) {
+ topActivity.recomputeConfiguration();
+ }
+ mDisplayContent.updateOrientation();
}
- updateOrientationWithWmLock();
}
private boolean isActivityForCameraIdRefreshing(String cameraId) {
diff --git a/services/core/java/com/android/server/wm/EventLogTags.logtags b/services/core/java/com/android/server/wm/EventLogTags.logtags
index 1e5a219e5e52..48ce22e227dd 100644
--- a/services/core/java/com/android/server/wm/EventLogTags.logtags
+++ b/services/core/java/com/android/server/wm/EventLogTags.logtags
@@ -1,4 +1,4 @@
-# See system/core/logcat/event.logtags for a description of the format of this file.
+# See system/logging/logcat/event.logtags for a description of the format of this file.
option java_package com.android.server.wm
@@ -62,6 +62,10 @@ option java_package com.android.server.wm
31002 wm_task_moved (TaskId|1|5),(ToTop|1),(Index|1)
# Task removed with source explanation.
31003 wm_task_removed (TaskId|1|5),(Reason|3)
+
+# Set the requested orientation of an activity.
+31006 wm_set_requested_orientation (Orientation|1|5),(Component Name|3)
+
# bootanim finished:
31007 wm_boot_animation_done (time|2|3)
diff --git a/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java b/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java
index 4a99db594755..3b10debaa753 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java
@@ -216,6 +216,10 @@ class LetterboxConfigurationPersister {
}
private void readCurrentConfiguration() {
+ if (!mConfigurationFile.exists()) {
+ useDefaultValue();
+ return;
+ }
FileInputStream fis = null;
try {
fis = mConfigurationFile.openRead();
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index e1dbe01aca61..d9f2b6e4a0a3 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -870,10 +870,9 @@ final class LetterboxUiController {
return mActivityRecord.mWmService.mContext.getResources();
}
- private void handleHorizontalDoubleTap(int x) {
- // TODO(b/260857308): Investigate if enabling reachability for translucent activity
- if (hasInheritedLetterboxBehavior() || !isHorizontalReachabilityEnabled()
- || mActivityRecord.isInTransition()) {
+ @VisibleForTesting
+ void handleHorizontalDoubleTap(int x) {
+ if (!isHorizontalReachabilityEnabled() || mActivityRecord.isInTransition()) {
return;
}
@@ -911,10 +910,9 @@ final class LetterboxUiController {
mActivityRecord.recomputeConfiguration();
}
- private void handleVerticalDoubleTap(int y) {
- // TODO(b/260857308): Investigate if enabling reachability for translucent activity
- if (hasInheritedLetterboxBehavior() || !isVerticalReachabilityEnabled()
- || mActivityRecord.isInTransition()) {
+ @VisibleForTesting
+ void handleVerticalDoubleTap(int y) {
+ if (!isVerticalReachabilityEnabled() || mActivityRecord.isInTransition()) {
return;
}
@@ -1435,7 +1433,7 @@ final class LetterboxUiController {
* the first opaque activity beneath.
*/
boolean hasInheritedLetterboxBehavior() {
- return mLetterboxConfigListener != null && !mActivityRecord.matchParentBounds();
+ return mLetterboxConfigListener != null;
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 79be9463aa05..2086b522aa66 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1222,7 +1222,7 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
// Clear last paused activity if focused root task changed while sleeping, so that the
// top activity of current focused task can be resumed.
- if (mDisplayContent.isSleeping()) {
+ if (mDisplayContent.isSleeping() && currentFocusedTask != null) {
currentFocusedTask.clearLastPausedActivity();
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index ce032442e4af..9e0e8c477573 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1436,7 +1436,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* {@link Configuration#ORIENTATION_PORTRAIT},
* {@link Configuration#ORIENTATION_UNDEFINED}).
*/
- @ScreenOrientation
+ @Configuration.Orientation
int getRequestedConfigurationOrientation() {
return getRequestedConfigurationOrientation(false /* forDisplay */);
}
@@ -1454,7 +1454,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* {@link Configuration#ORIENTATION_PORTRAIT},
* {@link Configuration#ORIENTATION_UNDEFINED}).
*/
- @ScreenOrientation
+ @Configuration.Orientation
int getRequestedConfigurationOrientation(boolean forDisplay) {
int requestedOrientation = getOverrideOrientation();
final RootDisplayArea root = getRootDisplayArea();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8931d8030df2..e6c1e75da581 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6198,9 +6198,10 @@ public class WindowManagerService extends IWindowManager.Stub
waitingForConfig = waitingForRemoteDisplayChange = false;
numOpeningApps = 0;
}
- if (waitingForConfig || waitingForRemoteDisplayChange || mAppsFreezingScreen > 0
- || mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE
- || mClientFreezingScreen || numOpeningApps > 0) {
+ final boolean waitingForApps = mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT
+ && (mAppsFreezingScreen > 0 || numOpeningApps > 0);
+ if (waitingForConfig || waitingForRemoteDisplayChange || waitingForApps
+ || mClientFreezingScreen) {
ProtoLog.d(WM_DEBUG_ORIENTATION, "stopFreezingDisplayLocked: Returning "
+ "waitingForConfig=%b, waitingForRemoteDisplayChange=%b, "
+ "mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, "
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/OWNERS b/services/tests/servicestests/src/com/android/server/media/projection/OWNERS
new file mode 100644
index 000000000000..832bcd9d70e6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/media/projection/OWNERS
@@ -0,0 +1 @@
+include /media/java/android/media/projection/OWNERS
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index 949455a18570..b2754d237f42 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -32,22 +32,24 @@ import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.EventInfo;
import android.service.notification.ZenPolicy;
-import android.test.suitebuilder.annotation.SmallTest;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
+import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.UiServiceTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParserException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -189,8 +191,6 @@ public class ZenModeConfigTest extends UiServiceTestCase {
@Test
public void testRuleXml() throws Exception {
- String tag = "tag";
-
ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
rule.configurationActivity = new ComponentName("a", "a");
rule.component = new ComponentName("b", "b");
@@ -205,20 +205,11 @@ public class ZenModeConfigTest extends UiServiceTestCase {
rule.snoozing = true;
rule.pkg = "b";
- TypedXmlSerializer out = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- out.setOutput(new BufferedOutputStream(baos), "utf-8");
- out.startDocument(null, true);
- out.startTag(null, tag);
- ZenModeConfig.writeRuleXml(rule, out);
- out.endTag(null, tag);
- out.endDocument();
+ writeRuleXml(rule, baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ ZenModeConfig.ZenRule fromXml = readRuleXml(bais);
- TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(new BufferedInputStream(
- new ByteArrayInputStream(baos.toByteArray())), null);
- parser.nextTag();
- ZenModeConfig.ZenRule fromXml = ZenModeConfig.readRuleXml(parser);
assertEquals("b", fromXml.pkg);
// always resets on reboot
assertFalse(fromXml.snoozing);
@@ -237,75 +228,41 @@ public class ZenModeConfigTest extends UiServiceTestCase {
@Test
public void testRuleXml_pkg_component() throws Exception {
- String tag = "tag";
-
ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
rule.configurationActivity = new ComponentName("a", "a");
rule.component = new ComponentName("b", "b");
- TypedXmlSerializer out = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- out.setOutput(new BufferedOutputStream(baos), "utf-8");
- out.startDocument(null, true);
- out.startTag(null, tag);
- ZenModeConfig.writeRuleXml(rule, out);
- out.endTag(null, tag);
- out.endDocument();
+ writeRuleXml(rule, baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ ZenModeConfig.ZenRule fromXml = readRuleXml(bais);
- TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(new BufferedInputStream(
- new ByteArrayInputStream(baos.toByteArray())), null);
- parser.nextTag();
- ZenModeConfig.ZenRule fromXml = ZenModeConfig.readRuleXml(parser);
assertEquals("b", fromXml.pkg);
}
@Test
public void testRuleXml_pkg_configActivity() throws Exception {
- String tag = "tag";
-
ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
rule.configurationActivity = new ComponentName("a", "a");
- TypedXmlSerializer out = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- out.setOutput(new BufferedOutputStream(baos), "utf-8");
- out.startDocument(null, true);
- out.startTag(null, tag);
- ZenModeConfig.writeRuleXml(rule, out);
- out.endTag(null, tag);
- out.endDocument();
+ writeRuleXml(rule, baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ ZenModeConfig.ZenRule fromXml = readRuleXml(bais);
- TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(new BufferedInputStream(
- new ByteArrayInputStream(baos.toByteArray())), null);
- parser.nextTag();
- ZenModeConfig.ZenRule fromXml = ZenModeConfig.readRuleXml(parser);
assertNull(fromXml.pkg);
}
@Test
public void testRuleXml_getPkg_nullPkg() throws Exception {
- String tag = "tag";
-
ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
rule.enabled = true;
rule.configurationActivity = new ComponentName("a", "a");
- TypedXmlSerializer out = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- out.setOutput(new BufferedOutputStream(baos), "utf-8");
- out.startDocument(null, true);
- out.startTag(null, tag);
- ZenModeConfig.writeRuleXml(rule, out);
- out.endTag(null, tag);
- out.endDocument();
-
- TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(new BufferedInputStream(
- new ByteArrayInputStream(baos.toByteArray())), null);
- parser.nextTag();
- ZenModeConfig.ZenRule fromXml = ZenModeConfig.readRuleXml(parser);
+ writeRuleXml(rule, baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ ZenModeConfig.ZenRule fromXml = readRuleXml(bais);
assertEquals("a", fromXml.getPkg());
fromXml.condition = new Condition(Uri.EMPTY, "", Condition.STATE_TRUE);
@@ -313,25 +270,26 @@ public class ZenModeConfigTest extends UiServiceTestCase {
}
@Test
- public void testZenPolicyXml_allUnset() throws Exception {
- String tag = "tag";
+ public void testRuleXml_emptyConditionId() throws Exception {
+ ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
+ rule.conditionId = Uri.EMPTY;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ writeRuleXml(rule, baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ ZenModeConfig.ZenRule fromXml = readRuleXml(bais);
+
+ assertEquals(rule.condition, fromXml.condition);
+ }
+
+ @Test
+ public void testZenPolicyXml_allUnset() throws Exception {
ZenPolicy policy = new ZenPolicy.Builder().build();
- TypedXmlSerializer out = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- out.setOutput(new BufferedOutputStream(baos), "utf-8");
- out.startDocument(null, true);
- out.startTag(null, tag);
- ZenModeConfig.writeZenPolicyXml(policy, out);
- out.endTag(null, tag);
- out.endDocument();
-
- TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(new BufferedInputStream(
- new ByteArrayInputStream(baos.toByteArray())), null);
- parser.nextTag();
- ZenPolicy fromXml = ZenModeConfig.readZenPolicyXml(parser);
+ writePolicyXml(policy, baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ ZenPolicy fromXml = readPolicyXml(bais);
// nothing was set, so we should have nothing from the parser
assertNull(fromXml);
@@ -339,8 +297,6 @@ public class ZenModeConfigTest extends UiServiceTestCase {
@Test
public void testZenPolicyXml() throws Exception {
- String tag = "tag";
-
ZenPolicy policy = new ZenPolicy.Builder()
.allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS)
.allowMessages(ZenPolicy.PEOPLE_TYPE_NONE)
@@ -355,20 +311,10 @@ public class ZenModeConfigTest extends UiServiceTestCase {
.showVisualEffect(ZenPolicy.VISUAL_EFFECT_AMBIENT, true)
.build();
- TypedXmlSerializer out = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- out.setOutput(new BufferedOutputStream(baos), "utf-8");
- out.startDocument(null, true);
- out.startTag(null, tag);
- ZenModeConfig.writeZenPolicyXml(policy, out);
- out.endTag(null, tag);
- out.endDocument();
-
- TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(new BufferedInputStream(
- new ByteArrayInputStream(baos.toByteArray())), null);
- parser.nextTag();
- ZenPolicy fromXml = ZenModeConfig.readZenPolicyXml(parser);
+ writePolicyXml(policy, baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ ZenPolicy fromXml = readPolicyXml(bais);
assertNotNull(fromXml);
assertEquals(policy.getPriorityCategoryCalls(), fromXml.getPriorityCategoryCalls());
@@ -457,4 +403,45 @@ public class ZenModeConfigTest extends UiServiceTestCase {
config.suppressedVisualEffects = 0;
return config;
}
+
+ private void writeRuleXml(ZenModeConfig.ZenRule rule, ByteArrayOutputStream os)
+ throws IOException {
+ String tag = "tag";
+
+ TypedXmlSerializer out = Xml.newFastSerializer();
+ out.setOutput(new BufferedOutputStream(os), "utf-8");
+ out.startDocument(null, true);
+ out.startTag(null, tag);
+ ZenModeConfig.writeRuleXml(rule, out);
+ out.endTag(null, tag);
+ out.endDocument();
+ }
+
+ private ZenModeConfig.ZenRule readRuleXml(ByteArrayInputStream is)
+ throws XmlPullParserException, IOException {
+ TypedXmlPullParser parser = Xml.newFastPullParser();
+ parser.setInput(new BufferedInputStream(is), null);
+ parser.nextTag();
+ return ZenModeConfig.readRuleXml(parser);
+ }
+
+ private void writePolicyXml(ZenPolicy policy, ByteArrayOutputStream os) throws IOException {
+ String tag = "tag";
+
+ TypedXmlSerializer out = Xml.newFastSerializer();
+ out.setOutput(new BufferedOutputStream(os), "utf-8");
+ out.startDocument(null, true);
+ out.startTag(null, tag);
+ ZenModeConfig.writeZenPolicyXml(policy, out);
+ out.endTag(null, tag);
+ out.endDocument();
+ }
+
+ private ZenPolicy readPolicyXml(ByteArrayInputStream is)
+ throws XmlPullParserException, IOException {
+ TypedXmlPullParser parser = Xml.newFastPullParser();
+ parser.setInput(new BufferedInputStream(is), null);
+ parser.nextTag();
+ return ZenModeConfig.readZenPolicyXml(parser);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 318fff275f1f..117805bf344d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -113,6 +113,8 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
/**
* Tests for Size Compatibility mode.
@@ -168,6 +170,156 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
+ public void testHorizontalReachabilityEnabledForTranslucentActivities() {
+ setUpDisplaySizeWithApp(2500, 1000);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ final LetterboxConfiguration config = mWm.mLetterboxConfiguration;
+ config.setTranslucentLetterboxingOverrideEnabled(true);
+ config.setLetterboxHorizontalPositionMultiplier(0.5f);
+ config.setIsHorizontalReachabilityEnabled(true);
+
+ // Opaque activity
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+ addWindowToActivity(mActivity);
+ mActivity.mRootWindowContainer.performSurfacePlacement();
+
+ // Translucent Activity
+ final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
+ .setLaunchedFromUid(mActivity.getUid())
+ .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
+ .build();
+ doReturn(false).when(translucentActivity).fillsParent();
+ mTask.addChild(translucentActivity);
+
+ spyOn(translucentActivity.mLetterboxUiController);
+ doReturn(true).when(translucentActivity.mLetterboxUiController)
+ .shouldShowLetterboxUi(any());
+
+ addWindowToActivity(translucentActivity);
+ translucentActivity.mRootWindowContainer.performSurfacePlacement();
+
+ final Function<ActivityRecord, Rect> innerBoundsOf =
+ (ActivityRecord a) -> {
+ final Rect bounds = new Rect();
+ a.mLetterboxUiController.getLetterboxInnerBounds(bounds);
+ return bounds;
+ };
+ final Runnable checkLetterboxPositions = () -> assertEquals(innerBoundsOf.apply(mActivity),
+ innerBoundsOf.apply(translucentActivity));
+ final Runnable checkIsLeft = () -> assertThat(
+ innerBoundsOf.apply(translucentActivity).left).isEqualTo(0);
+ final Runnable checkIsRight = () -> assertThat(
+ innerBoundsOf.apply(translucentActivity).right).isEqualTo(2500);
+ final Runnable checkIsCentered = () -> assertThat(
+ innerBoundsOf.apply(translucentActivity).left > 0
+ && innerBoundsOf.apply(translucentActivity).right < 2500).isTrue();
+
+ final Consumer<Integer> doubleClick =
+ (Integer x) -> {
+ mActivity.mLetterboxUiController.handleHorizontalDoubleTap(x);
+ mActivity.mRootWindowContainer.performSurfacePlacement();
+ };
+
+ // Initial state
+ checkIsCentered.run();
+
+ // Double-click left
+ doubleClick.accept(/* x */ 10);
+ checkLetterboxPositions.run();
+ checkIsLeft.run();
+
+ // Double-click right
+ doubleClick.accept(/* x */ 1990);
+ checkLetterboxPositions.run();
+ checkIsCentered.run();
+
+ // Double-click right
+ doubleClick.accept(/* x */ 1990);
+ checkLetterboxPositions.run();
+ checkIsRight.run();
+
+ // Double-click left
+ doubleClick.accept(/* x */ 10);
+ checkLetterboxPositions.run();
+ checkIsCentered.run();
+ }
+
+ @Test
+ public void testVerticalReachabilityEnabledForTranslucentActivities() {
+ setUpDisplaySizeWithApp(1000, 2500);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ final LetterboxConfiguration config = mWm.mLetterboxConfiguration;
+ config.setTranslucentLetterboxingOverrideEnabled(true);
+ config.setLetterboxVerticalPositionMultiplier(0.5f);
+ config.setIsVerticalReachabilityEnabled(true);
+
+ // Opaque activity
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+ addWindowToActivity(mActivity);
+ mActivity.mRootWindowContainer.performSurfacePlacement();
+
+ // Translucent Activity
+ final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
+ .setLaunchedFromUid(mActivity.getUid())
+ .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE)
+ .build();
+ doReturn(false).when(translucentActivity).fillsParent();
+ mTask.addChild(translucentActivity);
+
+ spyOn(translucentActivity.mLetterboxUiController);
+ doReturn(true).when(translucentActivity.mLetterboxUiController)
+ .shouldShowLetterboxUi(any());
+
+ addWindowToActivity(translucentActivity);
+ translucentActivity.mRootWindowContainer.performSurfacePlacement();
+
+ final Function<ActivityRecord, Rect> innerBoundsOf =
+ (ActivityRecord a) -> {
+ final Rect bounds = new Rect();
+ a.mLetterboxUiController.getLetterboxInnerBounds(bounds);
+ return bounds;
+ };
+ final Runnable checkLetterboxPositions = () -> assertEquals(innerBoundsOf.apply(mActivity),
+ innerBoundsOf.apply(translucentActivity));
+ final Runnable checkIsTop = () -> assertThat(
+ innerBoundsOf.apply(translucentActivity).top).isEqualTo(0);
+ final Runnable checkIsBottom = () -> assertThat(
+ innerBoundsOf.apply(translucentActivity).bottom).isEqualTo(2500);
+ final Runnable checkIsCentered = () -> assertThat(
+ innerBoundsOf.apply(translucentActivity).top > 0
+ && innerBoundsOf.apply(translucentActivity).bottom < 2500).isTrue();
+
+ final Consumer<Integer> doubleClick =
+ (Integer y) -> {
+ mActivity.mLetterboxUiController.handleVerticalDoubleTap(y);
+ mActivity.mRootWindowContainer.performSurfacePlacement();
+ };
+
+ // Initial state
+ checkIsCentered.run();
+
+ // Double-click top
+ doubleClick.accept(/* y */ 10);
+ checkLetterboxPositions.run();
+ checkIsTop.run();
+
+ // Double-click bottom
+ doubleClick.accept(/* y */ 1990);
+ checkLetterboxPositions.run();
+ checkIsCentered.run();
+
+ // Double-click bottom
+ doubleClick.accept(/* y */ 1990);
+ checkLetterboxPositions.run();
+ checkIsBottom.run();
+
+ // Double-click top
+ doubleClick.accept(/* y */ 10);
+ checkLetterboxPositions.run();
+ checkIsCentered.run();
+ }
+
+ @Test
public void testApplyStrategyToTranslucentActivities() {
mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
setUpDisplaySizeWithApp(2000, 1000);
@@ -809,7 +961,7 @@ public class SizeCompatTests extends WindowTestsBase {
.setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
.setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
.build();
- assertFalse(activity.shouldCreateCompatDisplayInsets());
+ assertTrue(activity.shouldCreateCompatDisplayInsets());
// The non-resizable activity should not be size compat because it is on a resizable task
// in multi-window mode.
@@ -842,7 +994,7 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
- public void testShouldNotCreateCompatDisplayInsetsWhenRootActivityIsResizeable() {
+ public void testShouldCreateCompatDisplayInsetsWhenUnresizeableAndSupportsSizeChangesFalse() {
setUpDisplaySizeWithApp(1000, 2500);
// Make the task root resizable.
@@ -851,7 +1003,7 @@ public class SizeCompatTests extends WindowTestsBase {
// Create an activity on the same task.
final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false,
RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- assertFalse(activity.shouldCreateCompatDisplayInsets());
+ assertTrue(activity.shouldCreateCompatDisplayInsets());
}
@Test
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index ec18c6a696b8..7a53447c1eee 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -555,6 +555,11 @@ public final class PhoneAccount implements Parcelable {
/**
* Sets the address. See {@link PhoneAccount#getAddress}.
+ * <p>
+ * Note: The entire URI value is limited to 256 characters. This check is
+ * enforced when registering the PhoneAccount via
+ * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} and will cause an
+ * {@link IllegalArgumentException} to be thrown if URI is over 256.
*
* @param value The address of the phone account.
* @return The builder.
@@ -588,6 +593,10 @@ public final class PhoneAccount implements Parcelable {
/**
* Sets the icon. See {@link PhoneAccount#getIcon}.
+ * <p>
+ * Note: An {@link IllegalArgumentException} if the Icon cannot be written to memory.
+ * This check is enforced when registering the PhoneAccount via
+ * {@link TelecomManager#registerPhoneAccount(PhoneAccount)}
*
* @param icon The icon to set.
*/
@@ -621,6 +630,10 @@ public final class PhoneAccount implements Parcelable {
/**
* Specifies an additional URI scheme supported by the {@link PhoneAccount}.
*
+ * <p>
+ * Each URI scheme is limited to 256 characters. Adding a scheme over 256 characters will
+ * cause an {@link IllegalArgumentException} to be thrown when the account is registered.
+ *
* @param uriScheme The URI scheme.
* @return The builder.
*/
@@ -634,6 +647,12 @@ public final class PhoneAccount implements Parcelable {
/**
* Specifies the URI schemes supported by the {@link PhoneAccount}.
*
+ * <p>
+ * A max of 10 URI schemes can be added per account. Additionally, each URI scheme is
+ * limited to 256 characters. Adding more than 10 URI schemes or 256 characters on any
+ * scheme will cause an {@link IllegalArgumentException} to be thrown when the account
+ * is registered.
+ *
* @param uriSchemes The URI schemes.
* @return The builder.
*/
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
index a8cbc5dc922c..e05312fe8cc5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
@@ -18,12 +18,15 @@ package com.android.server.wm.flicker.launch
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.RequiresDevice
+import android.platform.test.rule.SettingOverrideRule
+import android.provider.Settings
import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.ClassRule
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -98,5 +101,16 @@ open class OpenAppFromLockNotificationCold(testSpec: FlickerTestParameter)
return com.android.server.wm.flicker.FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(repetitions = 3)
}
+
+ /**
+ * Ensures that posted notifications will be visible on the lockscreen and not
+ * suppressed due to being marked as seen.
+ */
+ @ClassRule
+ @JvmField
+ val disableUnseenNotifFilterRule = SettingOverrideRule(
+ Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS,
+ /* value= */ "0",
+ )
}
-} \ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
index cd8dea012db5..fcec79f4d7f5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
@@ -18,6 +18,8 @@ package com.android.server.wm.flicker.launch
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.RequiresDevice
+import android.platform.test.rule.SettingOverrideRule
+import android.provider.Settings
import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -25,6 +27,7 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.traces.common.FlickerComponentName
+import org.junit.ClassRule
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -124,5 +127,16 @@ open class OpenAppFromLockNotificationWarm(testSpec: FlickerTestParameter)
return com.android.server.wm.flicker.FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(repetitions = 3)
}
+
+ /**
+ * Ensures that posted notifications will be visible on the lockscreen and not
+ * suppressed due to being marked as seen.
+ */
+ @ClassRule
+ @JvmField
+ val disableUnseenNotifFilterRule = SettingOverrideRule(
+ Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS,
+ /* value= */ "0",
+ )
}
-} \ No newline at end of file
+}
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
index 3db011683a86..fdd919412e55 100644
--- a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
+++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
@@ -86,7 +86,7 @@ public class ProtoLogImplTest {
mFile = testContext.getFileStreamPath("tracing_test.dat");
//noinspection ResultOfMethodCallIgnored
mFile.delete();
- mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader);
+ mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader, 1024);
}
@After
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index 34e8edb0a47f..8ea43abff895 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -27,7 +27,7 @@ namespace aapt {
static ApiVersion sDevelopmentSdkLevel = 10000;
static const auto sDevelopmentSdkCodeNames =
- std::unordered_set<StringPiece>({"Q", "R", "S", "Sv2", "Tiramisu", "UpsideDownCake"});
+ std::unordered_set<StringPiece>({"Q", "R", "S", "Sv2", "Tiramisu"});
static const std::vector<std::pair<uint16_t, ApiVersion>> sAttrIdMap = {
{0x021c, 1},